【 D3.js 进阶系列 — 2.0 】 力学图 + 人物关系图

力学图(力导向图)与生活中常见的人物关系图结合,是比较有趣的。本文将以此为凭,阐述在力学图中如何插入外部图片和文字。

result1

在【第 9.2 章】中制作了一个最简单的力学图。其后有很多朋友有疑问,主要的问题包括:

  • 如何在小球旁插入文字
  • 如何将小球换为别的图形
  • 如何插入图片
  • 如何限制小球运动的边界

本文将对以上问题依次做出解说。其中前三点是 SVG 元素的问题,和 D3 无多大关联。

1. SVG 图片

SVG 的图片元素的详细解说可看【官方文档-图片】。通常,我们只需要使用到图片元素的五个属性就够了。

其中:

  • xlink:href – 图片名称或图片网址
  • x – 图片坐上角 x 坐标
  • y – 图片坐上角 y 坐标
  • width – 图片宽度
  • height- 图片高度

在 D3 中插入图片,代码形如:

2. SVG 文本

SVG 的文本元素和图片类似,详细属性见【官方文档-文本】。

其中:

  • x – 文本 x 坐标
  • y – 文本 y 坐标
  • dx- x 轴方向的文本平移量
  • dy- y 轴方向的文本平移量
  • font-family – 字体
  • font-size – 字体大小
  • fill – 字体颜色

在 D3 中插入文本,代码形如:

 

3. 源文件

接下来制作力学图的源文件,本次将数据写入 JSON 文件中。
呵呵,借用一下【仙剑4】的人物,本人也是个仙剑迷,期待15年7月【仙剑6】的上市。

如上,在 JSON 文件中添加数据,再将图片文件与 JSON 文件放于同一目录下即可(放哪都行,最主要是看程序中是如何实现的)。

4. 力学图

4.1 读入文件

读入 JSON 文件,这点应该很熟了吧。不然可以先看看【第 9.4 章】。

4.2 定义力学图的布局

力学图的 Layout(布局)如下:

其中 linkDistance 是结点间的距离, charge 是定义结点间是吸引(值为正)还是互斥(值为负),值越大力越强。

4.3 绘制连接线

绘制结点之间的连接线的代码如下:

其中,
第 1 – 6 行:绘制直线
第 8 – 15 行:绘制直线上的文字
直线上文字的样式为:

fill-opacity 是透明度,0表示完全透明,1表示完全不透明。这里是0,表示初始状态下不显示。

4.4 绘制结点

绘制结点的图片和文字:

第 1 – 26 行:绘制图片
第 10 – 25 行:当鼠标移到图片上时,显示与此结点想关联的连接线上的文字。使用改变透明度的方式。
第 28 – 40 行:绘制图片下方的文字

4.5 更新

设定力学图更新时调用的函数,使用 force.on(“tick”,function(){ }),表示每一步更新都调用 function 函数。

 

5. 结果

结果如下,拖动试试吧:

可点击下面的地址,右键点浏览器查看完整代码:
http://www.ourd3js.com/demo/J-2.0/relationforce.html

源代码和图片打包下载:j20.zip

6. 结束语

在【入门系列】中,疑问最多的是【树状图】,本想先解决这个问题的,但是由于我也有些问题还没想明白,所以先写本文这个较容易的。接下来还将有几篇关于力学图的,树状图的整理要稍微拖一段时间。

谢谢阅读


文档信息


