【问题标题】:D3 Force Layout - Text Wrapping and Node OverlapsD3 强制布局 - 文本换行和节点重叠
【发布时间】:2016-06-29 20:27:13
【问题描述】:

这是我的第一个堆栈溢出问题,所以如果我犯了一些新手错误,请多多包涵。我在这里搜索了很多问题,并没有找到我正在寻找的确切内容(在一种情况下我有,但不知道如何实现它)。似乎只有问过类似问题的人没有得到任何答案。

我已经使用 D3 创建了一个强制布局,并且事情几乎按照我希望的方式工作。我无法编辑的两件事:

1) 防止节点重叠:是的,我已经阅读并重新阅读了 Mike Bostock 的集群力布局代码。我不知道如何在我的代码中实现它而不会出现严重错误!我从教程中尝试了这段代码,但它把我的节点固定在一个角落里,并在画布上展开了链接:

var padding = 1, // separation between circles
  radius=8;
function collide(alpha) {
var quadtree = d3.geom.quadtree(graph.nodes);
   return function(d) {
var rb = 2*radius + padding,
    nx1 = d.x - rb,
    nx2 = d.x + rb,
    ny1 = d.y - rb,
    ny2 = d.y + rb;
quadtree.visit(function(quad, x1, y1, x2, y2) {
  if (quad.point && (quad.point !== d)) {
    var x = d.x - quad.point.x,
        y = d.y - quad.point.y,
        l = Math.sqrt(x * x + y * y);
      if (l < rb) {
      l = (l - rb) / l * alpha;
      d.x -= x *= l;
      d.y -= y *= l;
      quad.point.x += x;
      quad.point.y += y;
    }
  }
  return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
});
};
}

您可以在我的 fiddle(下面链接)中看到对 tick 函数的添加被注释掉了。

2) 包装我的文本标签,使其适合节点。现在它们通过悬停扩展为节点的全名,但我最终会将其更改为工具提示(一旦我解决了这些问题,我会找出一个工具提示) - 现在我只想要原始的短名称包裹在节点内。我查看了this answerthis answer (http://jsfiddle.net/Tmj7g/4/),但是当我尝试将其实现到我自己的代码中时,它没有响应或最终聚集了左上角的所有节点(??)。

非常感谢任何和所有输入,请随时在此处编辑我的小提琴:https://jsfiddle.net/lilyelle/496c2bmr/

我也知道我的所有语言都不是完全一致的,也不是编写 D3 代码的最简单方法 - 那是因为我已经从不同来源复制并拼接了很多东西,并且仍在尝试找出最好的方法为自己写这些东西。在这方面的任何建议也值得赞赏。

【问题讨论】:

    标签: javascript d3.js force-layout


    【解决方案1】:

    1) 碰撞检测:这是一个更新后的工作 jsFiddle,它由来自 mbostock 的 this example 指导。添加碰撞检测主要是对重要位的复制/粘贴。具体来说,在tick 函数中,我添加了循环遍历所有这些节点并在它们发生碰撞时调整它们的位置的代码:

    var q = d3.geom.quadtree(nodes),
        i = 0,
        n = nodes.length;
    
    while (++i < n) q.visit(collide(nodes[i]));
    

    由于您的 jsFiddle 没有设置变量 nodes,因此我将其添加到最后一个片段的正上方:

    var nodes = force.nodes()
    

    此外,该循环需要定义函数 collide,就像在 Bostock 的示例中一样,所以我也将它添加到您的 jsFiddle 中:

    function collide(node) {
      var r = node.radius + 16,
          nx1 = node.x - r,
          nx2 = node.x + r,
          ny1 = node.y - r,
          ny2 = node.y + r;
      return function(quad, x1, y1, x2, y2) {
        if (quad.point && (quad.point !== node)) {
          var x = node.x - quad.point.x,
              y = node.y - quad.point.y,
              l = Math.sqrt(x * x + y * y),
              r = node.radius + quad.point.radius;
          if (l < r) {
            l = (l - r) / l * .5;
            node.x -= x *= l;
            node.y -= y *= l;
            quad.point.x += x;
            quad.point.y += y;
          }
        }
        return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
      };
    }
    

    最后必要的一点来自于检测节点冲突需要知道它们的大小这一事实。 Bostock 的代码在上面的collide 函数中访问node.radius。你的例子没有设置节点的半径,所以collide函数node.radiusundefined。设置此半径的一种方法是将其添加到您的 json 中,例如

    {radius: 30, "name":"AATF", "full_name":"African Agricultural Technology Foundation", "type":1}
    

    如果所有节点都具有相同的半径,那就太过分了。

    另一种方法是将出现的 2 次 node.radius 替换为硬编码数字,例如 30

    我选择在这两个选项之间做一些事情:通过循环加载的 json 为每个节点分配一个常量 node.radius

    json.nodes.forEach(function(node) {
        node.radius = 30;
    })
    

    这就是让碰撞检测工作的原因。我使用了30 的半径,因为这是您用于渲染这些节点的半径,如.attr("r", 30)。这将使所有节点聚集在一起——不重叠但仍然相互接触。您可以尝试为node.radius 设置更大的值,以在它们之间留出一些空白。

    2) 文字换行:这是一个很难的。没有简单的方法可以使 SVG &lt;text&gt; 以某种宽度换行。只有常规的 html div/span 可以自动执行此操作,但即使是 html 元素也无法换行以适应圆形,只能换行到恒定宽度。

    您可能会想出一些折衷方案,让您始终适合某些文本。例如,如果您的数据都是提前知道的,并且圆圈的大小始终是相同的固定值,那么您可以提前知道哪些标签可以适合,哪些不适合。那些没有的,您可以缩短,通过在 JSON 中的每个节点上添加一个 short_name 属性,并将其设置为绝对适合的值。或者,如果预先知道大小和标签,您可以预先确定如何将标签分成多行并将其硬编码到 JSON 中。然后,在渲染时,您可以使用多个 SVG &lt;text&gt; 元素来渲染该文本,您手动将这些元素定位为多行。最后,如果事先一无所知,那么您可以通过切换到将文本呈现为绝对定位的 div 在 SVG 顶部(和外部)的宽度来获得一个好的解决方案,其宽度与圆圈的宽度相匹配,以便文本自动换行。

    【讨论】:

    • 哦。我的。善良。感谢您的精彩回答和解释!现在更有意义了。我明白你对文本换行的意思 - 我认为我只需要手动调整它,现在碰撞检测工作将是一项更容易的任务。
    • @lilyelle,太棒了——乐于助人!一件事:如果我的回答解决了你的问题,那么请点击检查图标“接受”它。 StackOverflow 在积分上运行,通过您接受我的回答,我得到了积分:)
    猜你喜欢
    • 1970-01-01
    • 2016-08-15
    • 1970-01-01
    • 2013-12-18
    • 2015-05-23
    • 1970-01-01
    • 1970-01-01
    • 2014-10-18
    • 1970-01-01
    相关资源
    最近更新 更多