如何完全删除 d3 forceSimulation 及其拖动手柄
How to entirely remove a d3 forceSimulation and its drag handers
我想允许用户使用 d3 forceSimulation or a CoLa layout 查看他们的网络,这意味着当用户触发事件时,我需要更改哪些布局算法正在更新 x
和 y
我的节点和边的属性。
特别是,这要求我能够停止模拟并防止它们更新我给它们的数据的那些属性,而另一个是“活动的”——以及删除与它们关联的拖动处理程序.
我的渲染函数目前有:
if (use_cola) {
// MUST TURN OFF D3 AND ITS DRAG HANDLERS!
force = cola_force.nodes(graph.nodes)
.links(links)
.groups(groups[group_nodes_by])
.jaccardLinkLengths(repulsion_strength, 0.7)
.avoidOverlaps(true)
.start(50, 0, 50);
node.call(cola_force.drag);
group.call(cola_force.drag);
cola_force.on('tick', ticked);
} else { // d3
// MUST TURN OFF COLA AND ITS DRAG HANDLERS!
force = d3_force.nodes(graph.nodes)
.force("link", d3.forceLink(links))
.force("charge", d3.forceManyBody().strength(-repulsion_strength))
.force("center", d3.forceCenter(w / 2, h / 2));
node.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended)); // where those are the conventional functions
d3_force.on('tick', ticked);
}
一个解决方案可能是破坏这些对象,例如delete d3_force['something_important']
更简单的方法可能会起作用,例如 d3_force.nodes([])
或类似的东西。
我不确定如何做类似于拖动处理程序的事情,因为我不太熟悉它们的工作原理。
更新 1:
为 d3 拖动处理程序(在 d3v3 中)建议的部分解决方案 here:
var dragCallback = d3.select('rect#no-drag').property('__onmousedown.drag')['_'];
d3.select('rect#no-drag').on('mousedown.drag', null);
稍后恢复:
d3.selectAll('rect#no-drag').on('mousedown.drag', dragCallback);
你需要做两件事:
如果它仍然存在,请停止模拟 运行 防止它弄乱您的节点坐标。这可以通过调用 d3_force.stop()
轻松完成。不过,无需首先检查它是否 运行,因为在已经停止的模拟上调用它也不会造成任何伤害。
您稍后可以通过调用 d3_force.restart()
重新激活模拟,可能会抽回一些能量来加热它:d3_force.alpha(1).restart()
.
docs 告诉我们如何摆脱拖动行为:
The listeners use the name .drag
, so you can subsequently unbind the drag behavior as follows:
selection.on(".drag", null);
在你的情况下,这将是 node.on(".drag", null)
。如果用户切换回布局,您可以再次将拖动行为绑定到 node
选择。为此,可能值得考虑预先创建拖动行为,并在稍后重新绑定时传递引用。
我想允许用户使用 d3 forceSimulation or a CoLa layout 查看他们的网络,这意味着当用户触发事件时,我需要更改哪些布局算法正在更新 x
和 y
我的节点和边的属性。
特别是,这要求我能够停止模拟并防止它们更新我给它们的数据的那些属性,而另一个是“活动的”——以及删除与它们关联的拖动处理程序.
我的渲染函数目前有:
if (use_cola) {
// MUST TURN OFF D3 AND ITS DRAG HANDLERS!
force = cola_force.nodes(graph.nodes)
.links(links)
.groups(groups[group_nodes_by])
.jaccardLinkLengths(repulsion_strength, 0.7)
.avoidOverlaps(true)
.start(50, 0, 50);
node.call(cola_force.drag);
group.call(cola_force.drag);
cola_force.on('tick', ticked);
} else { // d3
// MUST TURN OFF COLA AND ITS DRAG HANDLERS!
force = d3_force.nodes(graph.nodes)
.force("link", d3.forceLink(links))
.force("charge", d3.forceManyBody().strength(-repulsion_strength))
.force("center", d3.forceCenter(w / 2, h / 2));
node.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended)); // where those are the conventional functions
d3_force.on('tick', ticked);
}
一个解决方案可能是破坏这些对象,例如delete d3_force['something_important']
更简单的方法可能会起作用,例如 d3_force.nodes([])
或类似的东西。
我不确定如何做类似于拖动处理程序的事情,因为我不太熟悉它们的工作原理。
更新 1:
为 d3 拖动处理程序(在 d3v3 中)建议的部分解决方案 here:
var dragCallback = d3.select('rect#no-drag').property('__onmousedown.drag')['_'];
d3.select('rect#no-drag').on('mousedown.drag', null);
稍后恢复:
d3.selectAll('rect#no-drag').on('mousedown.drag', dragCallback);
你需要做两件事:
如果它仍然存在,请停止模拟 运行 防止它弄乱您的节点坐标。这可以通过调用
d3_force.stop()
轻松完成。不过,无需首先检查它是否 运行,因为在已经停止的模拟上调用它也不会造成任何伤害。您稍后可以通过调用
d3_force.restart()
重新激活模拟,可能会抽回一些能量来加热它:d3_force.alpha(1).restart()
.docs 告诉我们如何摆脱拖动行为:
The listeners use the name
.drag
, so you can subsequently unbind the drag behavior as follows:selection.on(".drag", null);
在你的情况下,这将是
node.on(".drag", null)
。如果用户切换回布局,您可以再次将拖动行为绑定到node
选择。为此,可能值得考虑预先创建拖动行为,并在稍后重新绑定时传递引用。