d3:多焦点力关键代码组件理解



多焦点力的真正魔力在这里完成;

function tick(e) {
var k = .1 * e.alpha;
// Push nodes toward their designated focus.
nodes.forEach(function(o, i) {
o.y += (foci[o.id].y - o.y) * k;
o.x += (foci[o.id].x - o.x) * k;
});
node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
}   

但我希望能澄清一下发生了什么。

我相信,alpha是一种力方法,它控制力停止的速率,接受[0,1]范围内的值——更高的值会导致力缓慢停止,更低的值会更快。

然后,我们遍历原始数组,并将x和y位置(最初不存在,因此在forEach循环的第一次迭代中首次分配这些位置)增加k*焦点的x和y分量。

最终,它们将始终朝着指定的x和y位置移动,但我们如何保证根据这个k值(它本身就是基于alpha的)将它们移动到那里?节点沿x和y轴移动的程度是否由.1常数控制?设置得更高/更低意味着更多/更少地向焦点漂移?

最后,我们为什么要转换节点?我会理解

node.attr("cx",函数(d){return d.x}),y也是如此。为什么要转换?

在广告中谢谢

jfiddle-https://jsfiddle.net/hiwilson1/dL9r22ny/

更新:我怀疑我问题的最后一部分,为什么要转换节点,是因为我们移动的是g元素而不是圆形元素,并且我们不能在g元素上使用cx和cy。仍然不确定我们为什么要将它们转换为d.x和d.y,这难道不会将它们从任意分配的d.x和d.y值中移动出来,从而有效地将这些位置加倍吗?(如果我们从[10,10]开始,再翻译[10,10],我们会在[20,20]结束?)

动画由alpha驱动。这是一个始终相同的几何级数:在.start()中设置为0.1,并在每个刻度乘以0.99,当它小于0.005 时,动画停止

alpha: 0.0990
alpha: 0.0980
alpha: 0.0970
alpha: 0.0961
alpha: 0.0951
alpha: 0.0941

force.tick = function() {
if ((alpha *= .99) < .005) {
event.end({
type: "end",
alpha: alpha = 0
});
return true;
}
//other code...
};

它表示布局中的"热量",因为它用于确定节点的速度。这类似于气体的温度,它与分子的平均动能成正比。"冷却"被预先编程为始终为当前"温度"的-1%。

元素的初始位置也在.start()函数中设置为x和y的Math.random() * size,其中大小分别为宽度和高度。这是在tick函数中的第一个forEach之前完成的。

function tick(e) {
//var k = .1 * e.alpha;
var k = .1 * e.alpha;
log.text('alpha: ' + d3.format(".4f")(e.alpha * 1000))
// Push nodes toward their designated focus.
nodes.forEach(function (o, i) {
o.y += (foci[o.id].y - o.y) * k;
o.x += (foci[o.id].x - o.x) * k;
});

在上面的forEach语句中,如果元素y的位置大于焦点y的位置,那么它将被赋予更小的y,类似于x的位置。这意味着它们将以与其距离成比例的速度向焦点移动。比例常数k0.1*alpha,随着动画的进行,从k = 0.1*0.1k = 0.1*0.005呈几何递减。最终位置是它们的初始位置和k以及其他重力、电荷和摩擦力的函数。

节点是g元素,其除了其子元素的参考(定位上下文)之外没有定位。这是包含svg元素的原点(左上角),它的位置是页面流和CSS定位的结果。g元素的定位上下文可以通过它们的转换属性来更改,并且这是由它们的所有子元素继承的。如果没有g元素,圆和文本元素都必须分开放置,这样工作量就减半了。如果没有转换,所有的圆和文本都将定位在svg元素的左上角。

每个刻度计算的新位置是绝对值,而不是值的变化。

节点位置的变化是(foci[o.id].y - o.y) * k,这将使它们朝着焦点移动。这被"添加"到现有值(尽管它可能是负的)并存储在节点数据(o.xo.y)上,该语句

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

使用新的基准(d)来更新仍然相对于svg原点的平移。它是变换,而不是移动。因此,它不会相对于当前位置平移,而是更改相对于svg元素原点(g的定位上下文)的平移。因此,如果我们从[10,10]开始,并且新的计算是[10,10],那么相对于svg定位上下文,位置将保持在[10,10]。

最新更新