绘制人物关系图




<!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
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值