# Layout and routing

Grafloria keeps graph intent in the model and derives node positions and link paths when it lays out and renders the diagram. You describe relationships such as “connect `api` to `wallets`” and “avoid obstacles”; you do not need to store the pixels that satisfy those relationships.

## How the parts work together

```mermaid
flowchart LR
  I["Nodes, groups, and edges"] --> M["DiagramModel: semantic document"]
  M --> L["DiagramEngine.layout()"]
  L --> P["Node positions"]
  M --> R["Router"]
  R --> Q["Link paths"]
  P --> V["Rendered diagram"]
  Q --> V
```

The model stores node and group relationships, ports, link endpoints, routing choices, and optional waypoints. A layout algorithm assigns positions from that information. The router then turns the endpoints and routing choice into a path. When a node moves, its links follow; an obstacle-avoiding route can recalculate around the new obstacle positions.

This separation also keeps persistence meaningful: save the document's intent and constraints, not a collection of coordinates that only describes one rendering.

## Describe relationships as data

Use [`render`](https://atloria.dev/p/grafloria-h7YM7amryF/developer/grafloria-element-core#render) to mount a real diagram and receive its [`DiagramInstance`](https://atloria.dev/p/grafloria-h7YM7amryF/developer/grafloria-renderer-instance-diagraminstance#diagraminstance). The sample uses an architecture layout so the nodes need no hand-written positions. The `source`, `target`, and `sourceHandle` fields express the relationship and attachment; `router` expresses how the path should travel.

```ts title="main.ts"
import { render } from '@grafloria/element';

const container = document.getElementById('diagram')!;
container.style.height = '400px';

const edges = [
  {
    id: 'api-to-wallets',
    source: 'api',
    target: 'wallets',
    sourceHandle: 'right',
    targetHandle: 'left',
    router: 'avoid',
    connector: 'rounded',
    label: 'requests',
  },
];

const instance = render(
  {
    layout: 'architecture',
    nodes: [
      { id: 'api', label: 'API', size: { width: 150, height: 70 } },
      { id: 'wall', label: 'Obstacle', size: { width: 150, height: 110 } },
      { id: 'wallets', label: 'Wallets', size: { width: 150, height: 70 } },
    ],
    edges,
  },
  container,
);

instance.fitView();
```

```html
<div id="diagram" style="height: 400px"></div>
```

The mounted instance shows labelled `API`, `Obstacle`, and `Wallets` nodes with a rounded, obstacle-aware `requests` link. `fitView()` frames the content in the sized container. The instance is the handle you keep when the application needs to repaint, query the model, or invoke the engine.

## Read `type` and `router` as separate decisions

An [`EdgeSpec`](https://atloria.dev/p/grafloria-h7YM7amryF/developer/grafloria-renderer-instance-edgespec#edgespec) answers two different questions:

- `type` describes the line's shape: direct, smooth, orthogonal, or bezier.
- `router` describes the path it takes: `straight`, `orthogonal`, `manhattan`, or `avoid`.

For example, an orthogonal edge can use the obstacle-avoiding router while retaining right-angle geometry:

```ts
const orthogonalEdge = {
  source: 'api',
  target: 'wallets',
  type: 'orthogonal',
  router: 'avoid',
  connector: 'rounded',
};
```

Leave handles out when the renderer can choose the default port facing the other node. Use a port id or a side such as `'right'` when the attachment is part of the diagram's meaning. Use `waypoints` only when the document must preserve explicit interior bends; those points are world coordinates, not a replacement for the relationship between the endpoints.

## Choose and rerun a layout

The [`DiagramEngine`](https://atloria.dev/p/grafloria-h7YM7amryF/developer/grafloria-engine-engine#diagramengine) owns layout behavior. Obtain it from the mounted instance and call `layout()` with a registered name and optional layout settings:

```ts
import { render } from '@grafloria/element';

const container = document.getElementById('diagram')!;
container.style.height = '400px';
const instance = render(
  {
    nodes: [
      { id: 'api', label: 'API' },
      { id: 'wallets', label: 'Wallets' },
    ],
    edges: [{ source: 'api', target: 'wallets', router: 'avoid' }],
  },
  container,
);

async function layOutLeftToRight(): Promise<void> {
  const engine = instance.getEngine();
  await engine.layout('dagre', { rankSpacing: 80 });
  instance.renderNow();
}

void layOutLeftToRight();
```

The call commits new node positions to the live model and returns a layout result; the repaint then shows the new positions and recomputed link routes. Calling `engine.layout()` with no name selects the automatic layout, while an unknown name throws instead of silently doing nothing.

The built-in choices cover common graph shapes: use `elk` or `dagre` for layered flows, `tree` for hierarchies, `force` or `community` for networks, and `grid`, `circular`, or `radial` for catalogs. Use `architecture` when zones and their internal rows are part of the visual structure rather than a ranking problem.

## What belongs in the document

Store the facts that remain true when the drawing changes:

- node and group ids, labels, data, ports, and membership;
- link endpoints, endpoint handles, labels, connector and router choices;
- deliberate waypoints when a user-edited bend must round-trip.

Do not treat the current node positions or generated route polyline as the graph's business meaning. A layout recomputes positions from the graph, and a router recomputes paths from endpoints, obstacles, anchors, and waypoints. This is why the same document can be laid out again after loading, resizing, or moving a node.

For a hand-edited edge, the endpoint remains semantic and the saved `points` or `waypoints` preserve the user's route. Reconnecting an endpoint runs connection validation again; bending a path updates the model and remains undoable through the shared command history.

## Related pages

- [How Grafloria works](https://atloria.dev/p/grafloria-h7YM7amryF/developer/how-grafloria-works)
- [Auto-layout a diagram](https://atloria.dev/p/grafloria-h7YM7amryF/developer/auto-layout-a-diagram)
- [Edit and route edges](https://atloria.dev/p/grafloria-h7YM7amryF/developer/edit-and-route-edges)
- [Ports and validation](https://atloria.dev/p/grafloria-h7YM7amryF/developer/ports-and-validation)
- [Model and document](https://atloria.dev/p/grafloria-h7YM7amryF/developer/model-and-document)
