| src | ||
| .eslintrc | ||
| .gitignore | ||
| .npmignore | ||
| d3-force.sublime-project | ||
| index.js | ||
| LICENSE | ||
| package.json | ||
| README.md | ||
d3-force
…
Installing
If you use NPM, npm install d3-force. Otherwise, download the latest release. You can also load directly from d3js.org, either as a standalone library or as part of D3 4.0 alpha. AMD, CommonJS, and vanilla environments are supported. In vanilla, a d3_force global is exported:
<script src="https://d3js.org/d3-collection.v0.1.min.js"></script>
<script src="https://d3js.org/d3-dispatch.v0.4.min.js"></script>
<script src="https://d3js.org/d3-quadtree.v0.7.min.js"></script>
<script src="https://d3js.org/d3-timer.v0.4.min.js"></script>
<script src="https://d3js.org/d3-force.v0.3.min.js"></script>
<script>
var simulation = d3_force.forceSimulation(nodes);
</script>
API Reference
Simulation
# d3.forceSimulation([nodes])
Creates a new simulation with the specified array of nodes and no forces. If nodes is not specified, it defaults to the empty array. The simulator starts automatically; use simulation.on to listen for tick events as the simulation runs. If you wish to run the simulation manually instead, call simulation.stop, and then call simulation.tick as desired.
# simulation.restart()
Resets the current iteration count, setting the current alpha to one, restarts the simulation‘s internal timer, and returns the simulation. This method can be used to “reheat” the simulation after interaction, such as when dragging a node, or to resume the simulation after temporarily pausing it with simulation.stop.
# simulation.stop()
Stops the simulation‘s internal timer, if it is running, and returns the simulation. If the timer is already stopped, this method does nothing. This method is useful for running the simulation manually; see simulation.tick.
# simulation.tick()
Invokes each registered force, passing the current alpha; then updates the positions and velocities of each node according to the following formula: velocity *= 1 - drag, position += velocity. Returns true if the current alpha is less than alphaMin, indicating that the simulation would normally stop after this tick, and false otherwise.
The current alpha is defined as exp(iteration × alphaDecay) where iteration is the number of times this method has been called since the simulation started. Thus, the exact number of iterations needed to terminate the simulation naturally is ⌈log(alphaMin) / -alphaDecay⌉. For example, to run the simulation manually, as when computing a static layout in a background web worker or on the server:
for (var i = 0, n = Math.ceil(Math.log(simulation.alphaMin()) / -simulation.alphaDecay()); i < n; ++i) {
simulation.tick();
}
This method does not dispatch events; events are only dispatched by the internal timer when the simulation is started automatically upon creation or by calling simulation.restart.
# simulation.nodes([nodes])
If nodes is specified, sets the simulation’s nodes to the specified array, initializing their positions and velocities if necessary, and then re-initializes any bound forces; returns the simulation. If nodes is not specified, returns the simulation’s array of nodes as specified to the constructor. Each node must be an object; the following properties are initialized by the simulation:
index- the node’s zero-based index into nodesx- the node’s current x-positiony- the node’s current y-positionvx- the node’s current x-velocityvy- the node’s current y-velocity
The position ⟨x,y⟩ and velocity ⟨vx,vy⟩ may be subsequently modified by forces and by the simulation. If either vx or vy is NaN, the velocity is initialized to ⟨0,0⟩. If either x or y is NaN, the position is initialized in a phyllotaxis arrangement, so chosen to ensure a deterministic, uniform distribution around the origin.
If the specified array of nodes is modified, such as when nodes are added to or removed from the simulation, this method must be called again with the new (or changed) array to notify the simulation and bound forces of the change; the simulation does not make a defensive copy of the specified array.
# simulation.alphaMin([alpha])
If alpha is specified, sets the minimum alpha to the specified number and returns this simulation. If alpha is not specified, returns the current minimum alpha value, which defaults to 0.001. The minimum alpha value determines when the simulation will stop automatically: when the current alpha is less than the minimum alpha. Assuming the default alpha decay rate of 0.02, this corresponds to 346 iterations.
# simulation.alphaDecay([decay])
If decay is specified, sets the exponential decay rate constant λ to the specified number and returns this simulation. If decay is not specified, returns the current alpha decay rate, which defaults to 0.02. The alpha decay rate determines how quickly the simulation stabilizes. Higher values cause the simulation to stabilize more quickly, but risk getting stuck in a local minimum; lower values cause the simulation to take longer to run, but typically converge on a better layout. To have the simulation run forever, set the decay rate to zero.
# simulation.drag([drag])
If drag is specified, sets the drag factor to the specified number in the range [0,1] and returns this simulation. If drag is not specified, returns the current drag factor, which defaults to 0.4. The drag factor affects how quickly nodes’ velocities decay; at each tick, the velocities are updated according to the following formula: velocity *= 1 - drag. As with lowering the alpha decay rate, less drag may converge on a better solution, but it also risks numerical instabilities and oscillations.
# simulation.force(name[, force])
If force is specified, assigns the force for the specified name and returns this simulation. If force is not specified, returns the force with the specified name, or undefined if there is no such force. (By default, new simulations have no forces.) For example, to create a new simulation to layout a graph, you might say:
var simulation = d3.forceSimulation(nodes)
.force("charge", d3.forceManyBody())
.force("link", d3.forceLink(links))
.force("center", d3.forceCenter());
# simulation.on(typenames, [listener])
If listener is specified, sets the event listener for the specified typenames and returns this simulation. If an event listener was already registered for the same type and name, the existing listener is removed before the new listener is added. If listener is null, removes the current event listeners for the specified typenames, if any. If listener is not specified, returns the first currently-assigned listener matching the specified typenames, if any. When a specified event is dispatched, each listener will be invoked with the this context as the simulation.
The typenames is a string containing one or more typename separated by whitespace. Each typename is a type, optionally followed by a period (.) and a name, such as tick.foo and tick.bar; the name allows multiple listeners to be registered for the same type. The type must be one of the following:
See dispatch.on for details.
Forces
A force is simply a function that modifies nodes’ positions or velocities; in this context, a force can apply a classical physical force such as electrical charge or gravity, or it can resolve a geometric constraint, such as keeping nodes within a bounding box or keeping linked nodes a fixed distance apart. For example, a simple positioning force that moves nodes towards the origin ⟨0,0⟩ might be implemented as:
function force(alpha) {
for (var i = 0, n = nodes.length, node, k = alpha * 0.1; i < n; ++i) {
node = nodes[i];
node.vx -= node.x * k;
node.vy -= node.y * k;
}
}
Forces typically read the node’s current position ⟨x,y⟩ and then add to (or subtract from) the node’s velocity ⟨vx,vy⟩. However, forces may also “peek ahead” to the anticipated next position of the node, ⟨x + vx,y + vy⟩; this is necessary for resolving geometric constraints through iterative relaxation. Forces may also modify the position directly, which is sometimes useful to avoid adding energy to the simulation, such as when recentering the simulation in the viewport.
Simulations typically compose multiple forces as desired. This module provides several for your enjoyment:
Forces may optionally implement force.initialize to receive the simulation’s array of nodes.
# force(alpha)
Applies this force, optionally observing the specified alpha. Typically, the force is applied to the array of nodes previously passed to force.initialize, however, some forces may apply to a subset of nodes, or behave differently. For example, d3.forceLink applies to the source and target of each link.
# force.initialize(nodes)
Assigns the array of nodes to this force. This method is called when a force is bound to a simulation via simulation.force and when the simulation’s nodes change via simulation.nodes. A force may perform necessary work during initialization, such as evaluating per-node parameters, to avoid repeatedly performing work during each application of the force.
Centering
The centering force translates nodes uniformly so that the mean position of all nodes (the center of mass if all nodes have equal weight) is at the given position ⟨x,y⟩. This force modifies the positions of nodes on each application; it does not modify velocities, as doing so would typically cause the nodes to overshoot and oscillate around the desired center. This force helps keeps nodes in the center of the viewport, and unlike the positioning force, it does not distort their relative positions.
# d3.forceCenter([x, y])
Creates a new centering force with the specified x- and y- coordinates. If x and y are not specified, they default to ⟨0,0⟩.
# center.x([x])
If x is specified, sets the x-coordinate of the centering position to the specified number and returns this force. If x is not specified, returns the current x-coordinate, which defaults to zero.
# center.y([y])
If y is specified, sets the y-coordinate of the centering position to the specified number and returns this force. If y is not specified, returns the current y-coordinate, which defaults to zero.
Collision
The collision force treats nodes as circles with a given radius, rather than points, and prevents nodes from overlapping. More formally, two nodes a and b are separated so that the distance between a and b is at least radius(a) + radius(b). To reduce jitter, this is by default a “soft” constraint with a configurable strength and iteration count.
# d3.forceCollide([radius])
Creates a new circle collision force with the specified radius. If radius is not specified, it defaults to the constant one for all nodes.
# collide.radius([radius])
If radius is specified, sets the radius accessor to the specified number or function, re-evaluates the radius accessor for each node, and returns this force. If radius is not specified, returns the current radius accessor, which defaults to:
function radius() {
return 1;
}
The radius accessor is invoked for each node in the simulation, being passed the node and its zero-based index. The resulting number is then stored internally, such that the radius of each node is only recomputed when the force is initialized or when this method is called, and not on every application of the force.
# collide.strength([strength])
If strength is specified, sets the force strength to the specified number in [0,1] and returns this force. If strength is not specified, returns the current strength which defaults to 0.7.
Overlapping nodes are resolved through iterative relaxation. For each node, the other nodes that are anticipated to overlap at the the at the next tick (using the anticipated positions ⟨x + vx,y + vy⟩) are determined; the node’s velocity is then modified to push the node out of each overlapping node. The change in velocity is dampened by the force’s strength such that the resolution of simultaneous overlaps can be blended together to find a stable solution.
# collide.iterations([iterations])
If iterations is specified, sets the number of iterations per application to the specified number and returns this force. If iterations is not specified, returns the current iteration count which defaults to 1. Increasing the number of iterations greatly increases the rigidity of the constraint and avoids partial overlap of nodes, but also increases the runtime cost to evaluate the force.
Links
The link force pushes linked nodes closer together or farther apart according to the desired link distance, which may be specified on a per-node basis. (These parameters are only recomputed when the force is initialized, not on every application.)
# d3.forceLink([links])
…
# link.links([links])
…
index- the zero-based index into linkssource- the link’s source node; see simulation.nodestarget- the link’s target node; see simulation.nodes
The source and target properties may be initialized using link.id.
# link.id([id])
…
# link.distance([distance])
…
# link.strength([strength])
…
# link.iterations([iterations])
…
Many-Body
The many-body (or n-body) force applies mutally amongst all nodes. It can be used to simulate gravity (attraction) if the strength is positive, or eletrical charge (repulsion) if the strength is negative. This implementation uses quadtrees and the Barnes–Hut approximation to greatly improve performance; the accuracy can be customized using the theta parameter. The strength can be specified on a per-node basis. (This parameter is only recomputed when the force is initialized, not on every application.)
# d3.forceManyBody()
…
# manyBody.strength([strength])
…
# manyBody.theta([theta])
…
# manyBody.distanceMin([distance])
…
# manyBody.distanceMax([distance])
…
Positioning
The positioning force pushes nodes towards a desired position ⟨x,y⟩. The position and strength can be specified on a per-node basis. (These parameters are only recomputed when the force is initialized, not on every application.)
# d3.forcePosition([x, y])
…
# position.strength([strength])
…
# position.x([x])
…
# position.y([y])
…