2016-04-06 04:50:36 +08:00
|
|
|
import {dispatch as newDispatch} from "d3-dispatch";
|
2016-04-08 02:32:34 +08:00
|
|
|
import {map as newMap} from "d3-collection";
|
|
|
|
|
import {timer as newTimer} from "d3-timer";
|
2016-04-06 04:50:36 +08:00
|
|
|
|
|
|
|
|
export default function(nodes) {
|
2016-04-08 02:32:34 +08:00
|
|
|
var simulation,
|
|
|
|
|
iteration = 0,
|
2016-04-08 02:55:45 +08:00
|
|
|
alpha = 1,
|
2016-04-07 04:51:59 +08:00
|
|
|
alphaMin = 0.0001,
|
|
|
|
|
alphaDecay = -0.02,
|
|
|
|
|
velocityDecay = 0.5,
|
2016-04-08 02:32:34 +08:00
|
|
|
force = newMap(),
|
2016-04-06 04:50:36 +08:00
|
|
|
timer = newTimer(tick),
|
2016-04-08 02:32:34 +08:00
|
|
|
dispatch = newDispatch("start", "tick", "end");
|
2016-04-06 04:50:36 +08:00
|
|
|
|
2016-04-07 04:21:23 +08:00
|
|
|
function start() {
|
2016-04-07 04:51:59 +08:00
|
|
|
if (iteration < Infinity) {
|
2016-04-08 02:55:45 +08:00
|
|
|
iteration = 0, alpha = 1;
|
|
|
|
|
} else {
|
|
|
|
|
iteration = 0, alpha = 1;
|
2016-04-08 02:32:34 +08:00
|
|
|
dispatch.call("start", simulation);
|
2016-04-07 04:21:23 +08:00
|
|
|
timer.restart(tick);
|
|
|
|
|
}
|
2016-04-08 02:32:34 +08:00
|
|
|
return simulation;
|
2016-04-07 04:21:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function stop() {
|
2016-04-07 04:51:59 +08:00
|
|
|
if (iteration < Infinity) {
|
2016-04-08 02:55:45 +08:00
|
|
|
iteration = Infinity, alpha = 0;
|
2016-04-08 02:32:34 +08:00
|
|
|
dispatch.call("end", simulation);
|
2016-04-07 04:21:23 +08:00
|
|
|
timer.stop();
|
2016-04-06 04:50:36 +08:00
|
|
|
}
|
2016-04-08 02:32:34 +08:00
|
|
|
return simulation;
|
2016-04-06 04:50:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function tick() {
|
2016-04-08 02:32:34 +08:00
|
|
|
alpha = Math.exp(++iteration * alphaDecay);
|
2016-04-07 04:51:59 +08:00
|
|
|
if (!(alpha > alphaMin)) return stop();
|
2016-04-08 02:32:34 +08:00
|
|
|
force.each(apply);
|
2016-04-06 04:50:36 +08:00
|
|
|
|
|
|
|
|
for (var i = 0, n = nodes.length, node; i < n; ++i) {
|
|
|
|
|
node = nodes[i];
|
2016-04-07 04:21:23 +08:00
|
|
|
node.x += node.vx *= velocityDecay;
|
|
|
|
|
node.y += node.vy *= velocityDecay;
|
2016-04-06 04:50:36 +08:00
|
|
|
}
|
|
|
|
|
|
2016-04-08 02:32:34 +08:00
|
|
|
dispatch.call("tick", simulation);
|
2016-04-06 04:50:36 +08:00
|
|
|
}
|
|
|
|
|
|
2016-04-08 23:32:24 +08:00
|
|
|
function index() {
|
|
|
|
|
for (var i = 0, n = nodes.length; i < n; ++i) {
|
|
|
|
|
nodes[i].index = i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-08 02:32:34 +08:00
|
|
|
function initialize(force) {
|
2016-04-21 00:53:56 +08:00
|
|
|
if (force.nodes) force.nodes(nodes);
|
2016-04-08 02:32:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function apply(force) {
|
|
|
|
|
force(alpha);
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-08 23:32:24 +08:00
|
|
|
index();
|
|
|
|
|
|
2016-04-08 02:32:34 +08:00
|
|
|
return simulation = {
|
|
|
|
|
start: start,
|
|
|
|
|
stop: stop,
|
|
|
|
|
tick: tick,
|
2016-04-06 04:50:36 +08:00
|
|
|
nodes: function(_) {
|
2016-04-08 23:32:24 +08:00
|
|
|
return arguments.length ? (nodes = _, index(), force.each(initialize), simulation) : nodes;
|
2016-04-06 04:50:36 +08:00
|
|
|
},
|
2016-04-07 04:51:59 +08:00
|
|
|
alphaMin: function(_) {
|
2016-04-08 02:32:34 +08:00
|
|
|
return arguments.length ? (alphaMin = _, simulation) : alphaMin;
|
2016-04-06 04:50:36 +08:00
|
|
|
},
|
|
|
|
|
alphaDecay: function(_) {
|
2016-04-08 02:55:45 +08:00
|
|
|
return arguments.length ? (alphaDecay = -_, iteration = Math.round(Math.log(alpha) / alphaDecay), simulation) : -alphaDecay;
|
2016-04-06 04:50:36 +08:00
|
|
|
},
|
2016-04-07 04:21:23 +08:00
|
|
|
friction: function(_) {
|
2016-04-08 02:32:34 +08:00
|
|
|
return arguments.length ? (velocityDecay = 1 - _, simulation) : 1 - velocityDecay;
|
|
|
|
|
},
|
|
|
|
|
force: function(name, _) {
|
|
|
|
|
return arguments.length > 1 ? (initialize(_), force.set(name, _), simulation) : force.get(name);
|
2016-04-06 04:50:36 +08:00
|
|
|
},
|
|
|
|
|
on: function(name, _) {
|
2016-04-08 02:32:34 +08:00
|
|
|
return arguments.length > 1 ? (dispatch.on(name, _), simulation) : dispatch.on(name);
|
2016-04-06 04:50:36 +08:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|