Skip to content
D
Documentation

The graph model and document

concept
2 min readUpdated

A diagram is a model of nodes, ports, links, and groups; save that model as a document, then reconstruct it when you load the document.

One diagram, two layers

The DiagramModel holds diagram data: nodes, links, groups, and viewport state. The engine owns behavior such as commands, history, validation, and layout. Framework bindings accept convenient specs and turn them into live models; a rendered instance gives you access to the model behind its canvas.

The NodeModel represents an item with an identity, type, geometry, data, and ports. A node starts with four bidirectional ports, one on each side. Add a PortModel when a connection needs a specific direction, side, or other port-level configuration. Ports describe where a connection may attach and what constraints apply; they are not separate diagram nodes.

A LinkModel connects source and target ports. Its path type records the geometry intent; the renderer draws and routes the line. A GroupModel collects member entities into a container and can itself be nested in another group.

mermaid
flowchart LR
  Diagram["DiagramModel"] --> Nodes["NodeModel"]
  Nodes --> Ports["PortModel"]
  Links["LinkModel"] --> Ports
  Diagram --> Links
  Diagram --> Groups["GroupModel"]
  Groups --> Nodes

Mount a diagram and round-trip its document

Use render to mount the data spec and get a live instance. Read the model from that instance, serialize it with DiagramSerializer, then pass the saved JSON to fromDocument to reconstruct the model.

This browser example renders an order flow, serializes it, and reconstructs its model. Give the canvas a height so it has room to draw.

html
<div id="original" style="height: 360px"></div>
ts
import { DiagramSerializer } from '@grafloria/engine';
import { fromDocument, render } from '@grafloria/element';

const originalHost = document.getElementById('original')!;
originalHost.style.height = '360px';

const original = render(
  {
    nodes: [
      {
        id: 'intake',
        type: 'rect',
        position: { x: 40, y: 70 },
        size: { width: 130, height: 56 },
        label: 'Intake',
        data: { owner: 'Operations' },
      },
      {
        id: 'review',
        type: 'rect',
        position: { x: 250, y: 70 },
        size: { width: 130, height: 56 },
        label: 'Review',
        data: { owner: 'Finance' },
      },
    ],
    edges: [{ id: 'intake-review', source: 'intake', target: 'review' }],
    groups: [
      {
        id: 'approval',
        label: 'Approval',
        children: ['intake', 'review'],
        bounds: { x: 20, y: 30, width: 380, height: 150 },
      },
    ],
  },
  originalHost
);

const diagramModel = original.getModel();
const serializer = new DiagramSerializer();
const savedDocument = JSON.stringify(serializer.serializeEnvelope(diagramModel));
const restoredModel = fromDocument(savedDocument).model;
console.log('Restored node IDs:', restoredModel.getNodes().map((node) => node.id));

The canvas shows two labelled nodes joined by an edge inside the Approval group. The saved envelope contains the diagram model data, including nodes, links, groups, and viewport. fromDocument() accepts the JSON string and returns a loaded spec containing the restored model; the console lists its node IDs.

What the document contains

Serialization gives persistence one diagram-level format rather than separate node, edge, and group files. The flat model serialization includes a schema version, identity and metadata, the diagram name, nodes, links, groups, and viewport; each node entry includes its serialized ports. Strokes and comments are included when present. serializeEnvelope() wraps the diagram data with portable document metadata. deserialize() accepts the envelope as well as the flat serializer form, while fromDocument() turns a saved document into a renderable spec.

The document preserves model data and connection intent, not functions or an application's runtime. A custom-node painter is code and must be supplied again when loading a diagram that needs it. The renderer remains responsible for drawing and routing from the restored model.

Where to go next

Was this page helpful?

The graph model and document — Grafloria · GPT-6 Luna