CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-d3-force

Force-directed graph layout using velocity Verlet integration for simulating physical forces on particles

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

many-body.mddocs/

Many-Body Forces

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.

Capabilities

Many-Body Force Factory

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());

Strength Configuration

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));

Barnes-Hut Theta Configuration

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);

Distance Limits Configuration

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);

Common Usage Patterns

Standard Node Repulsion

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));

Variable Node Charges

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
    })
  );

Gravity Simulation

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 overlap

Performance-Optimized Large Networks

Configure 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
  );

Localized Force Fields

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);

Dynamic Charge Updates

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();
}

Barnes-Hut Approximation

The Barnes-Hut approximation greatly improves performance by treating distant groups of nodes as single entities:

  • Theta Parameter: Controls accuracy vs. speed trade-off
    • Lower theta (0.1-0.5): More accurate, slower computation
    • Higher theta (1.0-2.0): Less accurate, faster computation
  • Quadtree Structure: Nodes are organized in spatial quadtree for efficient range queries
  • Complexity: Reduces from O(n²) to O(n log n) per application

Force Calculation Details

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;

Performance Considerations

  • Distance Limits: Setting distanceMax can significantly improve performance for large graphs
  • Theta Tuning: Adjust theta based on required accuracy vs. performance needs
  • Strength Magnitude: Very large strength values can cause numerical instability
  • Node Count Scaling: Performance scales as O(n log n) with Barnes-Hut approximation

Key Characteristics

  • Global Effect: Unlike links, many-body forces affect all node pairs
  • Distance-Based: Force strength follows inverse square law
  • Directional: Forces are applied along the line connecting node pairs
  • Symmetric: Equal and opposite forces applied to both nodes in a pair
  • Configurable Range: Distance limits allow for localized or global effects

Default Values

  • strength: -30 (repulsive)
  • theta: 0.9
  • distanceMin: 1
  • distanceMax: Infinity

docs

centering.md

collision.md

index.md

links.md

many-body.md

positioning.md

simulation.md

tile.json