0

我正在研究 D3 网络可视化并尝试调整布局。节点代表大学课程,边连接先决条件(例如,如果课程 A 是课程 B 的先决条件,则存在从 A 到 B 的有向边)。还有代表“AND”和“OR”的小节点...例如,如果您需要课程 A 或课程 B 来完成课程 C,则将有从 A 和 B 指向“OR”节点的边,以及从“OR”节点到 C 的边。这些网络是根据用户选择的课程集动态生成的,因此节点的数量可以从少数几个到几百个不等。

课程节点可以按年份(1、2、3 或 4)分类。现在我将 SVG 分成四个水平带,在我的tick()函数中,我检查每个节点是否在正确的带中,如果不是,则将其推向正确的方向。这种方法可以保持从上到下的“流动”,但节点经常会卡在其他节点后面,永远无法到达正确的位置。

我也不希望节点在最终网络中重叠,所以我使用碰撞检测来始终保持它们之间的一些空间。

这些有所帮助,但我仍然对我得到的布局不太满意。根据数据的性质,边缘应始终指向侧面或向下,但不能向上(即,第一年或第二年课程可以成为第二年课程的先决条件,但第三年课程不能)。它不是真正的树,但它有一些方向。有没有办法实现这个约束?我尝试了力导向的树方法,但是即使增加常数,约束也不够强 - 它只是轻轻地朝正确的方向轻推,但是如果节点因为其他一些力而“卡住”,那么它们停止。我觉得如果我让箭头方向成为“最强”的约束(比电荷排斥、重力等更强),那么节点会更好地组织自己。

这是我第一次使用 D3,并且已经做了很多事情(D3 力布局的内置参数、按年组织和碰撞检测),因此非常感谢任何输入!

编辑:

我尝试在tick处理边缘的函数部分添加它:

if (d.target.y < d.source.y) {
    var avgY = (d.target.y + d.source.y)/2;
    d.target.y = avgY;
    d.source.y = avgY;
}

我的想法是,如果目标高于源,我可以强迫他们两个在中间相遇。这有点工作,但是在碰撞检测与它冲突的地方有点错误 - 当两个节点发生碰撞时,它们应该分开,但如果它们之间的边缘指向上方,它们可能会被推到一起。这导致一些节点奇怪地弹跳。它还使某些箭头末端不附加到节点上。对于如何解决这个问题,有任何的建议吗?

编辑#2:

我仍在使用我在上次编辑中添加的代码,但我已经删除了按年份将节点分成层的代码。我还将它添加到我的“碰撞”函数中以进行碰撞检测,并将 alpha 值传递给它:

// Minimum required distance between the two nodes' centers
if (alpha > 0) {
      r = node.radius + quad.point.radius - (alpha*100);
} else {
      r = node.radius + quad.point.radius;
}

这使得碰撞检测约束在布局末尾附近更强。这很好,因为它可以防止节点在到达漂亮布局的过程中“卡住”,而且我不在乎它们在移动时是否重叠,只要它们在最终布局中重叠。我对这给我的布局感到相当满意,它似乎已经解决了大部分“颠簸”。但是,如果有人有其他想法,请分享!

4

0 回答 0