【问题标题】:d3.js Node "jumps back" on fast drag in force layoutd3.js 节点在强制布局中快速拖动时“跳回”
【发布时间】:2015-05-22 03:14:40
【问题描述】:

我正在使用零重力和电荷值的力布局:

var force = d3.layout.force()
    .gravity(0)
    .charge(0)
    .friction(0.9)
    .linkDistance(250)
    .linkStrength(1)
    .size([width, height])
    .on("tick", tick);

function tick(e) {
    d.y = Math.max(d.radius, Math.min(height - d.radius, d.y));
    d.x = Math.max(d.radius, Math.min(width - d.radius, d.x));

    return "translate(" + d.x + "," + d.y + ")";
});
        }

有一个圆圈。问题是当我快速拖动时,圆圈“跳回来”。任何帮助,将不胜感激。谢谢。

代码笔:http://codepen.io/vanquang9387/pen/gpLpGE?editors=001

【问题讨论】:

  • 你能提供一个 JSFiddle 吗?
  • @thisOneGuy:我无法使其与 JSFiddle 一起用于共享。我已经更新了 CodePen 链接。谢谢。

标签: javascript d3.js


【解决方案1】:

脏修复

改变这个...

.friction(0.9)

到这个……

.friction(0)

背景

在 d3 的 force layout 模块中,有一个force.tick 方法在每个动画帧之前被调用。这是重新计算节点位置的地方。考虑到链接strengthweights 和目标linkDistance 的链接计算; gravity 计算,它是每个节点到布局中心的距离的函数;以及基于chargechargeDistance和节点相对位置的费用计算。还有一个friction 的计算。所有这些 - 除了friction 计算 - 考虑到布局的当前“温度”(alpha),这实际上只是一个指数衰减值,它是自布局以来经过多少滴答声的函数开始了。

这些计算顺序应用于布局的所有元素,每个步骤的输入位置是前一个步骤的输出。但是对于摩擦计算,“固定”节点的处理方式不同,并且被拖动的节点是 fixed 拖动行为。

friction 并不是真正的“摩擦”,它更像是WIKI 中解释的速度衰减,friction 计算旨在通过将节点从末端移开来保持节点的速度上一个刻度(pxpy)。移动的距离与每个节点的速度成正比,该速度基于(pxpy)与当前tick 中前面步骤(链接、电荷和重力)计算的位置之间的距离(实际上它比这要复杂一些,因为电荷计算实际上是“非因果”的,并且改变了以前的位置,但这并不影响摩擦计算的原理)。

在拖动过程中,(px, py) 通过每个mousemove 上的拖动行为随鼠标位置更新。 然后,在下一个滴答声中,这些值将复制到强制布局中的 (x, y)。因此,在拖动过程中,previous 位置实际上是 当前 位置,反之亦然!因此,当阻力结束时,摩擦计算中使用的速度与实际速度的方向相反,因此friction calc 试图保持这一点......这就是它跳回的原因.

死停

我的下一步是在dragend 事件处理程序中找到一种方法将 (px, py) 设置为 (x, y)。
比如这样...

  var stdDragEnd = force.drag().on("dragend.force");
  force.drag().on("dragend.force", myDragEnd);
  function myDragEnd(d) {
    d.px = d.x; d.py = d.y;
    stdDragEnd.call(this, d)
  }

您可以将它放在代码中已定义 force 变量的任何位置。这个想法是挂钩标准行为而不是替换它。

现在,即使您将摩擦力设置为 1.0,节点也会在拖动结束后停止。
顺便说一下,您不需要根据代码的当前状态保留this 上下文,但无论如何,我猜这是一个好习惯。谁知道未来会带来什么 lah ;)

【讨论】:

  • 它似乎有效。但是,当我添加更多节点和链接并带有负电荷值时,这会减慢运动速度。不是吗?
  • 感谢您的详细解释。我正在尝试使用 dragend 事件。
  • 非常感谢您的帮助。但现在我想做一个惯性拖动而不是“死停”。与其他节点和链接一样:bl.ocks.org/pjanik/5872514 我认为这很难实现:(
  • @Quang 这是一个新问题。你只是在问关于跳回来,我回答了,所以如果你接受我的回答并提出一个新问题会更好。我也会帮你的...
  • @Quang,顺便说一下,您提供的链接使用的是 d3 的旧版本(3.2.2),它有一个完全不同的拖动行为模块,其中包括一种惯性方法,该方法后来消失了。 ..
猜你喜欢
  • 1970-01-01
  • 2019-05-14
  • 2016-08-15
  • 1970-01-01
  • 2014-01-15
  • 2013-12-04
  • 1970-01-01
  • 2012-07-13
  • 2023-03-19
相关资源
最近更新 更多