The many-body force applies mutually among all nodes using the Barnes-Hut approximation for efficient n-body simulation. It can simulate gravity (positive strength) or electrostatic charge (negative strength), making it essential for node repulsion in network layouts.
Creates a new many-body force with default parameters.
/**
* Creates a new many-body force with default parameters
* @returns ManyBodyForce instance with configuration methods
*/
function forceManyBody(): ManyBodyForce;Usage Examples:
import { forceManyBody } from "d3-force";
// Create with default settings (repulsive force)
const chargeForce = forceManyBody();
// Add to simulation
simulation.force("charge", forceManyBody());Configure the strength of the many-body interaction.
/**
* Sets or gets the strength accessor for many-body force
* @param strength - Strength value or accessor function (optional, defaults to -30)
* @returns Current strength accessor or force instance for chaining
*/
strength(strength?: number | ((d: Node, i: number, nodes: Node[]) => number)): ((d: Node, i: number, nodes: Node[]) => number) | ManyBodyForce;Usage Examples:
const chargeForce = forceManyBody();
// Fixed repulsive force (negative values repel)
chargeForce.strength(-100);
// Fixed attractive force (positive values attract)
chargeForce.strength(50);
// Variable strength based on node properties
chargeForce.strength(d => d.charge || -30);
// Strength based on node size or importance
chargeForce.strength(d => -(d.size * 10));Configure the Barnes-Hut approximation accuracy parameter.
/**
* Sets or gets the Barnes-Hut approximation criterion
* @param theta - Theta value (optional, defaults to 0.9)
* @returns Current theta value or force instance for chaining
*/
theta(theta?: number): number | ManyBodyForce;Usage Examples:
const chargeForce = forceManyBody();
// More accurate (slower) - smaller theta
chargeForce.theta(0.5);
// Less accurate (faster) - larger theta
chargeForce.theta(1.5);
// Default accuracy
chargeForce.theta(0.9);Configure minimum and maximum interaction distances.
/**
* Sets or gets the minimum distance between nodes for force calculation
* @param distance - Minimum distance (optional, defaults to 1)
* @returns Current minimum distance or force instance for chaining
*/
distanceMin(distance?: number): number | ManyBodyForce;
/**
* Sets or gets the maximum distance between nodes for force calculation
* @param distance - Maximum distance (optional, defaults to Infinity)
* @returns Current maximum distance or force instance for chaining
*/
distanceMax(distance?: number): number | ManyBodyForce;Usage Examples:
const chargeForce = forceManyBody();
// Prevent extreme forces when nodes are very close
chargeForce.distanceMin(5);
// Limit force range for localized effects
chargeForce.distanceMax(200);
// Combined configuration
chargeForce
.distanceMin(10)
.distanceMax(500);Create typical node repulsion for network diagrams:
const simulation = forceSimulation(nodes)
.force("charge", forceManyBody()
.strength(-300)
.distanceMin(1)
.distanceMax(Infinity)
)
.force("link", forceLink(links))
.force("center", forceCenter(400, 300));Assign different charges based on node properties:
const nodes = [
{ id: "A", type: "hub", size: 10 },
{ id: "B", type: "leaf", size: 3 },
{ id: "C", type: "leaf", size: 3 }
];
const simulation = forceSimulation(nodes)
.force("charge", forceManyBody()
.strength(d => {
if (d.type === "hub") return -500; // Strong repulsion for hubs
return -100; // Weaker repulsion for leaves
})
);Create attractive forces for clustering:
const simulation = forceSimulation(nodes)
.force("gravity", forceManyBody()
.strength(50) // Positive = attractive
.distanceMax(100) // Limit attraction range
)
.force("collision", forceCollide(5)); // Prevent overlapConfigure for better performance with many nodes:
const simulation = forceSimulation(largeNodeArray)
.force("charge", forceManyBody()
.strength(-30)
.theta(1.2) // Less accuracy for speed
.distanceMax(300) // Limit computation range
);Create multiple localized charge zones:
// Central repulsive force
const centralCharge = forceManyBody()
.strength(-200)
.distanceMax(150);
// Peripheral attractive force
const peripheralCharge = forceManyBody()
.strength(d => d.x * d.x + d.y * d.y > 100 * 100 ? 20 : 0)
.distanceMin(50)
.distanceMax(200);
simulation
.force("central-repulsion", centralCharge)
.force("peripheral-attraction", peripheralCharge);Change node charges based on user interaction or data updates:
const chargeForce = forceManyBody().strength(d => d.currentCharge || -30);
simulation.force("charge", chargeForce);
function updateNodeCharges(nodes, chargeData) {
nodes.forEach((node, i) => {
node.currentCharge = chargeData[i];
});
// Re-initialize force with new charge data
chargeForce.strength(d => d.currentCharge);
// Reheat simulation to apply new forces
simulation.alpha(0.3).restart();
}
// Example: Make clicked node strongly repulsive
function onNodeClick(clickedNode) {
clickedNode.currentCharge = -1000;
chargeForce.strength(d => d.currentCharge || -30);
simulation.alpha(0.5).restart();
}The Barnes-Hut approximation greatly improves performance by treating distant groups of nodes as single entities:
Many-body forces are calculated using inverse square law:
// Simplified force calculation
const dx = nodeB.x - nodeA.x;
const dy = nodeB.y - nodeA.y;
const distance = Math.sqrt(dx * dx + dy * dy);
const force = (strengthA * strengthB) / (distance * distance);
// Applied as velocity changes
nodeA.vx += (dx / distance) * force * alpha;
nodeA.vy += (dy / distance) * force * alpha;distanceMax can significantly improve performance for large graphs