【 D3.js 进阶系列 — 2.0 】 力学图 + 人物关系图》上有54条评论

  1. 老师,麻烦把数据和图片发给我下,邮箱936145215@qq.com

      • 能不能麻烦把数据和图片和发我一遍,谢谢。
        邮箱是:448204015@qq.com
        顺便想请教一下,能不能两个人物之间有两条线,一条代表a对b的情况,一条是b对a的情况。

  2. 老师,能否把这篇文章用到的数据和图片发我

  3. 老师,如何将两个节点之间 连线设置一个箭头呢?就是从源指向目的,谢谢!

    • 参考这一篇文章,或许可以帮到你。
      http://www.ourd3js.com/wordpress/660
      但是,由于本文的图片是方形的,如果直接绘制箭头,箭头会在图片的背面,就看不到了。你需要计算出线段在图片之外的位置,或者把图片变成圆形。

      • 好的,谢谢老师,现在已经实现了,现在问题就是图片挡住了箭头,我通过设置refX,refY通过偏移实现了部分正常显示,但移动图形还是会改变。老师那里有写过计算位置的代码吗?我编写了,但是marker读不到source与target的坐标信息

      • //更新箭头坐标
        arrowMarker.attr(“refX”,function(d){
        var vay1=Math.sqrt(Math.pow((x2-x1),2)+Math.pow((y2-y1),2));
        var vay2=y2-y1;
        if(vay2==0)
        {
        return rect_h/2;
        else{
        return (vay1*rect_h/2)/vay2;
        }
        })
        arrowMarker.attr(“refy”,6);

        • 你误会我的意思了,这个箭头的标记,一旦定义之后是不需要更改的,没必要手动计算 refX 之类的。
          我所指的是修改线段的两个端点的坐标,即 line 的 x1, y1, x2, y2,使得该坐标位于矩形的边界。但是不是那么容易计算的,如果是圆形的图片就很容易。
          这个地方不好解释,我手里也没有符合你要求的代码。

  4. 请问一下:
    设置节点的位置时,能否对于每一层节点设置在不同位置,比如说第一层节点 我设置在页面的左边,第二层设置在中间,第三层设置在右边。

    • 我没有试过,不知道效果如何,但我想是可以的。
      只是通过限制节点的运动外围即可。

      • 请教一下,力导向图添加call事件监听后,怎么就不执行单击双击事件了呢。

  5. 请教一下,我想把图片做成圆角该怎么做

  6. 老师您好,我做了一个可视化数据可以随时间变化的, 但是每一次都会从新start一次相当于每次都从头来过,这样就不容易看出怎么随时间变化的,请问怎么能在变化数据后不让它再剧烈的来过一次?

    • 数据是随时间变化的吗?
      不知道是怎么的数据,怎么变化的?

      比如是原来是 A-B,B-C
      现在变成了 A-C,A-B,了吗

  7. 请问为什么edges_text.style(“fill-opacity”,function(edge)函数里是edge不是edges呢?我试了试变成edges,好像会有错。。

    • function(edge)
      的 edge 仅仅是一个参数,如果更改了,函数体内的此参数名也要更改。

  8. 老师,我用D3.js读取json文件的时候老是读取不出来,apache配置好了,我将json文件放在apache下的htdocs文件夹里面。然后复制你的代码,发现跑不出结果。个人觉得是路径的问题。但是又找不到原因

  9. 老师我想实现的是单击图片后出现人物的姓名之类的不是直接的显示出来,应该怎么修改

    • 将人物名称的文字元素(nodes_text)的属性fill-opacity设置为0(初始值),即:
      nodes_text.style(“fill-opacity”, 0.0 )。
      再在人物图片的 nodes_img 中添加一个新的事件 click,监听器里将文字的透明度设置为1.0即可:
      nodes_img.on(“click”,function(d,i){
      nodes_text.style(“fill-opacity”, 1.0 )。
      });
      如此,单击图片后文字才会出现。

  10. D3用在大数据可视化的话需要用到数据库,苦于不知道怎么通过数据库操作json,还请指点。说道:

    D3用在大数据可视化的话需要用到数据库,苦于不知道怎么通过数据库操作json,还请指点。

    • 这是我的想法,你看这样行不?

      数据库里只存json的文件名或地址,当要使用的时候,从数据库里获取到json文件的地址,再通过 d3.json 调用。

  11. 想请教一下老师,怎么才能一直显示这个关系呢?还有关系的显示沿着连接线,而不是水平显示。

  12. 我的效果是静态的,卡了,图片这块处理的不对,怎么弄啊

  13. 确实还有个问题,关系图静下来,显示的关系就停了

  14. 非常棒,给个建议哦,如果我拖动节点后,能让它拖到那儿定到哪,如果不合适双击解除锁定效果,这样是不是更好。
    这样的话我就可以自己排布他的展示效果,比如同组的我拉到一片区域,不要互相影响 而不是杂乱的拥簇到一起出现图遮挡图的情况

    这个官网demo有例子,可以借鉴下

  15. 节点属性:大小
    渲染方式:a. 标签渲染(可对提供链接或指定的节点增加图片或头像),边框颜色,标签颜色,设置标签长度
    b. 几何图形渲染(triangle, square, diamond…)
    颜色
    修改节点名称

    边属性: 权值区别粗细
    颜色
    边向性(有向无向)
    边标签
    修改边标签
    多边(任意两节点间可能有多边,代表两节点间不同关系)
    可修改边指向,由A->B改为AB的边,可将这条边拖拽成A->C

    d. 删除节点:删除当前选中节点(可通过鼠标右键或键盘delete键删除),在删除该节点时应删除该节点关联的边。

    e. 删除边:删除边时应仅删除该边,不删除该边关联的点(因为丢失的仅为关系,两节点实体依然存在)

    以上这些是实际应用中非常需要的一些功能,请问作者考虑这些功能实现在D3里难吗?
    我的联系方式QQ: 1820551097

    • 我认为并不困难,请问您是需要我回答怎么实现吗,还是只是想了解困难与否。

  16. 老师你好,我将代码复制进工程里发布的时候,查看源代码发现注释乱码,是什么原因呢?
    force.on(“tick”, function(){
    //限制结点的边界
    root.nodes.forEach(function(d,i){

      • 有点小问题就是图片飘动一会就变成静态了,鼠标放上去不显示关系,给人一种卡了的感觉,要重新拖动。

          • D3用在大数据可视化的话需要用到数据库,苦于不知道怎么通过数据库操作json,还请指点。

        • 从数据库读取的话,我认为用 PHP 或 JSP 等直接从数据库读取即可,无需用到 JSON 文件

          • 我现在开始用到数据库来动态生成关系了,请问老师我需要建怎样的表格呢?我想建两张一张有名字和图片路径,一张是名字1名字2关系不知道这样可不可以呢?

        • 用怎么的表格无所谓,只要读取数据的时候遵循上述规则赋予变量即可

  17. var edges_text = svg.selectAll(“.linetext”)
    老师,上面这行代码中selectAll中的参数是”.linetext”,我有些不明白;
    我记得selectAll 是选择所指定的所有的元素,这个地方是选择了”.linetext”这个样式吗?可以不选择text这个元素,而选择它对应的样式吗?

    • 其实在这里输入什么都行,因为这个时候还没有这个元素,表示的是选择一个空集,需要的元素在后面的append插入。在这里只是为了方便代码阅读,才输入这个。
      但如果是真正为了选择某个元素,就要输入正确的名称。

      • 哇~ 明白了~ 老师解释得很详细呦~ 能有中文学习d3的资料,感动中….. 希望老师继续更新文章,从老师的文章中我学到很多~ 谢谢老师~

评论已关闭。