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.
mermaidflowchart 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>
tsimport { 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
- Configure ports for port direction, positioning, and connection options.
- Route and edit edges for link geometry and routing.
- Group nodes and containers for group membership and nesting.
- Import and round-trip diagrams for persistence and text formats.
Was this page helpful?