Published
Edited
Jul 3, 2021
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// Defines a force that moves nodes along an SVG path.
//
// Parameters:
// - path: An SVGGeometryElement (e.g. a <path> element).
// Note: Elements other than <path> need to be attached to the DOM.
// - nodes: the simulation nodes.
// - options: An object with any of the following properties:
// - strength: ratio of the distance a node is moved towards its target at each step.
// - offset: callback that returns a node's relative offset along the path (from 0 to 1).
// - clamp: max movement distance per iteration step.
// - initialize: sets each node's position to its target on the path.
function pathForce(path, nodes, {
strength = .1,
offset = (n, i, nodes) => i / nodes.length,
initialize = true,
clamp = Infinity
} = {}) {
const getStrength = callable(strength),
getClamp = callable(clamp),
getScale = max => !isFinite(max) ? () => 1 : (dx, dy) => {
const d = Math.hypot(dx, dy);
return d ? Math.min(max, d) / d : 0;
},
getPoint = (i, l) => path.getPointAtLength(offset(nodes[i], i, nodes) * l),
getLength = () => path.getTotalLength();

// Initialize node positions along the path.
if(initialize) {
const l = getLength();
for(let i = 0, p; i < nodes.length; i++) {
p = getPoint(i, l);
nodes[i].x = p.x;
nodes[i].y = p.y;
}
}
// The simulation step callback.
return () => {
const l = getLength(),
s = getStrength(),
clamp = getScale(getClamp());
for(let i = 0, p, n, dx, dy, c; i < nodes.length; i++) {
p = getPoint(i, l);
n = nodes[i];
dx = s * (p.x - n.x);
dy = s * (p.y - n.y);
c = clamp(dx, dy);
n.vx += c * dx;
n.vy += c * dy;
}
};
};

Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more