or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

behaviors.mddata-management.mdelements.mdevents.mdgraph-runtime.mdindex.mdlayouts.mdplugins.mdtypes.md
tile.json

layouts.mddocs/

Layout Algorithms

G6 provides a comprehensive collection of layout algorithms for automatic graph positioning. Layouts can be executed synchronously or asynchronously, with extensive configuration options for different graph types and use cases.

Layout Configuration

Basic Layout Setup

import { Graph } from '@antv/g6';
import type { LayoutOptions } from '@antv/g6';

// Simple layout configuration
const graph = new Graph({
  layout: {
    type: 'force',
    preventOverlap: true,
    nodeSize: 30
  }
});

// Advanced layout configuration
const graph = new Graph({
  layout: {
    type: 'd3-force',
    linkDistance: 100,
    nodeStrength: -300,
    edgeStrength: 0.6,
    preventOverlap: true,
    nodeSize: (node) => node.data?.size || 20,
    animation: {
      duration: 1000,
      easing: 'ease-out'
    }
  }
});

Dynamic Layout Execution

// Set and execute layout
await graph.setLayout({
  type: 'circular',
  radius: 200,
  startRadius: 50,
  endRadius: 300
});

await graph.layout(); // Execute current layout

// Execute layout with custom options
await graph.layout({
  type: 'grid',
  cols: 5,
  rows: 4,
  sortBy: 'degree'
});

// Stop running layout
graph.stopLayout();

// Get current layout configuration
const currentLayout = graph.getLayout();

Force-Directed Layouts

D3 Force Layout

import type { D3ForceLayoutOptions } from '@antv/g6';

interface D3ForceLayoutOptions {
  type: 'd3-force';
  
  // Node forces
  nodeStrength?: number | ((node: NodeData) => number); // Node repulsion strength (-300)
  nodeSize?: number | ((node: NodeData) => number);     // Node size for collision
  
  // Edge forces  
  edgeStrength?: number | ((edge: EdgeData) => number); // Edge attraction strength (0.6)
  linkDistance?: number | ((edge: EdgeData) => number); // Desired edge length (100)
  
  // Simulation parameters
  alpha?: number;                      // Initial energy (1)
  alphaDecay?: number;                 // Energy decay rate (0.0228)
  alphaMin?: number;                   // Minimum energy (0.001)
  velocityDecay?: number;              // Velocity decay (0.4)
  
  // Positioning
  center?: [number, number];           // Layout center
  preventOverlap?: boolean;            // Prevent node overlapping
  
  // Animation
  animation?: boolean | {
    duration?: number;
    easing?: string;
  };
  
  // Event callbacks
  onLayoutStart?: () => void;
  onLayoutEnd?: () => void;
  onTick?: (progress: number) => void;
}

const d3ForceLayout = {
  type: 'd3-force',
  nodeStrength: (node) => -300 * (node.data?.importance || 1),
  edgeStrength: 0.8,
  linkDistance: (edge) => edge.data?.distance || 100,
  preventOverlap: true,
  nodeSize: 20,
  animation: {
    duration: 2000,
    easing: 'ease-in-out'
  },
  onTick: (progress) => {
    console.log(`Layout progress: ${Math.round(progress * 100)}%`);
  }
};

Classical Force Layout

import type { ForceLayoutOptions } from '@antv/g6';

const forceLayout = {
  type: 'force',
  preventOverlap: true,
  nodeSize: 30,
  nodeSpacing: (node) => node.data?.spacing || 10,
  linkDistance: 150,
  nodeStrength: -500,
  edgeStrength: 200,
  collideStrength: 0.8,
  center: [400, 300],
  animation: true
};

Force Atlas 2 Layout

import type { ForceAtlas2LayoutOptions } from '@antv/g6';

const forceAtlas2Layout = {
  type: 'forceAtlas2',
  kr: 5,                              // Repulsive force strength
  kg: 1,                              // Gravitational force strength
  mode: 'normal',                     // 'normal' | 'linlog'
  preventOverlap: true,
  dissuadeHubs: false,                // Reduce hub node influence
  linLogMode: false,                  // Lin-log mode
  strongGravityMode: false,           // Strong gravity mode
  gravity: 1,                         // Gravity strength
  ks: 0.1,                           // Speed multiplier
  ksMax: 10,                         // Maximum speed
  tao: 0.1,                          // Convergence threshold
  maxIteration: 1000                 // Maximum iterations
};

Hierarchical Layouts

Dagre Layout

import type { DagreLayoutOptions } from '@antv/g6';

interface DagreLayoutOptions {
  type: 'dagre';
  rankdir?: 'TB' | 'BT' | 'LR' | 'RL';  // Layout direction
  ranksep?: number;                      // Rank separation (50)
  nodesep?: number;                      // Node separation (50)  
  controlPoints?: boolean;               // Use control points (true)
  
