d3.js实现简单的网络拓扑图实例代码
作者:daisy 发布时间:2024-05-09 10:19:58
标签:d3.js,网络,拓扑图
前言
了解了D3.js的基本开发和组件以后,我们开始应用它激动人心之处:绚丽的预定义图形,应用D3.js,我们在它的示例文件的基础上稍加变动即可应用于我们的数据可视化工作中,D3.js将后台的运算已经预定义好,我们只需少量代码和规范的数据,就能做出很花哨(请原谅我的用词不当)的效果。
力学图(也称为导向图,也有叫网络拓补图的,反正就是通过排斥得到关系远近的结构)在社交网络研究、信息传播途径等群体关系研究中应用非常广泛,它可以直观地反映群体与群体之间联系的渠道、交集多少,群体内部成员的联系强度等。
本文实现如下面的效果(用非IE浏览器可以看到效果):
代码有点长,但是也不复杂,可以参考如下代码:
<!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>
总结


猜你喜欢
- 1、说明创建堆有两种基本方法:heappush() 和 heapify()。当使用heappush()时,当新元素添加时,堆得顺序被保持了。
- Django 提供内置的视图(view)函数用于处理登录和退出 (以及其他奇技淫巧),但在开始前,我们来看看如何手工登录和退出。 Djang
- 记录下第一次使用Python读写文件的过程,虽然很简单,第一次实现其实也有些注意的事项。单个文件的读操作:我们先假设一个需求如下:读取一个t
- 本文实例讲述了Python自动发送邮件的方法。分享给大家供大家参考,具体如下:python发邮件需要掌握两个模块的用法,smtplib和em
- 以前写代码时,都是直接将程序绑定到唯一端口提供http/https服务,在外层通过反向代理(nginx/caddy)来实现http和http
- 引言委托 和 事件在 .Net Framework中的应用非常广泛,然而,较好地理解委托和事件对很多接触C#时间不长的人来说并不容易。它们就
- 真正意义上来说Javascript并不是一门面向对象的语言,没有提供传统的继承方式,但是它提供了一种原型继承的方式,利用自身提供的原型属性来
- python中有两种方法可以调用父类的方法:super(Child, self).method(args) Parent.meth
- Python是一门面向对象的语言,定义类时经常要用到继承,在类的继承中,子类继承父类中已经封装好的方法,不需要再次编写,如果子类如果重新定义
- 本文实例讲述了JS实现利用两个队列表示一个栈的方法。分享给大家供大家参考,具体如下:先看原理图:理清楚思路,再动笔写:<!DOCTYP
- 前言要将图片转换为字符图其实很简单,我们首先将图片转换为灰度图像,这样图片的每个像素点的颜色值都是0到255,然后我们选用一些在文字矩形框内
- Hypothesis是Python的一个高级测试库。它允许编写测试用例时参数化,然后生成使测试失败的简单易懂的测试数据。可以用更少的工作在代
- 才发现做了这么多的博客和视频,居然从来没有系统地做过分类网络,做一个科学的分类网络,对身体好。源码下载分类网络的常见形式常见的分类网络都可以
- 本文实例讲述了Python使用MYSQLDB实现从数据库中导出XML文件的方法。分享给大家供大家参考。具体分析如下:这里需要给前端以xml格
- 一、前言相关知识来自《python算法设计与分析》。初级排序算法是指几种较为基础且容易理解的排序算法。初级排序算法包括插入排序、选择排序和冒
- 第一种import win32clipboardimport time#速度快 容易出错class niubi(): def l
- 在我的上篇文章发出之后,我听到对“WEb2.0视觉风格”这个称谓的不认同声音。其实这并不出乎我的意料,因为,我在认真的开始思考“WEb2.0
- 文通过一个操作实例来说明SQL中主标识列IDENTITY的使用技巧。要求:在 sql server 2005中,建立数据表book,在表bo
- 以前的Dreamweaver中是没有图片处理功能的,即使你要处理也只能使用CSS中的相关滤镜进行一些效
- Python中专门提供了telnetlib库,用来完成基于telnet协议的通信功能。python3下使用telnetlib模块连接网络设备