javascript - d3: Multi-Foci Force key code component understanding -
the real magic multi-foci force done here;
function tick(e) { var k = .1 * e.alpha; // push nodes toward 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 + ")"; }); }
but i'd appreciate clarification what's going on.
alpha, believe, force method controls rate @ force comes rest, accepting values in range [0, 1] - higher values cause force slow halt slower, lower values faster.
we iterate through original array , increment x , y locations (which don't exist initially, these assigned first time on first iteration of foreach loop) k * x , y components of focus point.
ultimately they'll moving towards designated x , y positions, how guarantee them there based on k value based on alpha? extent nodes move along x , y axes controlled .1 constant? setting higher/lower implies more/less drift towards focus points?
finally why transform nodes? understand
node.attr("cx", function(d) { return d.x}) , same y. why transform?
thanks in adv.
jfiddle - https://jsfiddle.net/hiwilson1/dl9r22ny/
update: suspect last part of question, why transform nodes, because we're moving g elements rather circle elements , can't use cx , cy on g element. still unsure why translate them d.x , d.y though, wouldn't move them arbitrarily assigned d.x , d.y values double these locations? (if start @ [10, 10] , translate [10, 10] end @ [20, 20]?)
the animation driven alpha
. it's geometric series same: set 0.1 in .start()
, multiplied 0.99 @ each tick, animation stops when less 0.005
alpha: 0.0990 alpha: 0.0980 alpha: 0.0970 alpha: 0.0961 alpha: 0.0951 alpha: 0.0941
...etc.
force.tick = function() { if ((alpha *= .99) < .005) { event.end({ type: "end", alpha: alpha = 0 }); return true; } //other code... };
it represents "heat" in layout because used determine velocity of nodes. in analogous temperature in gas, proportional average kinetic energy of it's molecules. "cooling" pre-programmed be -1% of current "temperature".
the initial positions of elements set in .start()
function math.random() * size
x , y, size width , height respectively. done before first foreach
in tick
function.
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 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; });
in above, foreach
statement, if element y position greater focus y position, given smaller y, similar x positions. means move towards foci @ speed proportional distance it. proportionality constant k
0.1*alpha
decreasing geometrically k = 0.1*0.1
k = 0.1*0.005
, animation proceeds. final positions function of initial positions , k
, other forces of gravity, charge , friction.
the nodes g
elements have no positioning other reference (positioning context) child elements. origin (top left corner) of containing svg
element , it's position result of page flow , css positioning. positioning context of g
elements can altered transform property , inherited of child elements. without g elements, circles , text elements both have positioned separately work halved way. without transforms, of circles , text positioned, centered on top, left corner of svg
element.
the new positions calculated each tick absolute values, not changes in value.
the change in node position (foci[o.id].y - o.y) * k
, move them towards foci. "added" existing value (although negative) , stored on node datum (o.x
, o.y
), statement
node.attr("transform", function (d) { return "translate(" + d.x + "," + d.y + ")"; });
uses new datum (d
) update translation, still relative svg
origin. transform, not move, doesn't translate relative current position, changes translation relative svg
element origin (which positioning context g
). if start @ [10,10] , new calculation [10,10] position remain @ [10,10] relative svg
positioning context.
Comments
Post a Comment