d3.js實現(xiàn)簡單的網(wǎng)絡拓撲圖實例代碼
前言
了解了D3.js的基本開發(fā)和組件以后,我們開始應用它激動人心之處:絢麗的預定義圖形,應用D3.js,我們在它的示例文件的基礎上稍加變動即可應用于我們的數(shù)據(jù)可視化工作中,D3.js將后臺的運算已經(jīng)預定義好,我們只需少量代碼和規(guī)范的數(shù)據(jù),就能做出很花哨(請原諒我的用詞不當)的效果。
力學圖(也稱為導向圖,也有叫網(wǎng)絡拓補圖的,反正就是通過排斥得到關(guān)系遠近的結(jié)構(gòu))在社交網(wǎng)絡研究、信息傳播途徑等群體關(guān)系研究中應用非常廣泛,它可以直觀地反映群體與群體之間聯(lián)系的渠道、交集多少,群體內(nèi)部成員的聯(lián)系強度等。
本文實現(xiàn)如下面的效果(用非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 + ")"); } //增加節(jié)點 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']); }); } } //刪除節(jié)點 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); } //刪除節(jié)點下的子節(jié)點,同時清除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); }); //清除沒有連線的節(jié)點 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); } } //查找節(jié)點 Topology.prototype.findNode=function(id){ var nodes=this.nodes; for (var i in nodes){ if (nodes[i]['id']==id ) return nodes[i]; } return null; } //查找節(jié)點所在索引號 Topology.prototype.findNodeIndex=function(id){ var nodes=this.nodes; for (var i in nodes){ if (nodes[i]['id']==id ) return i; } return -1; } //節(jié)點點擊事件 Topology.prototype.setNodeClickFn=function(callback){ this.clickFn=callback; } //更新拓撲圖狀態(tài)信息 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); //增加圖片,可以根據(jù)需要來修改 var self=this; nodeEnter.append("svg:image") .attr("class", "circle") .attr("xlink:href", function(d){ //根據(jù)類型來使用圖片 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); //可展開節(jié)點的點擊事件 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>
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以了留言交流。
相關(guān)文章
3分鐘教你用JavaScript實現(xiàn)電子簽名效果
電子簽名已經(jīng)成為現(xiàn)代商業(yè)中不可或缺的一部分,它可以提高業(yè)務流程的效率和安全性。本文將介紹如何使用HTML5的canvas元素和JavaScript在前端實現(xiàn)電子簽名,需要的可以參考一下2023-04-04性能優(yōu)化篇之Webpack構(gòu)建速度優(yōu)化的建議
這篇文章主要介紹了性能優(yōu)化篇之Webpack構(gòu)建速度優(yōu)化的建議,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-04-04微信小程序云開發(fā)實現(xiàn)數(shù)據(jù)添加、查詢和分頁
這篇文章主要為大家詳細介紹了微信小程序云開發(fā)實現(xiàn)數(shù)據(jù)添加、查詢和分頁,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-05-05JavaScript實現(xiàn)帶緩沖效果的隨屏滾動漂浮廣告代碼
這篇文章主要介紹了JavaScript實現(xiàn)帶緩沖效果的隨屏滾動漂浮廣告代碼,通過JavaScript結(jié)合時間函數(shù)動態(tài)響應頁面元素滾動事件實現(xiàn)懸浮廣告的緩沖漂浮效果,非常簡單實用,需要的朋友可以參考下2015-11-11JavaScript實現(xiàn)的原生態(tài)兼容IE6可調(diào)可控滾動文字功能詳解
這篇文章主要介紹了JavaScript實現(xiàn)的原生態(tài)兼容IE6可調(diào)可控滾動文字功能,簡單說明了文字滾動的實現(xiàn)原理并結(jié)合具體實例形式給出了javascript文字滾動功能的具體實現(xiàn)代碼,需要的朋友可以參考下2017-09-09