d3:Multi-Foci Force键代码组件理解

时间:2015-04-14 16:10:36

标签: javascript svg d3.js force-layout

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

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位置移动,但我们如何保证我们根据这个基于alpha的k值得到它们?节点沿着由.1常量控制的x和y轴移动的程度是多少?设置这个更高/更低意味着更多/更少的偏向焦点?

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

node.attr(“cx”,function(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]?)

1 个答案:

答案 0 :(得分:1)

动画由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%。

对于x和y,元素的初始位置也在.start()函数中设置为Math.random() * size,其中size分别是width和height。这是在<{em>} forEach函数中的第一个tick之前完成的。

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.1几何上逐渐减少到k = 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]。