d3.js实现简单的网络拓扑图实例代码


Posted in Javascript onNovember 06, 2016

前言

了解了D3.js的基本开发和组件以后,我们开始应用它激动人心之处:绚丽的预定义图形,应用D3.js,我们在它的示例文件的基础上稍加变动即可应用于我们的数据可视化工作中,D3.js将后台的运算已经预定义好,我们只需少量代码和规范的数据,就能做出很花哨(请原谅我的用词不当)的效果。

力学图(也称为导向图,也有叫网络拓补图的,反正就是通过排斥得到关系远近的结构)在社交网络研究、信息传播途径等群体关系研究中应用非常广泛,它可以直观地反映群体与群体之间联系的渠道、交集多少,群体内部成员的联系强度等。

本文实现如下面的效果(用非IE浏览器可以看到效果):

d3.js实现简单的网络拓扑图实例代码

代码有点长,但是也不复杂,可以参考如下代码:

<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="http://mbostock.github.com/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' && (ele=document.getElementById(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.nodes=this.force.nodes();
 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");

 this.force.on("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(" + d3.event.translate + ")"+ " scale(" + d3.event.scale + ")");

}


//增加节点
Topology.prototype.addNode=function(node){
 this.nodes.push(node);
}

Topology.prototype.addNodes=function(nodes){
 if (Object.prototype.toString.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 (Object.prototype.toString.call(links)=='[object Array]' ){
 var self=this;
 links.forEach(function(link){
  self.addLink(link['source'],link['target']);
 });
 }
}


//删除节点
Topology.prototype.removeNode=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;
 }
 this.nodes.splice(this.findNodeIndex(id),1);
}

//删除节点下的子节点,同时清除link信息
Topology.prototype.removeChildNodes=function(id){
 var node=this.findNode(id),
 nodes=this.nodes;
 links=this.links,
 self=this;

 var linksToDelete=[],
 childNodes=[];
 
 links.forEach(function(link,index){
 link['source']==node 
  && linksToDelete.push(index) 
  && childNodes.push(link['target']);
 });

 linksToDelete.reverse().forEach(function(index){
 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 nodes=this.nodes;
 for (var i in nodes){
 if (nodes[i]['id']==id ) return nodes[i];
 }
 return null;
}


//查找节点所在索引号
Topology.prototype.findNodeIndex=function(id){
 var nodes=this.nodes;
 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';
 });

 link.enter().insert("svg:line", "g.node")
 .attr("class", function(d){
  return d['source']['status'] && d['target']['status'] ? 'link' :'link link_error';
 });

 link.exit().remove();

 var node = this.vis.selectAll("g.node")
 .data(this.nodes, function(d) { return d.id;});

 var nodeEnter = node.enter().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){
  //根据类型来使用图片
  return d.expand ? "http://ww2.sinaimg.cn/large/412e82dbjw1dsbny7igx2j.jpg" : "http://ww4.sinaimg.cn/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 });

 
 node.exit().remove();

 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.removeChildNodes(id);
 topology.update();
}

</script>
</body>
</html>

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以了留言交流。

Javascript 相关文章推荐
共享自己写一个框架DreamScript
Jan 20 Javascript
css配合jquery美化 select
Nov 29 Javascript
jquery通过a标签删除table中的一行的代码
Dec 02 Javascript
Javascript中arguments和arguments.callee的区别浅析
Apr 24 Javascript
jQuery实现的超酷苹果风格图标滑出菜单效果代码
Sep 16 Javascript
jQuery.ajax实现根据不同的Content-Type做出不同的响应
Nov 03 Javascript
JS定时器实现数值从0到10来回变化
Dec 09 Javascript
AngularJS基于http请求实现下载php生成的excel文件功能示例
Jan 23 Javascript
vue实现文字加密功能
Sep 27 Javascript
微信小程序swiper使用网络图片不显示问题解决
Dec 13 Javascript
element 动态合并表格的步骤
Dec 31 Javascript
如何在CocosCreator里画个炫酷的雷达图
Apr 16 Javascript
HTML5 JS压缩图片并获取图片BASE64编码上传
Nov 16 #Javascript
JS控制div跳转到指定的位置的几种解决方案总结
Nov 05 #Javascript
xcode中获取js文件的路径方法(推荐)
Nov 05 #Javascript
在js里怎么实现Xcode里的callFuncN方法(详解)
Nov 05 #Javascript
jquery.Jcrop结合JAVA后台实现图片裁剪上传实例
Nov 05 #Javascript
JavaScript中绑定事件的三种方式及去除绑定
Nov 05 #Javascript
Ajax与服务器(JSON)通信实例代码
Nov 05 #Javascript
You might like
PHP判断手机是IOS还是Android
2015/12/09 PHP
thinkPHP5框架路由常用知识点汇总
2019/09/15 PHP
php设计模式之建造器模式分析【星际争霸游戏案例】
2020/01/23 PHP
Nigma vs Alliance BO5 第五场2.14
2021/03/10 DOTA
如何让您的中波更粗更长 - 中波框形天线制作
2021/03/10 无线电
Dom 结点创建 基础知识
2011/10/01 Javascript
js实现3D图片逐张轮播幻灯片特效代码分享
2015/09/09 Javascript
js判断某个字符出现的次数的简单实例
2016/06/03 Javascript
微信小程序实现图片轮播及文件上传
2017/04/07 Javascript
JSON在Javascript中的使用(eval和JSON.parse的区别)详细解析
2017/09/05 Javascript
移动前端图片压缩上传的实例
2017/12/06 Javascript
Node.js 使用request模块下载文件的实例
2018/09/05 Javascript
JavaScript两种计时器的实例讲解
2019/01/31 Javascript
vue + node如何通过一个Txt文件批量生成MP3并压缩成Zip
2020/06/02 Javascript
js节流防抖应用场景,以及在vue中节流防抖的具体实现操作
2020/09/21 Javascript
[05:56]第十六期——新进3大C之小兔基
2014/06/24 DOTA
[03:41]DOTA2上海特锦赛小组赛第三日recap精彩回顾
2016/02/28 DOTA
Python3中的列表,元组,字典,字符串相关知识小结
2017/11/10 Python
[原创]Python入门教程4. 元组基本操作
2018/10/31 Python
Python图像处理之颜色的定义与使用分析
2019/01/03 Python
python如何制作英文字典
2019/06/25 Python
解决Django中多条件查询的问题
2019/07/18 Python
django项目简单调取百度翻译接口的方法
2019/08/06 Python
Python文件路径名的操作方法
2019/10/30 Python
利用CSS3实现自定义滚动条代码分享
2016/08/18 HTML / CSS
7款设计巧妙的css3飘带状3D立体效果的导航菜单和表单窗口
2013/02/04 HTML / CSS
css3圆角边框和边框阴影示例
2014/05/05 HTML / CSS
周仰杰(JIMMY CHOO)英国官方网站:闻名世界的鞋子品牌
2018/10/28 全球购物
BudgetAir印度:预订航班、酒店和汽车租赁
2019/07/07 全球购物
大学生蛋糕店创业计划书
2014/01/13 职场文书
大专生自我评价
2014/01/28 职场文书
派出所所长先进事迹
2014/05/19 职场文书
解决Jupyter-notebook不弹出默认浏览器的问题
2021/03/30 Python
如何利用pygame实现打飞机小游戏
2021/05/30 Python
Java集成swagger文档组件
2021/06/28 Java/Android
MYSQL中文乱码问题的解决方案
2022/06/14 MySQL