当前位置:   article > 正文

D3.js的v5版本入门教程(第十四章)—— 力导向图_vue d3.js v5力导向图带箭头

vue d3.js v5力导向图带箭头

D3.js的v5版本入门教程(第十四章)

    

    这一章我们来绘制一个力导向图,什么叫力导向图,通俗一点将就是有节点和线组成,当鼠标拖拽一个节点时,其他节点都会受到影响(力导向图有多种类型,本章绘制的效果就是这样,其他类型的读者可以自己去试试),还是给读者提个醒,这一章又会有很多新的知识点,请拿出的学习新东西的本领来

    为了绘制一个力导向图,我们还是需要以下新的知识点

  • d3.forceSimulation() ,新建一个力导向图,
  • d3.forceSimulation().force(),添加或者移除一个力,这里给出官方示例: 

    

    这里说明一下对于d3.forceSimulation().force(name),也就是当force中只有一个参数,这个参数是某个力的名称,那么这段代码返回的是某个具体的力,(根据上面图片官方对force的说明也可以知道),例如d3.forceSimulation().force(“link”),则返回的是d3.forceLink()这个力,注意对照上面的图片,这个用法在下面会经常被用到

 

  • d3.forceSimulation().nodes(),输入是一个数组,然后将这个输入的数组进行一定的数据转换,例如添加坐标什么的!这里给出官方API的解释

    从这里可以看出,差不多就是上面作者讲的那个意思

 

  • d3.forceLink.links(),这里输入的也是一个数组(边集),然后对输入的边集进行转换,等一下我们会看到,它到底被转换成什么样子的
  • tick函数,这个函数对于力导向图来说非常重要,因为力导向图是不断运动的,每一时刻都在发生更新,所以需要不断更新节点和连线的位置
  • d3.drag(),是力导向图可以被拖动

    好了,有了这些基础知识后,我们开始绘制一个力导向图

    1、数据准备

  1. var marge = {top:60,bottom:60,left:60,right:60}
  2. var svg = d3.select("svg")
  3. var width = svg.attr("width")
  4. var height = svg.attr("height")
  5. var g = svg.append("g")
  6. .attr("transform","translate("+marge.top+","+marge.left+")");
  7. //准备数据
  8. var nodes = [//节点集
  9. {name:"湖南邵阳"},
  10. {name:"山东莱州"},
  11. {name:"广东阳江"},
  12. {name:"山东枣庄"},
  13. {name:"泽"},
  14. {name:"恒"},
  15. {name:"鑫"},
  16. {name:"明山"},
  17. {name:"班长"}
  18. ];
  19. var edges = [//边集
  20. {source:0,target:4,relation:"籍贯",value:1.3},
  21. {source:4,target:5,relation:"舍友",value:1},
  22. {source:4,target:6,relation:"舍友",value:1},
  23. {source:4,target:7,relation:"舍友",value:1},
  24. {source:1,target:6,relation:"籍贯",value:2},
  25. {source:2,target:5,relation:"籍贯",value:0.9},
  26. {source:3,target:7,relation:"籍贯",value:1},
  27. {source:5,target:6,relation:"同学",value:1.6},
  28. {source:6,target:7,relation:"朋友",value:0.7},
  29. {source:6,target:8,relation:"职责",value:2}
  30. ];

    2、设置一个颜色比例尺

  1. //设置一个color的颜色比例尺,为了让不同的扇形呈现不同的颜色
  2. var colorScale = d3.scaleOrdinal()
  3. .domain(d3.range(nodes.length))
  4. .range(d3.schemeCategory10);

    3、新建一个力导向图

  1. var forceSimulation = d3.forceSimulation()
  2. .force("link",d3.forceLink())
  3. .force("charge",d3.forceManyBody())
  4. .force("center",d3.forceCenter());

    其实上面那一段代码你就可以从官网上面复制下来(我也是这么干的) 

   4、生成节点数据

  1. //生成节点数据
  2. forceSimulation.nodes(nodes)
  3. .on("tick",ticked);//这个函数很重要,后面给出具体实现和说明

    注意,这里出现了tick函数,我把它的实现写到了一个有名函数ticked(以前我们是不是写的都是无名函数)

    5、生成边集数据

  1. //生成边数据
  2. forceSimulation.force("link")
  3. .links(edges)
  4. .distance(function(d){//每一边的长度
  5. return d.value*100;
  6. })

    注意,这里出现了forceSimulation.force(name)的用法,前面已经详细解释了它的返回值

    6、设置图形中心位置

  1. //设置图形的中心位置
  2. forceSimulation.force("center")
  3. .x(width/2)
  4. .y(height/2);

    这里也是forceSimulation.force(name)的用法

    7、输出顶点集和边集

  1. //在浏览器的控制台输出
  2. console.log(nodes);
  3. console.log(edges);

    顶点集的样子

    

    边集的样子

    

    8、绘制边

  1. //绘制边
  2. var links = g.append("g")
  3. .selectAll("line")
  4. .data(edges)
  5. .enter()
  6. .append("line")
  7. .attr("stroke",function(d,i){
  8. return colorScale(i);
  9. })
  10. .attr("stroke-width",1);

    这里注意一下,应该先绘制边,在绘制顶点,因为在d3中,各元素是有层级关系的,先绘制的在下面

    9、边上的文字

  1. var linksText = g.append("g")
  2. .selectAll("text")
  3. .data(edges)
  4. .enter()
  5. .append("text")
  6. .text(function(d){
  7. return d.relation;
  8. })

    10、老规矩,先建立用来放在每个节点和对应文字的分组<g>

  1. var gs = g.selectAll(".circleText")
  2. .data(nodes)
  3. .enter()
  4. .append("g")
  5. .attr("transform",function(d,i){
  6. var cirX = d.x;
  7. var cirY = d.y;
  8. return "translate("+cirX+","+cirY+")";
  9. })
  10. .call(d3.drag()
  11. .on("start",started)
  12. .on("drag",dragged)
  13. .on("end",ended)
  14. );

    注意,这里出现了drag函数,对于call函数大家应该比较熟悉了!我们也可以发现,这里使用了三个有名函数,具体实现后面会给出

    11、节点和文字

  1. //绘制节点
  2. gs.append("circle")
  3. .attr("r",10)
  4. .attr("fill",function(d,i){
  5. return colorScale(i);
  6. })
  7. //文字
  8. gs.append("text")
  9. .attr("x",-10)
  10. .attr("y",-20)
  11. .attr("dy",10)
  12. .text(function(d){
  13. return d.name;
  14. })

    注意,这里的文字的到需要根据转换后数据的特点得到!!!

    12、ticked函数的实现

  1. function ticked(){
  2. links
  3. .attr("x1",function(d){return d.source.x;})
  4. .attr("y1",function(d){return d.source.y;})
  5. .attr("x2",function(d){return d.target.x;})
  6. .attr("y2",function(d){return d.target.y;});
  7. linksText
  8. .attr("x",function(d){
  9. return (d.source.x+d.target.x)/2;
  10. })
  11. .attr("y",function(d){
  12. return (d.source.y+d.target.y)/2;
  13. });
  14. gs
  15. .attr("transform",function(d) { return "translate(" + d.x + "," + d.y + ")"; });
  16. }

    注意,可以发现,这里写的都是位置信息,所以你在绘制相应的图形元素的时候,位置信息就不那么重要的,而且,建议先写完这个函数后,在进行测试

    13、drag

  1. function started(d){
  2. if(!d3.event.active){
  3. forceSimulation.alphaTarget(0.8).restart();设置衰减系数,对节点位置移动过程的模拟,数值越高移动越快,数值范围[0,1]
  4. }
  5. d.fx = d.x;
  6. d.fy = d.y;
  7. }
  8. function dragged(d){
  9. d.fx = d3.event.x;
  10. d.fy = d3.event.y;
  11. }
  12. function ended(d){
  13. if(!d3.event.active){
  14. forceSimulation.alphaTarget(0);
  15. }
  16. d.fx = null;
  17. d.fy = null;
  18. }

    drag中有三个函数,在这里进行了实现,其中d.fx和d.fy表示固定坐标,例如,现在我们看到dragged函数,我们可以发现这样的代码:d.fx = d3.event.x;  d.fy = d3.event.y;,也就是在拖动节点的时候,鼠标位置在哪里(d3.event),节点的固定位置就在哪里,再看到ended函数,也就是结束拖动的时候触发,可以发现,固定坐标都为空,也就是不固定,这样模拟的效果才好(你们也可以试试去掉ended函数会发生什么,这样可以更好的理解)

    最后,附上代码运行的结果

    

    效果还是很不错的!!是不是感觉过程很复杂!没关系,一步一步来,结果好就行

效果浏览:点击浏览效果

源码浏览:点击源码浏览

(效果浏览会出现乱码,请谅解!但是整体效果和上面的截图差不多,而且是动态的,可以鼠标拖拽!)

 

(翻外篇)d3.js在网页端可视化neo4j图数据库

    为了让大家更好的学习d3.js,“d3.js在网页端可视化neo4j图数据库”这是一个比较综合的项目——利用neo4j的java驱动API从neo4j中取数据,并利用d3.js在网页端进行可视化。大家在学完基础课程后可以做一下这个项目,进行巩固。点击下面链接进行查看:d3.js可视化neo4j图数据库项目专栏

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/132687
推荐阅读
  

闽ICP备14008679号