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 相关文章推荐
下载文件个别浏览器文件名乱码解决办法
Mar 19 Javascript
javascript教程:关于if简写语句优化的方法
May 17 Javascript
jQuery中判断对象是否存在的方法汇总
Feb 24 Javascript
前端构建工具之gulp的语法教程
Jun 12 Javascript
jQuery+C#实现参数RSA加密传输功能【附jsencrypt.js下载】
Jun 26 jQuery
详解Angular CLI + Electron 开发环境搭建
Jul 20 Javascript
vue mintui-Loadmore结合实现下拉刷新和上拉加载示例
Oct 12 Javascript
vue mint-ui tabbar变组件使用
May 04 Javascript
Vue+Jwt+SpringBoot+Ldap完成登录认证的示例代码
May 21 Javascript
Vue Element 分组+多选+可搜索Select选择器实现示例
Jul 23 Javascript
三步实现ionic3点击退出app程序
Sep 17 Javascript
vue实现简单数据双向绑定
Apr 28 Vue.js
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
ThinkPHP使用心得分享-ThinkPHP + Ajax 实现2级联动下拉菜单
2014/05/15 PHP
PHP编程文件处理类SplFileObject和SplFileInfo用法实例分析
2017/07/22 PHP
Yii2.0框架实现带分页的多条件搜索功能示例
2019/02/20 PHP
jQuery 源代码显示控件 (Ajax加载方式).
2009/05/18 Javascript
js时间戳格式化成日期格式的多种方法
2013/11/11 Javascript
javascript实现json页面分页实例代码
2014/02/20 Javascript
javascript获取select值的方法分析
2015/07/02 Javascript
基于jQuery实现美观且实用的倒计时实例代码
2015/12/30 Javascript
Bootstrap框架安装使用详解
2017/01/21 Javascript
80%应聘者都不及格的JS面试题
2017/03/21 Javascript
MUI 上拉刷新/下拉加载功能实例代码
2017/04/13 Javascript
JavaScript比较两个数组的内容是否相同(推荐)
2017/05/02 Javascript
使用原生js+canvas实现模拟心电图的实例
2017/09/20 Javascript
详解关于vue-area-linkage走过的坑
2018/06/27 Javascript
Vue组件教程之Toast(Vue.extend 方式)详解
2019/01/27 Javascript
详解JavaScript中关于this指向的4种情况
2019/04/18 Javascript
JS实现电脑虚拟键盘打字测试
2020/06/24 Javascript
基于脚手架创建Vue项目实现步骤详解
2020/08/03 Javascript
python实现彩色图转换成灰度图
2019/01/15 Python
Python Pandas数据中对时间的操作
2019/07/30 Python
在python中使用pyspark读写Hive数据操作
2020/06/06 Python
x-ua-compatible content=”IE=7, IE=9″意思理解
2013/07/22 HTML / CSS
Sunglasses Shop德国站:欧洲排名第一的太阳镜网站
2017/08/01 全球购物
英国家喻户晓的高街品牌:River Island
2017/11/28 全球购物
什么是三层交换,说说和路由的区别在那里
2014/09/01 面试题
产品促销活动策划书
2014/01/15 职场文书
优秀少先队大队辅导员事迹材料
2014/05/04 职场文书
课程设计的心得体会
2014/09/03 职场文书
高等学院职业生涯规划书范文
2014/09/16 职场文书
老人再婚离婚协议书范本
2014/10/27 职场文书
2014年司机工作总结
2014/11/21 职场文书
2014年招商工作总结
2014/11/22 职场文书
2016拓展训练心得体会范文
2016/01/12 职场文书
《中国古代诗歌散文欣赏》高中语文教材
2019/08/20 职场文书
Linux安装Nginx步骤详解
2021/03/31 Servers
JS实现简单控制视频播放倍速的实例代码
2021/04/18 Javascript