【问题标题】:How to stop a d3 force graph layout simulation?如何停止 d3 力图布局模拟?
【发布时间】:2013-04-13 06:55:59
【问题描述】:

一旦你 d3.layout.force()..start() 在 D3 中进行强制布局模拟,它也会继续进行活动事件。

我想设置 5 秒的超时时间,让图形强制布局模拟成形并停止(调用 .stop() 或 alpha(0)。这可以停止,但只要我拖动一个节点,模拟又开始了。

以下代码(也可从jsfiddle 轻松测试)在最后一行显示将发出 stop() 并且模拟立即停止,但是只要您拖动任何节点,模拟就会重新开始。我认为这是在强制拖动中硬编码的。有没有办法禁用/取消注册?

var svgContainer = d3.select("#svgContainer");

var element0a = svgContainer.append("g").attr("class","node").attr("transform","translate(100,100)");
var element0b = element0a.append("rect").attr("x",0).attr("y",0).attr("width",20).attr("height",10).attr("fill","red");

var element1a = svgContainer.append("g").attr("class","node").attr("transform","translate(100,200)");
var element1b = element1a.append("rect").attr("x",0).attr("y",0).attr("width",20).attr("height",10).attr("fill","green");

var element2a = svgContainer.append("g").attr("class","node").attr("transform","translate(100,300)");
var element2b = element2a.append("rect").attr("x",0).attr("y",0).attr("width",20).attr("height",10).attr("fill","blue");

var nodeArray = new Array();
nodeArray[0] = { id : "000", label : "label 000", ui : element0a };
nodeArray[1] = { id : "001", label : "label 001", ui : element1a };
nodeArray[2] = { id : "002", label : "label 002", ui : element2a };

var linkArray = new Array();

var force = self.force = d3.layout.force()
    .nodes(nodeArray)
    .links(linkArray)
    .gravity(.05)
    .distance(80)
    .charge(-100)
    .size([600, 600])
    .start();

var node = svgContainer.selectAll("g.node")
    .data(nodeArray)
    .call(force.drag);


force.on("tick", function() {
      node.attr("transform", function(d) {return "translate(" + d.x + "," + d.y + ")";});
    });

// HERE !!!! Without the stop() the simulation goes fine. With the stop() the simulation will immediately stop, but will continue as soon as you drap something. I want the simulation to never start again. 

force.stop();

这是示例的截图:

【问题讨论】:

  • 当拖动事件发生时,听起来您正在重新启动模拟。检查你在哪里打电话.start()
  • 我实际上在开始时只调用了一次 start()。我添加了一个带有可测试场景的 jsfiddle。检查最后一行:jsfiddle.net/guidoextras/trzfw

标签: d3.js force-layout


【解决方案1】:

在内部拖动节点时调用的函数中重新启动模拟。但是,您可以覆盖此行为。事件名称为“drag.force”,您可以通过force.drag 访问它。除了通常的行为,您可以直接修改坐标而无需像这样重新启动模拟:

var node...
  .call(force.drag().on("drag.force", function() {
    d3.select(this).attr("transform", "translate(" + d3.event.x + "," + d3.event.y + ")");
  }));

这对应于正常的拖动行为。在执行此操作之前,建议停止模拟以防止拖动事件和强制刻度干扰。只需在修改后的事件处理程序的开头调用 force.stop()

最后,您需要重置拖动事件的原点,否则当您再次拖动它们时,您会注意到被拖动元素“跳”回其原始位置。这以与修改事件处理程序类似的方式完成。您只需获取当前翻译并以预期格式返回坐标。

var node...
  .call(force.drag().origin(function() {
    var t = d3.transform(d3.select(this).attr("transform")).translate;
    return {x: t[0], y: t[1]};
  }));

完整代码在更新的jsfiddlehere中。

【讨论】:

    【解决方案2】:

    设置一个适当的“摩擦”应该可以做到,尽管你无法控制它需要停止的时间:

    var force = self.force = d3.layout.force()
      .nodes(nodeArray)
      .links(linkArray)
      .gravity(.05)
      .distance(80)
      .charge(-100)
      .friction(0.5)
      .size([600, 600])
      .start();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-06-13
      • 2014-02-27
      • 1970-01-01
      • 2013-07-14
      • 1970-01-01
      • 1970-01-01
      • 2016-12-02
      • 1970-01-01
      相关资源
      最近更新 更多