Force-directed graph layout using velocity Verlet integration for simulating physical forces on particles
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
The collision force treats nodes as circles with configurable radius and prevents overlapping through iterative relaxation. It uses quadtree spatial partitioning for efficient collision detection and supports per-node radius configuration.
Creates a new collision force with specified radius configuration.
/**
* Creates a new collision force with the specified radius
* @param radius - Circle radius (number or accessor function, optional, defaults to 1)
* @returns CollideForce instance with configuration methods
*/
function forceCollide(radius?: number | ((d: Node, i: number, nodes: Node[]) => number)): CollideForce;Usage Examples:
import { forceCollide } from "d3-force";
// Fixed radius for all nodes
const collideForce = forceCollide(5);
// Variable radius based on node data
const collideForce = forceCollide(d => d.radius || 3);
// Default radius (1)
const collideForce = forceCollide();
// Add to simulation
simulation.force("collide", forceCollide(d => d.size * 2));Configure the collision radius for nodes.
/**
* Sets or gets the radius accessor for collision detection
* @param radius - Radius value or accessor function (optional)
* @returns Current radius accessor or force instance for chaining
*/
radius(radius?: number | ((d: Node, i: number, nodes: Node[]) => number)): ((d: Node, i: number, nodes: Node[]) => number) | CollideForce;Usage Examples:
const collideForce = forceCollide();
// Set fixed radius
collideForce.radius(10);
// Set variable radius based on node properties
collideForce.radius(d => d.size || 5);
// Complex radius calculation
collideForce.radius((d, i) => {
return Math.sqrt(d.value) * 3 + 2;
});
// Get current radius accessor
const currentRadius = collideForce.radius();Configure collision resolution strength.
/**
* Sets or gets the collision force strength
* @param strength - Strength value in range [0,1] (optional, defaults to 1)
* @returns Current strength or force instance for chaining
*/
strength(strength?: number): number | CollideForce;Usage Examples:
const collideForce = forceCollide(5);
// Full collision strength (hard collisions)
collideForce.strength(1);
// Soft collisions for smoother movement
collideForce.strength(0.7);
// Very soft collisions
collideForce.strength(0.3);Configure the number of collision resolution iterations per simulation tick.
/**
* Sets or gets the number of iterations per application
* @param iterations - Number of iterations (optional, defaults to 1)
* @returns Current iteration count or force instance for chaining
*/
iterations(iterations?: number): number | CollideForce;Usage Examples:
const collideForce = forceCollide(5);
// Single iteration (default, fastest)
collideForce.iterations(1);
// Multiple iterations for more rigid constraints
collideForce.iterations(3);
// High iteration count for very stable collisions
collideForce.iterations(5);Create non-overlapping bubble charts with variable sizes:
const bubbleData = [
{ name: "A", value: 100 },
{ name: "B", value: 200 },
{ name: "C", value: 50 }
];
const simulation = forceSimulation(bubbleData)
.force("collision", forceCollide()
.radius(d => Math.sqrt(d.value) * 0.5)
.strength(0.8)
.iterations(2)
)
.force("center", forceCenter(400, 300));Create tightly packed circles with minimal gaps:
const simulation = forceSimulation(nodes)
.force("collision", forceCollide()
.radius(d => d.radius + 1) // Small padding
.strength(1)
.iterations(4) // High iterations for tight packing
)
.force("center", forceCenter(width / 2, height / 2));Prevent node overlap in network diagrams:
const simulation = forceSimulation(nodes)
.force("link", forceLink(links))
.force("charge", forceManyBody())
.force("collision", forceCollide()
.radius(d => (d.children ? 10 : 5)) // Larger radius for parent nodes
.strength(0.9)
)
.force("center", forceCenter(400, 300));Create vertical or horizontal strips with collision:
// Horizontal beeswarm
const simulation = forceSimulation(data)
.force("x", forceX(d => xScale(d.value)).strength(0.8))
.force("y", forceY(height / 2).strength(0.1))
.force("collision", forceCollide()
.radius(3)
.strength(1)
.iterations(2)
);Update collision radius based on changing data:
const collideForce = forceCollide().radius(d => d.currentRadius);
simulation.force("collision", collideForce);
// Update radius and reheat simulation
function updateRadius(nodes, newRadiusData) {
nodes.forEach((node, i) => {
node.currentRadius = newRadiusData[i];
});
// Re-initialize force with new radius data
collideForce.radius(d => d.currentRadius);
// Reheat simulation to settle new configuration
simulation.alpha(0.3).restart();
}