赞
踩
先展示一波最终效果
这段时间再学习D3,力导向图
力导向图(Force-Directed Graph),是绘图的一种算法。在二维或三维空间里配置节点,节点之间用线连接,称为连线。各连线的长度几乎相等,且尽可能不相交。节点和连线都被施加了力的作用,力是根据节点和连线的相对位置计算的。根据力的作用,来计算节点和连线的运动轨迹,并不断降低它们的能量,最终达到一种能量很低的安定状态。
力导向图能表示节点之间的多对多的关系。
定义一个力导向图的布局关键方法 force()
d3在v3和v4版本上对于 force() 这个方法变动很大
话不多说,代码如下:(注意:这次使用的D3.js版本是V3的)
代码不是最终代码,但是功能基本已经实现,后续会更新这一版的最终代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>The END</title> <script src="http://d3js.org/d3.v3.min.js"></script> <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.js"></script> <script src="./js/smartMenu.js"></script> <script src="./fun.js"></script> <link rel="stylesheet" href="./css/smartMenu.css"> </head> <body> <div id="tpContainer"> </div> </body> </html>
//获取数据 d3.json('./preson.json', function(error,data){ if (error) { return console.log(error); } // console.log(data); drawToPofun(data.nodes,data.lines); }); function drawToPofun(nodes,edges){ //定义初始变量 var width = 1503; var height = 654; var img_w = 40; var img_h = 40; var text_dx = -20; var text_dy = 20; var i = 0; //初始化拖拽方法 var drag = d3.behavior.drag() .origin(function(d) { return d; }) .on("dragstart", dragstarted) .on("drag", dragged) .on("dragend", dragended); //初始化缩放方法 var zoom=d3.behavior.zoom() .scaleExtent([-10,10]).on("zoom",zoomed); //定义画布 var svg = d3.select("#tpContainer") .append("svg") .attr("width",width) .attr("height",height) .call(zoom) .on("dblclick.zoom", () => {});//禁止双击放大 //拆分子节点 var view = svg.append("g") .attr("class","graphCon"); var node = view.selectAll("g.node").data(nodes,function (d) { return d.id || (d.id = ++i); }); var nodeEnter = node .enter() .append("g") .attr("class","node") .attr("id",d=>d.id); //添加节点,以自定义图标代替 var nodes_img = nodeEnter.append("image") .data(nodes) .attr("width",function(d){ return img_w; }) .attr("height",function(d){ return img_h; }) .attr("xlink:href",function(d){ return d.image; }) .call(drag)//开始拖拽方法 //添加连线 var edges_line = nodeEnter.append("line") .data(edges) .attr("class","line") .style("stroke","#ccc") .style("stroke-width",1); //添加节点说明(文本) var nodes_text = nodeEnter.append("text") .data(nodes) .attr("class","nodetext") .attr("dx",text_dx) .attr("dy",text_dy) .text(function(d){ return d.name; }); //定义力学图布局 var force = d3.layout.force().nodes(nodes) .links(edges) .size([width,height]) .linkDistance(200) .charge(-800) .start() .on("tick", function(){ //限制结点的边界 nodes.forEach(function(d,i){ d.x = d.x - img_w/2 < 0? img_w/2 : d.x ; d.x = d.x + img_w/2 > width ? width - img_w/2 : d.x ; d.y = d.y - img_h/2 < 0? img_h/2 : d.y ; d.y = d.y + img_h/2 + text_dy > height ? height - img_h/2 - text_dy : d.y ; }); //更新连接线的位置 edges_line.attr("x1",function(d){ return d.source.x; }); edges_line.attr("y1",function(d){ return d.source.y; }); edges_line.attr("x2",function(d){ return d.target.x; }); edges_line.attr("y2",function(d){ return d.target.y; }); //更新结点图片和文字 nodes_img.attr("x",function(d){ return d.x - img_w/2; }); nodes_img.attr("y",function(d){ return d.y - img_h/2; }); nodes_text.attr("x",function(d){ return d.x; }); nodes_text.attr("y",function(d){ return d.y + img_h/2; }); }); // 定义菜单选项 var userMenuData = [ [{ text: "菜单1", func: function () { var id = Number($(this).attr("id")) alert("菜单1"+",No."+ id) } }, { text: "菜单2", func: function () { var id = Number($(this).attr("id")) alert("菜单2"+",No."+ id) } }, { text: "菜单3", func: function () { var id = Number($(this).attr("id")) alert("菜单3"+",No."+ id) } } ] ]; // 事件监听方式添加事件绑定 $("body").smartMenu(userMenuData, { name: "chatRightControl", container: "g.node" }); function zoomed(){ view.attr("transform", "translate("+d3.event.translate+")scale(" + d3.event.scale + ")"); } function dragstarted(d) { d3.event.sourceEvent.stopPropagation(); d3.select(this).classed("dragging", true); force.start(); } function dragged(d) { d.x = d3.event.x; d.y = d3.event.y; } function dragended(d) { d3.select(this).classed("dragging", false); } }
{ "nodes": [ {"name": "preson1", "image": "./person.png"}, {"name": "preson2", "image": "./person.png"}, {"name": "preson3", "image": "./person.png"}, {"name": "preson4", "image": "./person.png"}, {"name": "preson5", "image": "./person.png"}, {"name": "preson6", "image": "./person.png"}, {"name": "preson7", "image": "./person.png"}, {"name": "preson8", "image": "./person.png"}, {"name": "preson9", "image": "./person.png"}, {"name": "preson10","image": "./person.png"} ], "lines": [ { "source": 0 , "target": 1 }, { "source": 0 , "target": 2 }, { "source": 0 , "target": 3 }, { "source": 1 , "target": 4 }, { "source": 1 , "target": 5 }, { "source": 1 , "target": 6 }, { "source": 0 , "target": 7 }, { "source": 7 , "target": 8 }, { "source": 7 , "target": 9 } ] }
菜单我用的是jQuery插件,下载下来的,js/css代码就不展示了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。