---
title: D3 Force-Directed Layout
order: 8
---
## Overview
The D3Force layout is a force-directed layout based on [d3-force](https://d3js.org/d3-force). It simulates physical forces (such as attraction, repulsion, collision, etc.) to make the graph reach a stable state with minimal energy.
The main features of this layout are:
1. **Automatic arrangement**: No need to manually set node positions, the system will automatically find suitable positions
2. **Real-time adjustment**: When you drag a node, other nodes will adjust their positions in real time
3. **Flexible configuration**:
- You can adjust the attraction and repulsion between nodes
- You can set the ideal length of edges
- You can fix the positions of important nodes
4. **Animation effect**: Nodes move with smooth animation, making changes more natural
## Core Concepts
### Force System
The D3Force layout simulates five different forces to achieve automatic layout. Imagine a physical world where these forces act simultaneously and eventually reach equilibrium:
> Note: The arrows of different colors in the diagram represent different types of forces. In the actual layout, these forces are invisible and also affected by other forces.
- **Link Force**: Imagine nodes connected by rubber bands, which pull connected nodes to a suitable distance. The tightness of the rubber band is the force strength, and the ideal length is the distance we set.
- **Many-Body Force**: Similar to magnets, it allows all nodes to attract or repel each other. When the force strength is negative, nodes repel each other (like like poles of magnets); when positive, they attract (like opposite poles). This force determines the density of the graph.
- **Center Force**: Like all nodes are tied to the center of the canvas by an invisible string. This force prevents nodes from drifting too far and keeps the graph centered.
- **Collision Force**: Treats nodes as solid balls. When nodes get too close, they automatically bounce apart. This force mainly prevents node overlap and improves readability.
- **Radial Force**: Imagine an invisible ring that attracts nodes to the ring. By setting the radius and force strength, nodes can form a beautiful circular layout.
### Iteration System
Layout calculation is an iterative process with two key concepts:
#### Alpha Value (Energy)
Like the "energy" of the layout, it determines how vigorously nodes move:
- **Initial state**: Alpha = 1, nodes move vigorously
- **During calculation**: Alpha gradually decreases, node movement slows
- **End state**: When Alpha < alphaMin, nodes stop moving
#### Iterations
Controls the number of times forces are applied in each calculation:
- **Effect**: The larger the value, the more precise the layout, but the slower the computation
- **Adjustment**:
- Simple graphs: use the default value
- Complex graphs: increase the number of iterations as needed
- Real-time interaction: use fewer iterations
> Tip: Iterations and alpha value work together. Increasing iterations makes each step more precise, while alpha controls the overall progress.
## Options
| Property | Description | Type | Default | Required |
| --------------- | -------------------------------------------------- | ------------------------------------------ | ---------- | -------- |
| type | Layout type | string | 'd3-force' | ✓ |
| centerX | Layout center x coordinate | number | width / 2 | |
| centerY | Layout center y coordinate | number | height / 2 | |
| centerStrength | Center force strength | number | - | |
| nodeSize | Node size (diameter), for collision detection | number \| ((node, index, nodes) => number) | 10 | |
| nodeSpacing | Extra spacing between nodes | number \| ((node, index, nodes) => number) | 0 | |
| iterations | Number of force iterations, higher is more precise | number | - | |
| onTick | Callback for each iteration, for real-time results | (data: LayoutMapping) => void | - | |
| forceSimulation | Custom force simulation, defaults to d3.js method | Simulation | - | |
| randomSource | Function to generate random numbers | () => number | - | |
### Iteration Control
| Property | Description | Type | Default | Required |
| ------------- | ---------------------------------------------------- | ------ | ------- | -------- |
| alpha | Current convergence threshold, controls activity | number | 1 | |
| alphaMin | Minimum threshold to stop, when alpha < this, stop | number | 0.001 | |
| alphaDecay | Decay rate of alpha, [0, 1], 0.028 ≈ 300 iterations | number | 0.028 | |
| alphaTarget | Target alpha, system tries to converge to this value | number | 0 | |
| velocityDecay | Velocity decay factor, higher means slower movement | number | 0.4 | |
### Force Model Options
#### Link Force (link)
| Property | Description | Type | Default | Required |
| --------------- | -------------------------------------------- | ------------------------------------------ | ----------- | -------- |
| link.id | Function to generate edge id | (edge, index, edges) => string | (e) => e.id | |
| link.distance | Ideal edge length | number \| ((edge, index, edges) => number) | 30 | |
| link.strength | Force strength, higher means closer to ideal | number \| ((edge, index, edges) => number) | 1 | |
| link.iterations | Number of link force iterations | number | 1 | |
#### Many-Body Force (manyBody)
| Property | Description | Type | Default | Required |
| -------------------- | --------------------------------------------------------------- | ------------------------------------------ | -------- | -------- |
| manyBody.strength | Force strength, negative for repulsion, positive for attraction | number \| ((node, index, nodes) => number) | -30 | |
| manyBody.theta | Barnes-Hut accuracy, smaller is more accurate | number | 0.9 | |
| manyBody.distanceMin | Minimum distance, prevents excessive force | number | 1 | |
| manyBody.distanceMax | Maximum distance, beyond which no force is applied | number | Infinity | |
#### Center Force (center)
| Property | Description | Type | Default | Required |
| --------------- | --------------------------------------------- | ------ | ------- | -------- |
| center.x | Center x coordinate | number | - | |
| center.y | Center y coordinate | number | - | |
| center.strength | Force strength, higher means closer to center | number | - | |
> Note: In `5.1`, `centerX` / `centerY` are the recommended shortcut fields. If you configure the `center` force directly, it follows the native `d3-force` style.
#### Collision Force (collide)
| Property | Description | Type | Default | Required |
| ------------------ | ----------------------------------------------- | ------------------------------------------ | ------- | -------- |
| collide.radius | Collision radius, nodes repel if closer | number \| ((node, index, nodes) => number) | 10 | |
| collide.strength | Force strength, higher means stronger repulsion | number | 1 | |
| collide.iterations | Number of collision iterations | number | 1 | |
#### Radial Force (radial)
| Property | Description | Type | Default | Required |
| --------------- | --------------------------------------------- | ------------------------------------------ | ------- | -------- |
| radial.strength | Force strength, higher means closer to radius | number \| ((node, index, nodes) => number) | 0.1 | |
| radial.radius | Target radius, nodes are attracted to circle | number \| ((node, index, nodes) => number) | 100 | |
| radial.x | Center x coordinate | number | 0 | |
| radial.y | Center y coordinate | number | 0 | |
#### X Axis Force (x)
| Property | Description | Type | Default | Required |
| ---------- | ----------------------------------------- | ------------------------------------------ | ------- | -------- |
| x.strength | Force strength in x direction | number \| ((node, index, nodes) => number) | - | |
| x.x | Target x coordinate, nodes attracted here | number \| ((node, index, nodes) => number) | - | |
#### Y Axis Force (y)
| Property | Description | Type | Default | Required |
| ---------- | ----------------------------------------- | ------------------------------------------ | ------- | -------- |
| y.strength | Force strength in y direction | number \| ((node, index, nodes) => number) | - | |
| y.y | Target y coordinate, nodes attracted here | number \| ((node, index, nodes) => number) | - | |
## Code Examples
### Prevent Node Overlap
```js
{
layout: {
type: 'd3-force',
collide: {
// Prevent nodes from overlapping by specifying a collision radius for each node.
radius: (d) => d.size / 2,
},
},
}
```
See [Example - Prevent Node Overlap in Force-Directed Layout](/en/examples/layout/force-directed/#prevent-overlap)
### Team Clustering Layout
This example shows how to use force-directed layout for team clustering, where nodes of different teams automatically cluster together.
```js | ob { pin: false, inject: true }
import { Graph } from '@antv/g6';
const graph = new Graph({
container: 'container',
width: 500,
height: 250,
autoFit: 'view',
data: {
nodes: [
// Team A
{ id: 'A1', team: 'A', label: 'A1', size: 30 },
{ id: 'A2', team: 'A', label: 'A2', size: 20 },
{ id: 'A3', team: 'A', label: 'A3', size: 20 },
{ id: 'A4', team: 'A', label: 'A4', size: 20 },
// Team B
{ id: 'B1', team: 'B', label: 'B1', size: 30 },
{ id: 'B2', team: 'B', label: 'B2', size: 20 },
{ id: 'B3', team: 'B', label: 'B3', size: 20 },
{ id: 'B4', team: 'B', label: 'B4', size: 20 },
// Team C
{ id: 'C1', team: 'C', label: 'C1', size: 30 },
{ id: 'C2', team: 'C', label: 'C2', size: 20 },
{ id: 'C3', team: 'C', label: 'C3', size: 20 },
{ id: 'C4', team: 'C', label: 'C4', size: 20 },
],
edges: [
// Team A internal connections
{ source: 'A1', target: 'A2' },
{ source: 'A1', target: 'A3' },
{ source: 'A1', target: 'A4' },
// Team B internal connections
{ source: 'B1', target: 'B2' },
{ source: 'B1', target: 'B3' },
{ source: 'B1', target: 'B4' },
// Team C internal connections
{ source: 'C1', target: 'C2' },
{ source: 'C1', target: 'C3' },
{ source: 'C1', target: 'C4' },
// Few connections between teams
{ source: 'A1', target: 'B1' },
{ source: 'B1', target: 'C1' },
],
},
node: {
style: {
size: (d) => d.size,
fill: (d) => {
// Different colors for different teams
const colors = {
A: '#FF6B6B',
B: '#4ECDC4',
C: '#45B7D1',
};
return colors[d.team];
},
labelText: (d) => d.label,
labelPlacement: 'center',
labelFill: '#fff',
},
},
edge: {
style: {
stroke: '#aaa',
},
},
layout: {
type: 'd3-force',
// Configure link force - nodes within the same team are closer
link: {
distance: (d) => {
// Shorter distance within the same team
if (d.source.team === d.target.team) return 50;
// Longer distance between teams
return 200;
},
strength: (d) => {
// Stronger connection within the same team
if (d.source.team === d.target.team) return 0.7;
// Weaker connection between teams
return 0.1;
},
},
// Configure many-body force - control repulsion between nodes
manyBody: {
strength: (d) => {
// Team leader nodes (ending with 1) have stronger repulsion
if (d.label.endsWith('1')) return -100;
return -30;
},
},
// Configure collision force - prevent node overlap
collide: {
radius: 35,
strength: 0.8,
},
// Configure center force - keep the graph centered
center: {
strength: 0.05,
},
},
behaviors: ['drag-element-force'],
});
graph.render();
```
Show full code
```javascript
import { Graph } from '@antv/g6';
// Create mock data with nodes from different teams
const data = {
nodes: [
// Team A
{ id: 'A1', team: 'A', label: 'A1', size: 30 },
{ id: 'A2', team: 'A', label: 'A2', size: 20 },
{ id: 'A3', team: 'A', label: 'A3', size: 20 },
{ id: 'A4', team: 'A', label: 'A4', size: 20 },
// Team B
{ id: 'B1', team: 'B', label: 'B1', size: 30 },
{ id: 'B2', team: 'B', label: 'B2', size: 20 },
{ id: 'B3', team: 'B', label: 'B3', size: 20 },
{ id: 'B4', team: 'B', label: 'B4', size: 20 },
// Team C
{ id: 'C1', team: 'C', label: 'C1', size: 30 },
{ id: 'C2', team: 'C', label: 'C2', size: 20 },
{ id: 'C3', team: 'C', label: 'C3', size: 20 },
{ id: 'C4', team: 'C', label: 'C4', size: 20 },
],
edges: [
// Team A internal connections
{ source: 'A1', target: 'A2' },
{ source: 'A1', target: 'A3' },
{ source: 'A1', target: 'A4' },
// Team B internal connections
{ source: 'B1', target: 'B2' },
{ source: 'B1', target: 'B3' },
{ source: 'B1', target: 'B4' },
// Team C internal connections
{ source: 'C1', target: 'C2' },
{ source: 'C1', target: 'C3' },
{ source: 'C1', target: 'C4' },
// Few connections between teams
{ source: 'A1', target: 'B1' },
{ source: 'B1', target: 'C1' },
],
};
const graph = new Graph({
container: 'container',
data,
node: {
style: {
size: (d) => d.size,
fill: (d) => {
// Different colors for different teams
const colors = {
A: '#FF6B6B',
B: '#4ECDC4',
C: '#45B7D1',
};
return colors[d.team];
},
labelText: (d) => d.label,
labelPlacement: 'center',
labelFill: '#fff',
},
},
edge: {
style: {
stroke: '#aaa',
},
},
layout: {
type: 'd3-force',
// Configure link force - nodes within the same team are closer
link: {
distance: (d) => {
// Shorter distance within the same team
if (d.source.team === d.target.team) return 50;
// Longer distance between teams
return 200;
},
strength: (d) => {
// Stronger connection within the same team
if (d.source.team === d.target.team) return 0.7;
// Weaker connection between teams
return 0.1;
},
},
// Configure many-body force - control repulsion between nodes
manyBody: {
strength: (d) => {
// Team leader nodes (ending with 1) have stronger repulsion
if (d.label.endsWith('1')) return -100;
return -30;
},
},
// Configure collision force - prevent node overlap
collide: {
radius: 35,
strength: 0.8,
},
// Configure center force - keep the graph centered
center: {
strength: 0.05,
},
},
behaviors: ['drag-element-force'],
});
graph.render();
```
Main configuration notes:
- `link.distance`: Shorter within teams, longer between teams
- `link.strength`: Stronger within teams, weaker between teams
- `manyBody.strength`: Controls repulsion between nodes
- `collide`: Prevents node overlap
- `center`: Keeps the layout centered
See also [Customize parameters for different nodes](/en/examples/layout/force-directed/#functional-params).