  // Node sizing
  nodeSize?: number | [number, number] | ((node: NodeData) => number | [number, number]);
  
  // Sorting and ranking
  sortByCombo?: boolean;                 // Sort by combo membership
  radial?: boolean;                      // Radial layout mode
}

const dagreLayout = {
  type: 'dagre',
  rankdir: 'TB',                        // Top to bottom
  ranksep: 70,
  nodesep: 50,
  nodeSize: [60, 40],
  controlPoints: true,
  sortByCombo: false
};

// Radial dagre layout
const radialDagreLayout = {
  type: 'dagre',
  radial: true,
  focusNode: 'root-node',
  unitRadius: 100,
  linkDistance: 150
};

AntV Dagre Layout

const antvDagreLayout = {
  type: 'antv-dagre',
  rankdir: 'LR',                        // Left to right
  ranksep: 80,
  nodesep: 40,
  nodeSize: [80, 60],
  preventOverlap: true
};

Tree Layouts

Compact Box Layout

import type { CompactBoxLayoutOptions } from '@antv/g6';

const compactBoxLayout = {
  type: 'compactBox',
  direction: 'LR',                      // 'LR' | 'RL' | 'TB' | 'BT'
  getId: (node) => node.id,
  getHeight: () => 32,
  getWidth: () => 60,
  getVGap: () => 16,                    // Vertical gap
  getHGap: () => 32,                    // Horizontal gap
  radial: false                         // Enable radial mode
};

// Radial compact box layout
const radialCompactBoxLayout = {
  type: 'compactBox',
  direction: 'LR',
  radial: true,
  focusNode: 'root'
};

Dendrogram Layout

const dendrogramLayout = {
  type: 'dendrogram',
  direction: 'TB',                      // Tree direction
  nodeSep: 36,                          // Node separation
  rankSep: 128,                         // Rank separation
  radial: false
};

Indented Layout

const indentedLayout = {
  type: 'indented',
  direction: 'LR',
  indent: 30,                           // Indentation distance
  getHeight: () => 16,
  getWidth: () => 100
};

Mindmap Layout

const mindmapLayout = {
  type: 'mindmap',
  direction: 'H',                       // 'H' (horizontal) | 'V' (vertical)
  getHeight: () => 32,
  getWidth: () => 80,
  getVGap: () => 16,
  getHGap: () => 24,
  getSide: (node) => {
    // Determine which side of the root (for H direction)
    return node.data?.side || 'right';
  }
};

Circular and Radial Layouts

Circular Layout

import type { CircularLayoutOptions } from '@antv/g6';

const circularLayout = {
  type: 'circular',
  center: [400, 300],                   // Circle center
  radius: 200,                          // Circle radius
  startRadius: 50,                      // Starting radius (for spiral)
  endRadius: 300,                       // Ending radius (for spiral)
  clockwise: true,                      // Clockwise arrangement
  divisions: 1,                         // Number of divisions
  ordering: 'topology',                 // 'topology' | 'degree' | null
  angleRatio: 1                         // Angle ratio for partial circle
};

Radial Layout

const radialLayout = {
  type: 'radial',
  focusNode: 'center-node',            // Focus node ID
  unitRadius: 100,                     // Unit radius between levels
  linkDistance: 150,                   // Edge length
  maxIteration: 1000,                  // Maximum iterations
  preventOverlap: true,
  nodeSize: 30,
  strictRadial: true                   // Strict radial positioning
};

Concentric Layout

const concentricLayout = {
  type: 'concentric',
  center: [400, 300],
  nodeSize: 30,
  minNodeSpacing: 10,                  // Minimum space between nodes
  preventOverlap: true,
  sweep: Math.PI * 2,                  // Angular sweep
  equidistant: false,                  // Equal distances between levels
  startAngle: 0,                       // Starting angle
  clockwise: true,
  maxLevelDiff: undefined,             // Maximum level difference
  sortBy: 'degree'                     // Sorting criteria
};

Grid and Geometric Layouts

Grid Layout

import type { GridLayoutOptions } from '@antv/g6';

const gridLayout = {
  type: 'grid',
  rows: 5,                             // Number of rows
  cols: 4,                             // Number of columns
  center: [400, 300],                  // Grid center
  width: 600,                          // Grid width
  height: 400,                         // Grid height
  preventOverlap: true,
  nodeSize: 30,
  sortBy: 'degree',                    // 'degree' | 'clustering' | custom function
  condense: false,                     // Condense to smaller area
  position: (node, i) => {             // Custom positioning function
    return [i % 4 * 100, Math.floor(i / 4) * 100];
  }
};

Random Layout

const randomLayout = {
  type: 'random',
  center: [400, 300],
  width: 600,
  height: 400,
  preventOverlap: true,
  nodeSize: 30
};

Specialized Layouts

