# Layout and routing

```mermaid
flowchart LR
  S["Node and edge specs"] --> M["Diagram model"]
  M --> L["Layout algorithm"]
  L --> P["Node positions"]
  P --> R["Edge router"]
  M --> R
  R --> G["Routed edge geometry"]
  P --> V["Renderer"]
  G --> V
```

## Layout arranges nodes

Use the mounted [`DiagramInstance`](https://bench-grafloria-56.atloria.app/p/bench-grafloria-56-62cg8vR5rF/developer/grafloria-renderer-instance-diagraminstance#diagraminstance) to reach the engine that owns layout and to render the resulting positions.

The layout algorithm reads the graph's relationships, groups, and node sizes. It writes positions, not new relationships. Choose a layout according to the graph:

| Graph | Algorithm | Result |
| --- | --- | --- |
| Flowcharts, pipelines, and DAGs | `elk`, `layered`, or `dagre` | Layered ranking with fewer crossings; ELK also handles ports and nesting. |
| Architecture diagrams with zones | `architecture` | Regions on a grid, sized boxes in rows, and bends in gutters. |
| Hierarchies and org charts | `tree` | Tidy, parent-centered placement. |
| Networks and clusters | `force`, `community`, or `spectral` | Physical spread or community-oriented placement. |
| Catalogs and galleries | `grid`, `circular`, or `radial` | Uniform placement. |
| An unknown graph shape | `auto` | Graph classification followed by algorithm selection. |

## Routing turns edge intent into geometry

See the [JavaScript quick start](https://bench-grafloria-56.atloria.app/p/bench-grafloria-56-62cg8vR5rF/developer/javascript-quick-start) for the complete [`EdgeSpec`](https://bench-grafloria-56.atloria.app/p/bench-grafloria-56-62cg8vR5rF/developer/grafloria-renderer-instance-edgespec#edgespec) shape and how `source` and `target` identify the endpoints. This page adds the routing choice: set `router` to change the edge geometry without changing the relationship:

```ts
import type { EdgeSpec } from '@grafloria/renderer';

const edges: EdgeSpec[] = [
  {
    id: 'request',
    source: 'client',
    target: 'service',
    router: 'avoid',
    label: 'request',
  },
];
```

`router` answers “which path does the line take?” The shipped routers provide these choices:

| Router | Path behavior |
| --- | --- |
| `straight` | Direct line between the endpoints. |
| `orthogonal` | Right-angled path from the port's exit direction. |
| `manhattan` | Grid-based right-angle routing with turn minimization. |
| `avoid` | Walks around obstacles and re-routes as nodes move. |
| `elk` | Uses ELK edge routing for an ELK-laid-out graph. |

Use `waypoints` or `points` when the route has explicit bends. Handles can name a port, a side such as `'right'`, or a position along a side such as `'right@36'`. If you omit both handles, the edge uses the default port facing its partner as nodes move.

## Declarative layout and explicit re-layout

Bindings can receive a layout value at mount time. The binding re-runs layout when that value changes, but not when node data changes. That prevents a user drag from being immediately overwritten by an automatic re-layout.

When relationship or node data changes after mount, call the engine's `layout()` explicitly and then render:

```ts
import type { DiagramInstance } from '@grafloria/renderer';

export async function reflowAfterDataChange(instance: DiagramInstance): Promise<void> {
  await instance.getEngine().layout('elk');
  instance.renderNow();
}
```

For an already-laid-out graph, incremental layout moves only the neighborhood of inserted nodes instead of scrambling the whole mental map. Use the full layout when you want a new global arrangement; use incremental layout when preserving the existing arrangement matters.

## Extend routing only when the shipped routers are insufficient

The engine exposes a [`RoutingEngine`](https://bench-grafloria-56.atloria.app/p/bench-grafloria-56-62cg8vR5rF/developer/grafloria-engine-routing#routingengine) for extension. A custom [`IRouter`](https://bench-grafloria-56.atloria.app/p/bench-grafloria-56-62cg8vR5rF/developer/grafloria-engine-routing#irouter) supplies `route()` and `getName()`; register it with `registerRouter()`, then select its name through an edge's `router` value. A per-edge router choice is sufficient when one of the shipped algorithms provides the required geometry.

## Pitfall: data changes do not re-run layout

Changing node data does not re-run the declarative `layout` value. Invoke the engine's `layout()` explicitly, then render. Automatic re-layout on every data change would fight user dragging.

## Live examples

- [Layout demos](https://grafloria.com/demos/diagrams/architecture-layout.html) compare architecture and layered layout on the same text.
- [Edge routing demo](https://grafloria.com/demos/#edges) shows edge types, routers, and connectors on a mounted diagram.

See [How Grafloria works](https://bench-grafloria-56.atloria.app/p/bench-grafloria-56-62cg8vR5rF/developer/how-grafloria-works), [Apply auto-layout](https://bench-grafloria-56.atloria.app/p/bench-grafloria-56-62cg8vR5rF/developer/apply-auto-layout), and [Route and edit edges](https://bench-grafloria-56.atloria.app/p/bench-grafloria-56-62cg8vR5rF/developer/route-and-edit-edges) for the surrounding model, layout procedure, and edge-editing workflows.
