Layout Engine

The Layout Engine provides automatic arrangement algorithms for organizing diagram elements.

Applying Layouts

// Apply layout to all items with ports
await app.diagramSystem.applyLayout(null, 'hierarchical', {
  direction: 'TB',
  levelSpacing: 100,
  nodeSpacing: 80
});

// Apply to specific items
await app.diagramSystem.applyLayout([item1, item2, item3], 'grid', {
  columns: 3
});

Layout Types

Hierarchical

Arranges items in levels based on connection hierarchy. Best for flowcharts and org charts.

await app.diagramSystem.applyLayout(items, 'hierarchical', {
  direction: 'TB',      // 'TB', 'BT', 'LR', 'RL'
  levelSpacing: 100,    // Space between levels
  nodeSpacing: 80,      // Space between siblings
  padding: 50           // Canvas padding
});

Directions:

Direction Description
TB Top to Bottom
BT Bottom to Top
LR Left to Right
RL Right to Left
// Top-down flowchart
await app.diagramSystem.applyLayout(items, 'hierarchical', {
  direction: 'TB'
});

// Left-to-right org chart
await app.diagramSystem.applyLayout(items, 'hierarchical', {
  direction: 'LR'
});

Force-Directed

Physics-based layout where connected nodes attract and unconnected nodes repel. Best for network diagrams and relationship graphs.

await app.diagramSystem.applyLayout(items, 'force-directed', {
  iterations: 100,      // Simulation steps
  repulsion: 5000,      // Node repulsion force
  attraction: 0.1,      // Edge attraction force
  damping: 0.9          // Velocity damping
});

Parameters:

Parameter Default Description
iterations 100 Number of simulation steps
repulsion 5000 Force pushing nodes apart
attraction 0.1 Force pulling connected nodes
damping 0.9 Velocity reduction per step

Tree

Dendrogram-style layout for hierarchical tree structures.

await app.diagramSystem.applyLayout(items, 'tree', {
  direction: 'TB',      // Layout direction
  levelSpacing: 100,    // Vertical/horizontal gap between levels
  nodeSpacing: 80,      // Gap between siblings
  padding: 50
});

Radial

Concentric circle layout with root nodes at center.

await app.diagramSystem.applyLayout(items, 'radial', {
  levelSpacing: 80,     // Radius increment per level
  padding: 50
});

Grid

Simple grid arrangement, useful for uniform positioning.

await app.diagramSystem.applyLayout(items, 'grid', {
  columns: 4,           // Auto-calculated if not set
  nodeSpacing: 80,      // Cell spacing
  padding: 50
});

Animation

Layouts can animate smoothly or apply instantly:

// Animated layout (default)
await app.diagramSystem.applyLayout(items, 'hierarchical', {
  animate: true,
  animationDuration: 300   // Milliseconds
});

// Instant layout
await app.diagramSystem.applyLayout(items, 'hierarchical', {
  animate: false
});

Layout Settings

Update default layout settings:

app.diagramSystem.layoutEngine.updateSettings({
  direction: 'LR',
  levelSpacing: 120,
  nodeSpacing: 100,
  padding: 60,
  animate: true,
  animationDuration: 400
});

Graph Analysis

The layout engine builds a graph from connectors:

// Build adjacency graph (internal method)
const graph = app.diagramSystem.layoutEngine.buildGraph(items);
// Returns: Map<item, connectedItems[]>

// Find root nodes (no incoming edges)
const roots = app.diagramSystem.layoutEngine.findRoots(graph, items);

// Assign levels via BFS
const levels = app.diagramSystem.layoutEngine.assignLevels(graph, roots);
// Returns: Map<item, levelNumber>

Canvas Bounds

Layouts automatically consider canvas size:

  • Items stay within canvas bounds with padding
  • Grid layout calculates optimal column count
  • Radial layout limits radius to fit
  • Hierarchical layout centers and scales if needed

Connector Updates

After layout, connectors are automatically refreshed:

// Layout moves items
await app.diagramSystem.applyLayout(items, 'hierarchical');
// Connectors automatically update their paths

Examples

Flowchart Layout

// Create flowchart shapes
const start = app.diagramSystem.createShape('terminal', { label: 'Start' });
const step1 = app.diagramSystem.createShape('process', { label: 'Step 1' });
const step2 = app.diagramSystem.createShape('process', { label: 'Step 2' });
const decision = app.diagramSystem.createShape('decision', { label: 'Check' });
const end = app.diagramSystem.createShape('terminal', { label: 'End' });

// Connect them
app.diagramSystem.connect(start, step1);
app.diagramSystem.connect(step1, step2);
app.diagramSystem.connect(step2, decision);
app.diagramSystem.connect(decision, end);

// Apply hierarchical layout
await app.diagramSystem.applyLayout(null, 'hierarchical', {
  direction: 'TB',
  levelSpacing: 100
});

Network Diagram

// Create network nodes
const cloud = app.diagramSystem.createShape('cloud', { label: 'Internet' });
const router = app.diagramSystem.createShape('server', { label: 'Router' });
const server1 = app.diagramSystem.createShape('server', { label: 'Web' });
const server2 = app.diagramSystem.createShape('server', { label: 'DB' });
const server3 = app.diagramSystem.createShape('server', { label: 'App' });

// Connect
app.diagramSystem.connect(cloud, router);
app.diagramSystem.connect(router, server1);
app.diagramSystem.connect(router, server2);
app.diagramSystem.connect(router, server3);
app.diagramSystem.connect(server1, server2);
app.diagramSystem.connect(server1, server3);

// Force-directed for natural spacing
await app.diagramSystem.applyLayout(null, 'force-directed', {
  iterations: 150,
  repulsion: 8000
});

Radial Org Chart

// Create org chart
const ceo = app.diagramSystem.createShape('process', { label: 'CEO' });
const vp1 = app.diagramSystem.createShape('process', { label: 'VP Sales' });
const vp2 = app.diagramSystem.createShape('process', { label: 'VP Eng' });
const vp3 = app.diagramSystem.createShape('process', { label: 'VP Ops' });
// ... more nodes

// Connect hierarchy
app.diagramSystem.connect(ceo, vp1);
app.diagramSystem.connect(ceo, vp2);
app.diagramSystem.connect(ceo, vp3);

// Radial layout places CEO at center
await app.diagramSystem.applyLayout(null, 'radial', {
  levelSpacing: 120
});
// Create items without connections
const items = [];
for (let i = 0; i < 12; i++) {
  items.push(app.diagramSystem.createShape('rectangle', {
    label: `Item ${i + 1}`
  }));
}

// Grid layout with 4 columns
await app.diagramSystem.applyLayout(items, 'grid', {
  columns: 4,
  nodeSpacing: 100
});

Performance

Layout Type Complexity Best For
Grid O(n) Any size
Hierarchical O(n log n) < 200 nodes
Tree O(n log n) < 200 nodes
Radial O(n log n) < 100 nodes
Force-Directed O(n²) per iteration < 50 nodes

For large diagrams (100+ nodes), use hierarchical or grid layouts for best performance.