MDS Layout (Multidimensional Scaling)

const mdsLayout = {
  type: 'mds',
  center: [400, 300],
  linkDistance: 200,                   // Desired edge length
  preventOverlap: true,
  nodeSize: 30
};

Fruchterman Layout

const fruchtermanLayout = {
  type: 'fruchterman',
  center: [400, 300],
  maxIteration: 1000,
  gravity: 10,                         // Gravity strength
  speed: 5,                            // Speed multiplier
  clustering: true,                    // Enable clustering
  clusterGravity: 10                   // Cluster gravity strength
};

Custom G6 Layouts

// Fishbone Layout (for cause-effect diagrams)
const fishboneLayout = {
  type: 'fishbone',
  direction: 'LR',
  main: 'main-branch',                 // Main branch node
  hGap: 50,                           // Horizontal gap
  vGap: 30                            // Vertical gap
};

// Snake Layout
const snakeLayout = {
  type: 'snake',
  direction: 'horizontal',             // 'horizontal' | 'vertical'
  cols: 5,
  colGap: 20,
  rowGap: 20
};

Combo-Aware Layouts

Combo Combined Layout

const comboCombinedLayout = {
  type: 'comboCombined',
  center: [400, 300],
  // Inner layout for nodes within combos
  innerLayout: {
    type: 'grid',
    cols: 3
  },
  // Outer layout for combos themselves  
  outerLayout: {
    type: 'circular',
    radius: 200
  },
  spacing: [30, 30],                   // [combo spacing, node spacing]
  preventOverlap: true
};

Layout Utilities and Controls

Layout Execution Control

// Progressive layout with progress tracking
await graph.layout({
  type: 'd3-force',
  animation: true,
  onTick: (progress) => {
    console.log(`Progress: ${progress}`);
    updateProgressBar(progress);
  },
  onLayoutEnd: () => {
    console.log('Layout completed');
  }
});

// Stop layout execution
graph.stopLayout();

// Check if layout is running
const isLayoutRunning = graph.isLayoutRunning?.();

Layout Combinations

// Sequential layout execution
await graph.layout({ type: 'grid' });      // Initial positioning
await graph.layout({ type: 'force' });     // Refinement with force

// Conditional layouts based on graph size
const nodeCount = graph.getNodeData().length;
const layoutType = nodeCount > 100 ? 'grid' : 'force';

await graph.layout({
  type: layoutType,
  animation: nodeCount < 50
});

Custom Layout Functions

import { invokeLayoutMethod } from '@antv/g6';

// Invoke layout utility functions
const layoutResult = invokeLayoutMethod(
  { type: 'circular', radius: 200 },
  graph.getData()
);

// Apply custom positioning logic
const customPositions = graph.getNodeData().map((node, i) => ({
  id: node.id,
  x: Math.cos(i * 0.5) * 200,
  y: Math.sin(i * 0.5) * 200
}));

await graph.updateNodeData(customPositions);

Type Definitions

interface LayoutOptions {
  type: string;                        // Layout algorithm type
  animation?: boolean | {
    duration?: number;
    easing?: string;
  };
  onLayoutStart?: () => void;
  onLayoutEnd?: () => void;
  onTick?: (progress: number) => void;
  [key: string]: any;                  // Algorithm-specific options
}

interface BaseLayoutOptions {
  center?: [number, number];           // Layout center point
  nodeSize?: number | number[] | ((node: NodeData) => number | number[]);
  preventOverlap?: boolean;            // Prevent node overlapping
  animation?: boolean | AnimationConfig;
}

interface ForceLayoutOptions extends BaseLayoutOptions {
  type: 'force' | 'd3-force' | 'forceAtlas2';
  nodeStrength?: number | ((node: NodeData) => number);
  edgeStrength?: number | ((edge: EdgeData) => number);
  linkDistance?: number | ((edge: EdgeData) => number);
  alpha?: number;
  alphaDecay?: number;
  velocityDecay?: number;
}

interface HierarchicalLayoutOptions extends BaseLayoutOptions {
  type: 'dagre' | 'compactBox' | 'dendrogram' | 'indented' | 'mindmap';
  direction?: 'TB' | 'BT' | 'LR' | 'RL';
  rankSep?: number;
  nodeSep?: number;
  ranksep?: number;
  nodesep?: number;
}

interface CircularLayoutOptions extends BaseLayoutOptions {
  type: 'circular' | 'radial' | 'concentric';
  radius?: number;
  startRadius?: number;
  endRadius?: number;
  focusNode?: string;
  unitRadius?: number;
  clockwise?: boolean;
}

interface GridLayoutOptions extends BaseLayoutOptions {
  type: 'grid';
  rows?: number;
  cols?: number;
  width?: number;
  height?: number;
  sortBy?: 'degree' | 'clustering' | ((a: NodeData, b: NodeData) => number);
}