【问题标题】:d3 force-directed layout expands on reheatd3 力导向布局在再热时扩展
【发布时间】:2015-11-26 03:33:36
【问题描述】:

考虑任何 d3 力导向动画,例如:

http://bl.ocks.org/mbostock/1062288

加载该图并让节点稳定下来,这样它们就不会移动。将鼠标悬停在橙色节点上,让鼠标静止。单击并不执行任何其他操作。您会看到所有节点向内移动一点,然后又恢复正常。

我不喜欢这种不必要的动作,我需要删除它。

我相信这与“重新加热”的图表有关(请参阅https://github.com/mbostock/d3/wiki/Force-Layout ),它将 alpha 参数设置为 0.1。具体来说,我看到在以下任何一项之后立即发生了不必要的移动。

  1. 一个新节点被添加到图表中
  2. 从图中删除一个节点
  3. force.drag() 被调用。

究竟是什么导致了这种“不必要的移动”,我该如何禁用它? (不禁用节点拖动)

【问题讨论】:

  • d3.js static force layout的可能重复
  • 强制布局是为了重新计算节点位置而进行的。如果您真的想要它,您可以将节点设置到特定位置。或者大约 3 秒后,您将节点设置为固定。这取决于你最后想要什么。
  • @kwoxer 这不是另一个问题的重复。这个问题不是关于图初始化时节点的行为。我已经编辑了我的问题以使其更清楚。
  • 好的,那为什么不直接修复节点呢?
  • @kwoxer 我认为您没有仔细阅读我的问题。我想我已经描述得很清楚了。

标签: javascript d3.js


【解决方案1】:

通常,当force.resume() 被触发时,alpha 值会从 0 跳到 0.1。通过更慢地放宽 alpha,我们可以掩盖“不必要的运动”。

我仍然对其他想法和解决方案持开放态度。

旧功能:

force.resume = function() {
  return force.alpha(.1);
};

替换函数:

force.resume = function() {
  var alpha = force.alpha()
  if( alpha < 0.005 ){ alpha = 0.0055 }
  else if( alpha < 0.11 ){ alpha += 0.0006 }
  return force.alpha(alpha);
};

【讨论】:

    【解决方案2】:

    行为主要来自 alpha。 d3内的alpha函数:

    force.alpha = function(x) {
      if (!arguments.length) return alpha;
      x = +x;
      if (alpha) {
        if (x > 0) alpha = x; else alpha = 0;
      } else if (x > 0) {
        event.start({
          type: "start",
          alpha: alpha = x
        });
        d3.timer(force.tick);
      }
      return force;
    };
    

    所以当调用 alpha 时,如果大于 0 则启动 tick 事件

    在滴答事件中,一开始,您可以看到导致您提到的“冻结”的中断:

    if ((alpha *= .99) < .0005) {
             event.end({
               type: "end",
               alpha: alpha = 0
             });
             return true;
           }
    

    现在,如果我们看一下 dragmove,它会调用 resume 函数:

    function dragmove(d) {
          d.px = d3.event.x, d.py = d3.event.y;
          force.resume();
        } 
    

    调用值为0.1的alpha函数:

     force.resume = function() {
          return force.alpha(.1);
        };
    

    为了在 0.0005 停止跳跃和冻结,我认为自己没有任何可以使用的公共函数。

    我有一个示例fiddle,它从导致冻结的刻度函数中删除了代码,并将恢复函数更改为以较小的 alpha 开始。

    我相信这会提供您想要的结果,但我当然不建议自定义库。

    也许有人知道如何在不修改源代码的情况下覆盖 tick 函数。

    【讨论】:

    • 我想我必须自定义库。我要看看我是否能弄清楚event.start 到底是什么,以及它与force.start 的关系。
    • 我无法通过图书馆中的var candidates = neighbors[i], j = -1, l = candidates.length, x; 行。它在函数外部使用i。另外,如果没有提供输入位置,它会给出一个随机数吗?
    • 只有当你的 x 和 y 值不是数字时才会调用这个函数,从这个函数的 start 方法:for (i = 0; i &lt; n; ++i) { o = nodes[i]; if (isNaN(o.x)) o.x = position("x", w); if (isNaN(o.y)) o.y = position("y", h); if (isNaN(o.px)) o.px = o.x; if (isNaN(o.py)) o.py = o.y; } i 是这个方法的i
    • 感谢您的帮助!
    【解决方案3】:

    在

    // Toggle children on click.
    function click(d) {
      if (!d3.event.defaultPrevented) {
        if (d.children) {
          d._children = d.children;
          d.children = null;
        } else {
          d.children = d._children;
          d._children = null;
        }
        update();
      }
    }
    

    您可以将更新移动到仅打开的子项

    // Toggle children on click.
    function click(d) {
      if (!d3.event.defaultPrevented) {
        if (d.children) {
          d._children = d.children;
          d.children = null;
          update();
        } else {
          d.children = d._children;
          d._children = null;
        }
    
      }
    }
    

    所以没有子节点(橙色)的节点不会在点击时更新。

    【讨论】:

    • 我认为这不能回答问题。这个问题并不特定于树木。
    • s/他想在单击橙色圆圈时摆脱更新。它就是这样做的,交换两行代码。它可以简单到什么程度?虽然投票的答案是 ncie 和完整的,但它建议对核心库进行大量编辑,我认为这不是 OP 想要做的!
    • 我是 OP,如果可以解决问题,我可以编辑库。我不想摆脱更新,而是想防止当图形从静止位置变为移动位置时节点产生的不必要的扰动或痉挛(当图形静止然后拖动时会发生这种情况) fiddle 中的一个节点)。如果您确信您的答案可以做到这一点,请分叉小提琴并在此处链接回您的解决方案。
    • OP 询问了有关此特定代码的问题:bl.ocks.org/mbostock/1062288,现在链接到大约 3000 多行代码,这些代码与原始代码几乎没有任何关系。我回答了有关上述代码的问题。橙色节点是叶节点。点击对它没有任何作用,只会让它发出嘶嘶声。我的回答删除了橙色节点上的更新,并按要求将其删除。但显然 OP 现在正在开发一个非常不同的分支,所以谁在乎......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-12
    • 2017-11-17
    • 1970-01-01
    相关资源
    最近更新 更多