import constant from "./constant"; import jiggle from "./jiggle"; /** * Modified link force algorithm * - simplify calculations for parameters locked for spring model * - replace the use of links {} with loop. greatly reduce memory usage * - removed other unused functions * Alpha should be constant 1 for accurate simulation */ export default function() { var dataSizeFactor, distance = constant(30), distances = [], nodes, iterations = 1; function force(alpha) { // Each iteration in a tick for (var k = 0, n = nodes.length, source, target, i, j, x, y, l; k < iterations; ++k) { // For each link for (i = 1; i < n; i++) for (j = 0; j < i; j++) { // jiggle so l won't be zero and divide by zero error after this source = nodes[i]; target = nodes[j]; x = target.x + target.vx - source.x - source.vx || jiggle(); y = target.y + target.vy - source.y - source.vy || jiggle(); l = Math.sqrt(x * x + y * y); l = (l - distances[i*(i-1)/2+j]) / l * dataSizeFactor * alpha; x *= l, y *= l; target.vx -= x; target.vy -= y; source.vx += x; source.vy += y; } } } function initialize() { if (!nodes) return; // 0.5 to divide the force to two part for source and target node dataSizeFactor = 0.5/(nodes.length-1); initializeDistance(); } function initializeDistance() { if (!nodes) return; for (let i = 1, n = nodes.length; i < n; i++) { for (let j = 0; j < i; j++) { distances.push(distance(nodes[i], nodes[j])); } } } force.initialize = function(_) { nodes = _; initialize(); }; force.iterations = function(_) { return arguments.length ? (iterations = +_, force) : iterations; }; force.distance = function(_) { return arguments.length ? (distance = typeof _ === "function" ? _ : constant(+_), initializeDistance(), force) : distance; }; return force; }