我正在使用零重力和充电值的力布局:
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 + ")";
});
}
有一个圆圈。问题是当我快速拖动时,圆圈“跳回”。任何帮助,将不胜感激。感谢。
CodePen:http://codepen.io/vanquang9387/pen/gpLpGE?editors=001
答案 0 :(得分:4)
改变这个......
.friction(0.9)
到此......
.friction(0)
在d3中的强制布局模块中,有一个force.tick
方法在每个动画帧之前调用。这是重新计算节点位置的位置。对链接进行了计算,其中考虑了链接strength
,weights
和目标linkDistance
; gravity
计算,它是每个节点距布局中心的距离的函数;以及基于charge
,chargeDistance
和节点相对位置的费用计算。还有friction
的计算。所有这些 - 除了friction
计算 - 考虑到布局的当前“温度”(alpha
),这实际上只是一个指数衰减的值,它是多少滴答的函数布局开始后经过的时间。
这些计算顺序应用于布局的所有元素,每个步骤的输入位置是前一个的输出。但是,对于摩擦计算,“固定”节点的处理方式不同,拖动的节点由拖动行为fixed
处理。
friction
不是真正的“摩擦”,它更像是WIKI中解释的速度衰减,friction
计算是为了通过将它们移开来保持节点的速度从他们在上一个刻度结束时的位置(px
,py
)开始。移开的距离与每个节点的速度成比例,该速度基于(px
,py
)与当前步骤(链路,电荷和重力)计算的位置之间的距离tick
(实际上它比那更复杂,因为电荷计算实际上是“非因果”并改变了以前的位置,但这并不影响摩擦计算的原理)。
在拖动过程中,(px
,py
)会根据每个mousemove
上的拖动行为使用鼠标位置进行更新。 然后,在下一个标记处,这些值将被复制到强制布局中的(x
,y
)。因此,在拖动过程中,上一个位置实际上是当前位置,反之亦然!因此,当拖动结束时,摩擦计算中使用的速度在与其实际速度相反的方向,因此friction
calc试图保持这个...这就是为什么它跳回来。
我的下一步行动是找到一种方法在px
事件处理程序中设置(py
,x
)到(y
,dragend
) 。
像这样......例如......
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,节点也会在dragend之后停止
根据代码的当前状态,您不需要保留this
上下文,但无论如何,我认为这是一个好习惯。谁知道未来会带来什么呢?)