Learn / The model
The model
Everything in Grafloria — the React component, the Angular canvas, the web component — is a thin skin over one headless model in @grafloria/engine. Understand the model once and every binding makes sense.
Two layers, one truth
The engine (DiagramEngine) owns behavior: commands, history,
layout, validation, collaboration. The diagram (DiagramModel) owns
the data: nodes, links, groups, viewport. The framework bindings hand you a friendlier
spec layer ({ id, position, data, ports } objects), convert it to
models internally, and hand models back in change events. This page is the layer
underneath — it runs identically in the browser, in a worker, and in Node (the snippets
below execute in plain Node against the published package).
import { DiagramEngine, NodeModel, PortModel, LinkModel } from '@grafloria/engine';
const engine = new DiagramEngine();
const diagram = engine.createDiagram('order-flow');
const intake = new NodeModel({
id: 'intake', type: 'task',
position: { x: 40, y: 60 }, size: { width: 120, height: 48 },
});
intake.setData('label', 'Intake');
const review = new NodeModel({
id: 'review', type: 'task',
position: { x: 260, y: 60 }, size: { width: 120, height: 48 },
});
review.setData('label', 'Review');
diagram.addNode(intake);
diagram.addNode(review);
diagram.addLink(new LinkModel({
id: 'l1',
source: { nodeId: 'intake' },
target: { nodeId: 'review' },
}));
Nodes
A node is an id, a type (which selects its renderer — a shape, a custom
component, a template), geometry (position, size), and two
open dictionaries: data for your payload
(setData/getData) and metadata for
Grafloria-adjacent settings (label, shape styling, port groups). In the framework spec
layer, label: 'Intake' and data: { label: 'Intake' } are the
convenient front doors to the same places.
Ports — four by default, precise on demand
Every node is born with four deterministic bi-directional ports (top, right, bottom, left) — the industry default, so plain flowcharts need zero port ceremony. The moment you need precision, add your own:
intake.addPort(new PortModel({ id: 'intake-out', type: 'output', side: 'right' }));
// reach them later
intake.getPorts(); // all ports
intake.getPortBySide('right');
diagram.getPortById('intake-out');
diagram.getNodeByPortId('intake-out');
A port has a direction (input / output / bi),
a side, an optional dataType (drives both its color and connection
compatibility), connection caps, glyph shape, label, and layout strategy. The full
surface is on Ports & validation.
Links
A link connects two endpoints. Each endpoint names a node — and optionally a specific
port; omit portId and the renderer picks the best side as things move:
new LinkModel({
id: 'l1',
source: { nodeId: 'intake', portId: 'intake-out' }, // pinned to a port
target: { nodeId: 'review' }, // free — best side wins
});
diagram.getLinksForNode('intake'); // every link touching a node
In the spec layer this is just { source: 'intake', target: 'review' } —
with sourceHandle/targetHandle to pin ports, and
type: 'orthogonal' | 'smooth' | 'bezier' | 'direct' to pick geometry.
Routing (including the obstacle-avoiding router) is the renderer's job; the model stores
intent, not pixels.
Groups
Groups are containers with real semantics — membership
(engine.addToGroup), collective drag, collapse/expand
(engine.collapseGroup), and nesting
(diagram.getAncestors/getDescendants). A group can render with
full chrome or frameless (frameChrome: 'none') for dashboard-style
packing.
Serialization — the document is the API
The whole diagram round-trips through one JSON document with a
schemaVersion and migrations on load — save it anywhere:
const doc = diagram.serialize();
// { schemaVersion, id, uuid, type, version, metadata, name, nodes, links, groups, viewport }
const engine2 = new DiagramEngine();
engine2.createDiagram('restored');
engine2.deserialize(doc);
engine2.getDiagram().getNode('intake').getData('label'); // 'Intake' — everything survives
snapshot()/loadSnapshot()
(Angular), DiagramSerializer (React/Vue), SVG/PNG embedModel
export, and the collaboration op-log all speak. There is exactly one persistence format
to learn.Where next
- Ports & validation — the full port spec and connection rules.
- Commands & undo — why mutations are objects.
- Mermaid & the text format — the second, human-writable serialization.