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 相关文章推荐
JavaScript验证图片类型(扩展名)的函数分享
May 05 Javascript
js用拖动滑块来控制图片大小的方法
Feb 27 Javascript
input输入框鼠标焦点提示信息
Mar 17 Javascript
javascript下拉列表中显示树形菜单的实现方法
Nov 17 Javascript
浅谈JS继承_借用构造函数 &amp; 组合式继承
Aug 16 Javascript
jQuery Easyui快速入门教程
Aug 21 Javascript
vue使用keep-alive实现数据缓存不刷新
Oct 21 Javascript
jquery使用FormData实现异步上传文件
Oct 25 jQuery
浅谈Vue数据响应思路之数组
Nov 06 Javascript
ES6中Set和Map数据结构,Map与其它数据结构互相转换操作实例详解
Feb 28 Javascript
Vue项目接入Paypal实现示例详解
Jun 04 Javascript
关于better-scroll插件的无法滑动bug(2021通过插件解决)
Mar 01 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
摩卡咖啡
2021/03/03 咖啡文化
用PHP和ACCESS写聊天室(八)
2006/10/09 PHP
php异常处理方法实例汇总
2015/06/24 PHP
JavaScript高级程序设计
2006/12/29 Javascript
出现“不能执行已释放的Script代码”错误的原因及解决办法
2007/08/29 Javascript
简明json介绍
2008/09/28 Javascript
基于jquery的获取浏览器窗口大小的代码
2011/03/28 Javascript
js函数的引用, 关于内存的开销
2012/09/17 Javascript
JS操作select下拉框动态变动(创建/删除/获取)
2013/06/02 Javascript
js监听鼠标事件控制textarea输入字符串的个数
2014/09/29 Javascript
jQuery实现的调整表格行tr上下顺序
2016/01/10 Javascript
jQuery实现手机上输入后隐藏键盘功能
2017/01/04 Javascript
vue基于mint-ui的城市选择3级联动的示例
2017/10/25 Javascript
用vue2.0实现点击选中active其他选项互斥的效果
2018/04/12 Javascript
vue.js的状态管理vuex中store的使用详解
2019/11/08 Javascript
python 中文乱码问题深入分析
2011/03/13 Python
python 图片验证码代码分享
2012/07/04 Python
详解python的webrtc库实现语音端点检测
2017/05/31 Python
Python 实现购物商城,含有用户入口和商家入口的示例
2017/09/15 Python
多个应用共存的Django配置方法
2018/05/30 Python
使用python itchat包爬取微信好友头像形成矩形头像集的方法
2019/02/21 Python
用django设置session过期时间的方法解析
2019/08/05 Python
Python+Selenium实现自动化的环境搭建的步骤(图文)
2020/09/01 Python
python中添加模块导入路径的方法
2021/02/03 Python
HTML5新特性之语义化标签
2017/10/31 HTML / CSS
毕业生造价工程师求职信
2013/10/17 职场文书
后勤岗位职责
2013/11/26 职场文书
网上开商店的创业计划书
2014/01/19 职场文书
社区安全检查制度
2014/02/03 职场文书
cf收人广告词
2014/03/14 职场文书
商业融资计划书
2014/04/29 职场文书
教师暑期培训感言
2014/08/15 职场文书
深入开展党的群众路线教育实践活动心得体会
2014/11/05 职场文书
英语读书笔记
2015/07/02 职场文书
PHP策略模式写法
2021/04/01 PHP
Python中rapidjson参数校验实现
2021/07/25 Python