Code

D3.js

Force-Directed Graph

Advanced Interactive network graph powered by d3-force simulation. Drag any node to explore the layout. Forces: link distance, charge repulsion, center gravity, collision. d3-force

const simulation = d3.forceSimulation(nodes)
  .force('link',
    d3.forceLink(links)
      .id(d => d.id)
      .distance(60))
  .force('charge',
    d3.forceManyBody().strength(-120))
  .force('center',
    d3.forceCenter(cx, cy))
  .force('collide',
    d3.forceCollide(20))
  .on('tick', () => {
    // Update positions each tick
    links
      .attr('x1', d => d.source.x)
      .attr('y1', d => d.source.y)
      .attr('x2', d => d.target.x)
      .attr('y2', d => d.target.y);
    nodes
      .attr('cx', d => d.x)
      .attr('cy', d => d.y);
  });

// Drag to pin nodes
nodes.call(d3.drag()
  .on('start', (ev, d) => {
    if (!ev.active)
      simulation.alphaTarget(0.3).restart();
    d.fx = d.x; d.fy = d.y;
  })
  .on('drag', (ev, d) => {
    d.fx = ev.x; d.fy = ev.y;
  })
  .on('end', (ev, d) => {
    if (!ev.active)
      simulation.alphaTarget(0);
    d.fx = null; d.fy = null;
  }));
Key APIs
  • d3.forceSimulation(nodes) — creates and starts the physics simulation
  • d3.forceLink(links) — spring force along edges; .id() resolves string ids
  • d3.forceManyBody() — N-body charge (negative = repulsion)
  • d3.forceCenter(x, y) — gently pulls nodes toward the centre
  • d3.forceCollide(r) — prevents node overlap
  • simulation.on('tick', fn) — called each animation frame to update positions
  • d.fx / d.fy — fixed coordinates to pin a node during drag