理解"电话"在D3.js中使用强制定向布局

时间:2014-04-04 19:14:39

标签: javascript d3.js drag force-layout

我是D3.js的新手,我想使用图形布局。我有这个演示设置了一个非常简单的图形,遵循D3中内置的力导向布局。

http://jsfiddle.net/ewG95/

我想要做的是能够关闭图形布局算法(例如,当用户按下空格时)然后仍然能够拖动节点并转动力导向布局重新开始。

现在我已将其设置为在击中空间时停止力导向布局:

d3.select("body")
   .on("keydown", function() { 
     if (d3.event.keyCode == 32) { 
        if (forceActive) {force.stop();} else {force.resume();} 
     } 
   });

问题是每次拖动节点时都会重新启动强制布局。我已经将它缩小到(基本上)节点上的调用方法被绑定到强制布局的拖动方法。

即。这段链接代码:

var node = svg.selectAll(".node")
     .data(graph.nodes)
   .enter().append("circle")
     ...
     .call(force.drag);

我想我可能要做两件事:

  1. 编写一个自定义“拖动”方法,用于移动节点和与单个节点关联的边。
  2. 根据需要将节点的调用方法重新绑定(这是否有意义?是否会替换绑定的方法?force.drag实际上做了什么?)。
  3. 我想知道之前是否已完成此操作,以及如何操作(根本不会使用我猜测如何操作)。

1 个答案:

答案 0 :(得分:6)

首先,关于您的明确问题:call()方法有什么作用?

在d3中,call只是一个方便的功能,可以将其他功能彻底改变。做

node.call( force.drag );

实际上和做

一样
force.drag( node );

唯一的区别是选择中的call方法总是返回选择,因此您可以将其他方法链接到它。

所以现在你的问题是,force.drag( selection )做了什么?它创建了用于处理拖动行为的鼠标和触摸事件的事件侦听器。这些事件侦听器更新节点数据对象的位置,但它们也会重新启动强制布局。

如果您不想使用默认的强制布局拖动行为,请不要在选择中调用force.drag方法。

只要能够自定义拖动行为以使其不重新启动强制布局,看起来就不能用force.drag执行此操作(无论如何都不能更改源代码) 。 但是,您可以通过创建自己的drag behaviour object并将其绑定到节点来访问大多数与拖动相关的功能。

然后,在您的拖动事件处理程序中,您将更新节点数据对象的x和y位置,并重绘节点以及连接到它的任何链接。如果你的图表不是太大,你可以通过重新调用tick函数来重绘所有元素以匹配他们的数据;如果您的图表 大,您可能希望存储对数据对象中实际元素的引用,以便您可以快速找到正确的链接。

使用拖动行为(没有强制布局)的一些示例可以帮助您入门: