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 相关文章推荐
Prototype Function对象 学习
Jul 12 Javascript
javascript 获取页面的高度及滚动条的位置的代码
May 06 Javascript
jquery弹出关闭遮罩层实例
Aug 06 Javascript
Javascript selection的兼容性写法介绍
Dec 20 Javascript
使用Chrome调试JavaScript的断点设置和调试技巧
Dec 16 Javascript
js鼠标悬浮出现遮罩层的方法
Jan 28 Javascript
简介JavaScript中valueOf()方法的使用
Jun 05 Javascript
jQuery实现可高亮显示的二级CSS菜单效果
Sep 01 Javascript
微信小程序 地图定位简单实例
Oct 14 Javascript
实例解析angularjs的filter过滤器
Dec 14 Javascript
微信小程序动态添加分享数据
Jun 14 Javascript
浅谈关于iview表单验证的问题
Sep 29 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实现通过Luhn算法校验信用卡卡号是否有效
2015/03/23 PHP
php写app接口并返回json数据的实例(分享)
2017/05/20 PHP
yii2.0整合阿里云oss上传单个文件的示例
2017/09/19 PHP
laravel框架创建授权策略实例分析
2019/11/22 PHP
php设计模式之观察者模式实例详解【星际争霸游戏案例】
2020/03/30 PHP
javascript firefox兼容ie的dom方法脚本
2008/05/18 Javascript
javascript Window及document对象详细整理
2011/01/12 Javascript
jQuery实战之仿淘宝商城左侧导航效果
2011/04/12 Javascript
js 获取本地文件及目录的方法(推荐)
2016/11/10 Javascript
微信小程序 自定义对话框实例详解
2017/01/20 Javascript
JavaScript实现自动跳转文本功能
2017/05/25 Javascript
基于JavaScript实现带数据验证和复选框的表单提交
2017/08/23 Javascript
JS开发 富文本编辑器TinyMCE详解
2019/07/19 Javascript
vue input标签通用指令校验的实现
2019/11/05 Javascript
JavaScript使用canvas绘制随机验证码
2020/02/17 Javascript
微信小程序实现签到弹窗动画
2020/09/21 Javascript
vue+element实现动态加载表单
2020/12/13 Vue.js
原生微信小程序开发中 redux 的使用详解
2021/02/18 Javascript
Python中decorator使用实例
2015/04/14 Python
RC4文件加密的python实现方法
2015/06/30 Python
Python的Flask框架中SQLAlchemy使用时的乱码问题解决
2015/11/07 Python
Python的SimpleHTTPServer模块用处及使用方法简介
2018/01/22 Python
Python爬虫之网页图片抓取的方法
2018/07/16 Python
详解Anconda环境下载python包的教程(图形界面+命令行+pycharm安装)
2019/11/11 Python
python实现二分类的卡方分箱示例
2019/11/22 Python
Python之Class&amp;Object用法详解
2019/12/25 Python
英国家喻户晓的家居商店:The Range
2019/03/25 全球购物
L’Artisan Parfumeur官网:法国香水品牌
2020/08/11 全球购物
销售总监岗位职责
2014/01/04 职场文书
优秀教师事迹简介
2014/02/02 职场文书
2014年学习雷锋活动总结
2014/03/01 职场文书
《果园机器人》教学反思
2014/04/13 职场文书
小学一年级学生评语
2014/04/22 职场文书
小小商店教学反思
2014/04/27 职场文书
2015毕业寄语大全
2015/02/26 职场文书
民主生活会主持词
2015/07/01 职场文书