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 相关文章推荐
jQuery EasyUI API 中文文档 - Documentation 文档
Sep 29 Javascript
简单的JS时钟实例讲解
Jan 13 Javascript
一步步教大家编写酷炫的导航栏js+css实现
Mar 14 Javascript
jquery插件方式实现table查询功能的简单实例
Jun 06 Javascript
js获取对象、数组的实际长度,元素实际个数的实现代码
Jun 08 Javascript
AngularJS过滤器filter用法总结
Dec 13 Javascript
AngularJS实现图片上传和预览功能的方法分析
Nov 08 Javascript
JS排序算法之冒泡排序,选择排序与插入排序实例分析
Dec 13 Javascript
详解Angular2学习笔记之Html属性绑定
Jan 03 Javascript
layui表格 列自动适应大小失效的解决方法
Sep 06 Javascript
vue开发拖拽进度条滑动组件
Sep 21 Javascript
原生js滑动轮播封装
Jul 31 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
DSP接收机前端设想
2021/03/02 无线电
php 将bmp图片转为jpg等其他任意格式的图片
2009/06/29 PHP
PHP中使用php://input处理相同name值的表单数据
2015/02/03 PHP
CI(Codeigniter)的Setting增强配置类实例
2016/01/06 PHP
PHP使用token防止表单重复提交的方法
2016/04/07 PHP
老生常谈PHP位运算的用途
2017/03/12 PHP
解读JavaScript中 For, While与递归的用法
2013/05/07 Javascript
jQuery中eq()方法用法实例
2015/01/05 Javascript
javascript框架设计之浏览器的嗅探和特征侦测
2015/06/23 Javascript
angularjs学习笔记之完整的项目结构
2015/09/26 Javascript
解决wx.onMenuShareTimeline出现的问题
2016/08/16 Javascript
基于JavaScript实现飘落星星特效
2017/08/10 Javascript
BootStrap模态框不垂直居中的解决方法
2017/10/19 Javascript
vue中v-model动态生成的实例详解
2017/10/27 Javascript
jQuery ajax读取本地json文件的实例
2017/10/31 jQuery
nodejs操作mongodb的填删改查模块的制作及引入实例
2018/01/02 NodeJs
iview tabs 顶部导航栏和模块切换栏的示例代码
2019/03/04 Javascript
Vue源码之关于vm.$delete()/Vue.use()内部原理详解
2019/05/01 Javascript
使用vue脚手架(vue-cli)搭建一个项目详解
2019/05/09 Javascript
详解vue中v-bind:style效果的自定义指令
2020/01/21 Javascript
微信小程序自定义底部弹出框动画
2020/11/18 Javascript
[01:16:28]DOTA2-DPC中国联赛 正赛 iG vs Magma BO3 第二场 2月23日
2021/03/11 DOTA
python去重,一个由dict组成的list的去重示例
2019/01/21 Python
Django框架使用内置方法实现登录功能详解
2019/06/12 Python
Python的log日志功能及设置方法
2019/07/11 Python
python3-flask-3将信息写入日志的实操方法
2019/11/12 Python
Python的pygame安装教程详解
2020/02/10 Python
Python实现打包成库供别的模块调用
2020/07/13 Python
django有哪些好处和优点
2020/09/01 Python
2014信息技术专业毕业生自我评价
2014/01/17 职场文书
小学运动会表扬稿
2014/01/19 职场文书
党的群众路线对照检查材料(个人)
2014/09/24 职场文书
如何签定毕业生就业协议书
2014/09/28 职场文书
高三英语教学计划
2015/01/23 职场文书
泰山导游词
2015/02/02 职场文书
2015年学生会主席工作总结
2015/04/21 职场文书