避免 D3 强制布局中节点和边之间的碰撞

Posted

技术标签:

【中文标题】避免 D3 强制布局中节点和边之间的碰撞【英文标题】:Avoid collision between nodes and edges in D3 force layout 【发布时间】:2013-07-29 01:06:38 【问题描述】:

在本例中:http://bl.ocks.org/mbostock/1747543:

...Mike 向我们展示了如何避免节点之间的冲突,以使两个节点不会相互重叠。

我想知道是否有可能避免节点和边之间的冲突,以便没有节点“剪辑”或重叠边,除非它被该边连接。

以下使用 D3 force-direct 的示例显示节点 L 与连接 IA 的边重叠,类似地,节点 M 与连接 LD 的边重叠。我们如何防止此类情况发生?

【问题讨论】:

这对于 D3 中的强制布局实现是不可能的。你需要自己实现这个。请注意,这实际上是一个非常困难的问题(计算上),因此即使您有一个实现,它也可能不想在浏览器中运行它。 @LarsKotthoff,你是说,一般来说,没有已知的图形布局算法(包括为 D3 实现的算法)可以有效地解决这个问题? 这取决于你对高效的定义。找到一个(静态)解决方案对我来说听起来至少是 NP-hard。这并不意味着它可以在特定情况下快速解决,但这通常是困难的(对于大型图表,您可能无法快速解决)。然后更改初始解决方案以使节点稍微移动(就像模拟那样)将非常容易,因为您只需要进行本地修复。 这不是一个难题。除了节点之外,只需向边缘添加力即可。如果可能的话,简单地增加图表的大小会有很大帮助。 @tba,你对边缘施加力到底是什么意思?增加图表大小不是很灵活,因为可用于显示图表的区域可能会受到应用程序的限制。 【参考方案1】:

如果您的图表没有太多节点,您可以伪造它。只需为每个链接插入一个或多个节点,并在tick 处理程序中沿链接设置它们的位置。以http://bl.ocks.org/couchand/7190660 为例,但对 Mike Bostock 版本的更改基本上只是:

var linkNodes = [];

graph.links.forEach(function(link) 
  linkNodes.push(
    source: graph.nodes[link.source],
    target: graph.nodes[link.target]
  );
);

// force.on('tick', function() 
linkNodes.forEach(function(node) 
  node.x = (node.source.x + node.target.x) * 0.5;
  node.y = (node.source.y + node.target.y) * 0.5;
);

如果您有很多节点和边,这将引入相当严重的性能开销,但如果您的图表没有比您的示例大很多,则几乎不会被注意到。

您可能还想调整真实节点与链接节点的相对力。

再往前走一步,你会得到http://bl.ocks.org/mbostock/4600693的漂亮弯曲链接。

【讨论】:

以上是关于避免 D3 强制布局中节点和边之间的碰撞的主要内容,如果未能解决你的问题,请参考以下文章

d3强制定向布局中的神秘力量?

修复 D3 强制定向布局中的节点位置

D3js:自动放置标签以避免重叠? (强制排斥)

D3 强制布局 - 按名称而不是索引链接节点

D3强制布局:如何设置每个节点的大小?

d3js 在地图上强制布局