使用强制定向布局理解D3.js中的"调用"

Jer*_*Kun 2 javascript drag d3.js 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();} 
     } 
   });
Run Code Online (Sandbox Code Playgroud)

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

即这段链接代码:

var node = svg.selectAll(".node")
     .data(graph.nodes)
   .enter().append("circle")
     ...
     .call(force.drag);
Run Code Online (Sandbox Code Playgroud)

我想我可能要做两件事:

  1. 编写自定义"拖动"方法,移动节点和与单个节点关联的边.
  2. 根据需要将节点的调用方法重新绑定(这是否有意义?是否会替换绑定的方法?force.drag实际上做了什么?).

我想知道以前是否已经完成这项工作,以及如何做到(根本不会使用我的猜测,如何做到这一点).

Ame*_*aBR 6

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

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

node.call( force.drag );
Run Code Online (Sandbox Code Playgroud)

实际上和做的一样

force.drag( node );
Run Code Online (Sandbox Code Playgroud)

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

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

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

至于能够自定义拖动行为以便它不会重新启动强制布局,它看起来就像你可以做到这一点force.drag(无论如何都不能更改源代码). 但是,您可以通过创建自己的拖动行为对象并将其绑定到节点来访问大多数与拖动相关的功能.

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

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