Skip to content
D
Documentation

Instance and lifecycle

concept
2 min readUpdated

The DiagramInstance is the renderer-level facade: use it for specs, pixels, events, and lifecycle; use its model for data queries and its engine for behavior.

mermaid
flowchart TB
  Host["Mounted host element"] --> Instance["DiagramInstance"]
  Instance --> Model["DiagramModel\ndata: nodes, links, groups"]
  Instance --> Engine["DiagramEngine\nbehavior: layout, validation, history"]
  Instance --> Pixels["rendered pixels"]

Create the mounted instance

Create the instance with a real DOM container. The container needs a resolved height; a zero-height parent produces a blank canvas. The browser-only factory returns the same instance that framework bindings expose through their initialization callback.

The sample uses the shipped LIGHT_THEME for the initial appearance.

ts
import {
  createDiagram,
  LIGHT_THEME,
  type DiagramInstance,
} from '@grafloria/renderer';

const container = document.getElementById('diagram')!;
container.style.height = '400px';
const nodes = [
  { id: 'start', type: 'rect', position: { x: 40, y: 80 }, label: 'Start' },
  { id: 'finish', type: 'rect', position: { x: 260, y: 80 }, label: 'Finish' },
];

const instance: DiagramInstance = createDiagram(container, {
  nodes,
  theme: LIGHT_THEME,
});

The mounted diagram contains two boxes. Pass a different theme at creation or replace it later with setTheme().

The model is the data layer. Read it through DiagramModel when you need live nodes, links, or groups:

ts
import { createDiagram } from '@grafloria/renderer';

const container = document.getElementById('diagram')!;
container.style.height = '400px';
const instance = createDiagram(container, {
  nodes: [{ id: 'review', type: 'rect', position: { x: 40, y: 80 }, label: 'Review' }],
});
const model = instance.getModel();
const review = model.getNode('review');
const currentNodes = model.getNodes();

Use the DiagramEngine for behavior that is not an instance method, such as layout, validation, and history:

ts
import { createDiagram } from '@grafloria/renderer';

const container = document.getElementById('diagram')!;
container.style.height = '400px';
const instance = createDiagram(container, {
  nodes: [{ id: 'review', type: 'rect', position: { x: 40, y: 80 }, label: 'Review' }],
});
const engine = instance.getEngine();
const validation = engine.validateDiagram();

Do not call undo() on the instance. History belongs to the engine; call instance.getEngine().undo() instead. Layout also belongs to the engine, followed by renderNow() when you need the result painted before continuing.

Subscribe to changes

Subscribe on the instance with on(). It returns an unsubscribe function, so keep that function with the mounted instance and invoke it during teardown.

ts
import { createDiagram } from '@grafloria/renderer';

const container = document.getElementById('diagram')!;
container.style.height = '400px';
const instance = createDiagram(container, {
  nodes: [{ id: 'review', type: 'rect', position: { x: 40, y: 80 }, label: 'Review' }],
});
const stopSelection = instance.on('selection:change', ({ nodes: selectedNodes }) => {
  console.log('selected nodes:', selectedNodes.length);
});

const stopViewport = instance.on('viewport:change', ({ zoom }) => {
  console.log('zoom:', zoom);
});

function onUnmount(): void {
  stopSelection();
  stopViewport();
  instance.dispose();
}

The event map includes node and edge changes, selection, completed connections, reconnections, node and edge clicks, and viewport changes. The handlers receive live model objects where the event provides them; click events also include world coordinates. Use off() when you need to remove a handler by its original function instead of retaining the returned unsubscribe function.

Framework bindings dress the same event map in their own idiom: React uses callback props, Vue uses emits, Angular uses outputs for its component events, and the web element bubbles DOM events. Reach through to instance.on() when you need the common instance surface.

Dispose at unmount

Call dispose() from the host's unmount or close path, not immediately after setup. It releases the instance's rendering and interaction resources; the host then no longer owns a live diagram. Dispose subscriptions you manage separately when their API returns an unsubscribe function.

Was this page helpful?