Assign node.index in d3.forceSimulation.

Also get ready for d3-quadtree 0.3 and per-node forces.
This commit is contained in:
Mike Bostock 2016-04-08 08:32:24 -07:00
parent 13fd5ee8ce
commit f08062fb16
5 changed files with 40 additions and 34 deletions

View File

@ -32,7 +32,7 @@
"dependencies": {
"d3-collection": "0.1",
"d3-dispatch": "0.4",
"d3-quadtree": "0.2",
"d3-quadtree": "0.3",
"d3-timer": "0.4"
},
"devDependencies": {

5
src/constant.js Normal file
View File

@ -0,0 +1,5 @@
export default function(x) {
return function() {
return x;
};
}

View File

@ -22,19 +22,10 @@ export default function(links) {
}
function initialize() {
var i, n, link, count;
for (i = 0, n = nodes.length, count = new Array(n); i < n; ++i) {
count[nodes[i].index = i] = 0;
}
for (i = 0, n = links.length; i < n; ++i) {
link = links[i], ++count[link.source.index], ++count[link.target.index];
}
for (i = 0, bias = new Array(n); i < n; ++i) {
link = links[i], bias[i] = count[link.source.index] / (count[link.source.index] + count[link.target.index]);
}
var i, n = nodes.length, m = links.length, k = new Array(n), l;
for (i = 0; i < n; ++i) k[i] = 0;
for (i = 0, bias = new Array(m); i < m; ++i) l = links[i], ++k[l.source.index], ++k[l.target.index];
for (i = 0; i < m; ++i) l = links[i], bias[i] = k[l.source.index] / (k[l.source.index] + k[l.target.index]);
}
force.nodes = function(_) {

View File

@ -1,4 +1,5 @@
import {quadtree} from "d3-quadtree";
import constant from "./constant";
var nodeQuadtree = quadtree()
.x(function(d) { return d.x; })
@ -7,21 +8,19 @@ var nodeQuadtree = quadtree()
function accumulate(quad, k) {
var cx = 0, cy = 0, charge = 0;
if (!quad.leaf) {
for (var i = 0, child; i < 4; ++i) {
child = quad.nodes[i];
if (child == null) continue;
accumulate(child, k);
charge += child.charge;
cx += child.charge * child.cx;
cy += child.charge * child.cy;
}
if (quad.point) { // TODO handle coincident nodes
charge += quad.selfCharge = k;
cx += k * quad.point[0];
cy += k * quad.point[1];
}
if (quad.data) {
charge += quad.selfCharge = k;
cx += k * quad.data.x;
cy += k * quad.data.y;
else for (var i = 0, child; i < 4; ++i) {
child = quad[i];
if (child == null) continue;
accumulate(child, k);
charge += child.charge;
cx += child.charge * child.cx;
cy += child.charge * child.cy;
}
quad.cx = cx / charge;
@ -31,19 +30,22 @@ function accumulate(quad, k) {
export default function() {
var nodes,
strength = -100, // TODO compute per-node charge on initialization
strength = constant(-100),
distance2 = Infinity,
theta2 = 0.64,
target;
function force(alpha) {
var root = nodeQuadtree(nodes);
accumulate(root, alpha * strength);
for (var i = 0, n = nodes.length; i < n; ++i) target = nodes[i], root.visit(apply);
accumulate(root, alpha * strength()); // TODO
for (var i = 0, n = nodes.length; i < n; ++i) {
target = nodes[i];
root.each(apply);
}
}
function apply(quad, x1, _, x2) {
if (quad.data !== target) {
if (!quad.point || quad.point.data !== target) {
var dx = quad.cx - target.x,
dy = quad.cy - target.y,
dw = x2 - x1,
@ -59,7 +61,7 @@ export default function() {
return true;
}
if (quad.data && dn && dn < distance2) {
if (quad.point && dn && dn < distance2) { // TODO handle coincident nodes
k = quad.selfCharge / dn;
target.vx += dx * k;
target.vy += dy * k;
@ -74,7 +76,7 @@ export default function() {
};
force.strength = function(_) {
return arguments.length ? (strength = +_, force) : strength;
return arguments.length ? (strength = typeof _ === "function" ? _ : constant(+_), force) : strength;
};
force.distance = function(_) {

View File

@ -47,6 +47,12 @@ export default function(nodes) {
dispatch.call("tick", simulation);
}
function index() {
for (var i = 0, n = nodes.length; i < n; ++i) {
nodes[i].index = i;
}
}
function initialize(force) {
force.nodes(nodes);
}
@ -55,12 +61,14 @@ export default function(nodes) {
force(alpha);
}
index();
return simulation = {
start: start,
stop: stop,
tick: tick,
nodes: function(_) {
return arguments.length ? (nodes = _, force.each(initialize), simulation) : nodes;
return arguments.length ? (nodes = _, index(), force.each(initialize), simulation) : nodes;
},
alphaMin: function(_) {
return arguments.length ? (alphaMin = _, simulation) : alphaMin;