d3.js实现简单的⽹络拓扑图实例代码
前⾔
了解了D3.js的基本开发和组件以后,我们开始应⽤它激动⼈⼼之处:绚丽的预定义图形,应⽤D3.js,我们在它的⽰例⽂件的基础上稍加变动即可应⽤于我们的数据可视化⼯作中,D3.js将后台的运算已经预定义好,我们只需少量代码和规范的数据,就能做出很花哨(请原谅我的⽤词不当)的效果。
⼒学图(也称为导向图,也有叫⽹络拓补图的,反正就是通过排斥得到关系远近的结构)在社交⽹络研究、信息传播途径等体关系研究中应⽤⾮常⼴泛,它可以直观地反映体与体之间联系的渠道、交集多少,体内部成员的联系强度等。
本⽂实现如下⾯的效果(⽤⾮IE浏览器可以看到效果):
代码有点长,但是也不复杂,可以参考如下代码:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="mbostock.github/d3/d3.v2.js?2.9.1"></script>
<style type="text/css">
.link { stroke: green; stroke-linejoin:bevel;}
.link_error{
stroke:red;
stroke-linejoin:bevel;
}
.nodetext {
font: 12px sans-serif;
-webkit-user-select:none;
-moze-user-select:none;
stroke-linejoin:bevel;
}
#container{
width:800px;
height:600px;
border:1px solid gray;
border-radius:5px;
position:relative;
margin:20px;
}
</style>
</head>
<body>
<div id='container'></div>
<script type="text/javascript">
function Topology(ele){
typeof(ele)=='string' && (ElementById(ele));
var w=ele.clientWidth,
h=ele.clientHeight,
self=this;
this.force = d3.layout.force().gravity(.05).distance(200).charge(-800).size([w, h]);
this.links=this.force.links();
this.clickFn=function(){};
this.vis = d3.select(ele).append("svg:svg")
.attr("width", w).attr("height", h).attr("pointer-events", "all");
("tick", function(x) {
self.vis.selectAll("g.node")
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
self.vis.selectAll("line.link")
.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.
attr("y2", function(d) { return d.target.y; });
});
}
Topology.prototype.doZoom=function(){
d3.select(this).select('g').attr("transform","translate(" + anslate + ")"+ " scale(" + d3.event.scale + ")"); }
//增加节点
Topology.prototype.addNode=function(node){
}
Topology.prototype.addNodes=function(nodes){
if (String.call(nodes)=='[object Array]' ){
var self=this;
nodes.forEach(function(node){
self.addNode(node);
});
}
}
//增加连线
Topology.prototype.addLink=function(source,target){
this.links.push({source:this.findNode(source),target:this.findNode(target)});
}
//增加多个连线
Topology.prototype.addLinks=function(links){
if (String.call(links)=='[object Array]' ){
var self=this;
links.forEach(function(link){
self.addLink(link['source'],link['target']);
});
}
}
//删除节点
veNode=function(id){
var i=0,
n=this.findNode(id),
links=this.links;
while ( i < links.length){
links[i]['source']==n || links[i]['target'] ==n ? links.splice(i,1) : ++i;
}
}
//删除节点下的⼦节点,同时清除link信息
veChildNodes=function(id){
var node=this.findNode(id),
des;
links=this.links,
self=this;
var linksToDelete=[],
childNodes=[];
links.forEach(function(link,index){
link['source']==node
&& linksToDelete.push(index)
&& childNodes.push(link['target']);
});
links.splice(index,1);
});
var remove=function(node){
var length=links.length;
for(var i=length-1;i>=0;i--){
if (links[i]['source'] == node ){
var target=links[i]['target'];
links.splice(i,1);
nodes.splice(self.findNodeIndex(node.id),1);
remove(target);
}
}
}
childNodes.forEach(function(node){
remove(node);
});
//清除没有连线的节点
for(var i=nodes.length-1;i>=0;i--){
var haveFoundNode=false;
for(var j=0,l=links.length;j<l;j++){
( links[j]['source']==nodes[i] || links[j]['target']==nodes[i] ) && (haveFoundNode=true)  }
!haveFoundNode && nodes.splice(i,1);
}
}
//查节点
Topology.prototype.findNode=function(id){
var des;
for (var i in nodes){
if (nodes[i]['id']==id ) return nodes[i];
}
return null;
}
//查节点所在索引号3 d
Topology.prototype.findNodeIndex=function(id){
var des;
for (var i in nodes){
if (nodes[i]['id']==id ) return i;
}
return -1;
}
//节点点击事件
Topology.prototype.setNodeClickFn=function(callback){
this.clickFn=callback;
}
//更新拓扑图状态信息
Topology.prototype.update=function(){
var link = this.vis.selectAll("line.link")
.data(this.links, function(d) { return d.source.id + "-" + d.target.id; })
.attr("class", function(d){
return d['source']['status'] && d['target']['status'] ? 'link' :'link link_error';
});
<().insert("svg:line", "g.node")
.attr("class", function(d){
return d['source']['status'] && d['target']['status'] ? 'link' :'link link_error';
});
var node = this.vis.selectAll("g.node")
.des, function(d) { return d.id;});
var nodeEnter = ().append("svg:g")
.attr("class", "node")
.call(this.force.drag);
//增加图⽚,可以根据需要来修改
var self=this;
nodeEnter.append("svg:image")
.attr("class", "circle")
.attr("xlink:href", function(d){
//根据类型来使⽤图⽚
pand ? "ww2.sinaimg/large/412e82dbjw1dsbny7igx2j.jpg" : "ww4.sinaimg/large/412e82dbjw1dsbnxezrrpj.jpg"; })
.attr("x", "-32px")
.attr("y", "-32px")
.attr("width", "64px")
.attr("height", "64px")
.on('click',function(d){ d.expand && self.clickFn(d);})
nodeEnter.append("svg:text")
.attr("class", "nodetext")
.attr("dx", 15)
.attr("dy", -35)
.text(function(d) { return d.id });
this.force.start();
}
var topology=new Topology('container');
var nodes=[
{id:'10.4.42.1',type:'router',status:1},
{id:'10.4.43.1',type:'switch',status:1,expand:true},
{id:'10.4.44.1',type:'switch',status:1},
{id:'10.4.45.1',type:'switch',status:0}
];
var childNodes=[
{id:'10.4.43.2',type:'switch',status:1},
{id:'10.4.43.3',type:'switch',status:1}
];
var links=[
{source:'10.4.42.1',target:'10.4.43.1'},
{source:'10.4.42.1',target:'10.4.44.1'},
{source:'10.4.42.1',target:'10.4.45.1'}
];
var childLinks=[
{source:'10.4.43.1',target:'10.4.43.2'},
{source:'10.4.43.1',target:'10.4.43.3'},
{source:'10.4.43.2',target:'10.4.43.3'}
]
topology.addNodes(nodes);
topology.addLinks(links);
//可展开节点的点击事件
topology.setNodeClickFn(function(node){
if(!node['_expanded']){
expandNode(node.id);
node['_expanded']=true;
}else{
collapseNode(node.id);
node['_expanded']=false;
}
});
topology.update();
function expandNode(id){
topology.addNodes(childNodes);
topology.addLinks(childLinks);
topology.update();
}
function collapseNode(id){
topology.update();
}
</script>
</body>
</html>
总结
以上就是这篇⽂章的全部内容了,希望本⽂的内容对⼤家的学习或者⼯作能带来⼀定的帮助,如果有疑问⼤家可以了留⾔交流。