Import it from @grafloria/renderer.
tsinterface DiagramInstance
Properties
| Name | Type | Default | Description |
|---|---|---|---|
viewport | ViewportController | ||
interaction | InteractionController | ||
animations | AnimationService | The renderer's animation service. Host policy lives here: global enable/speed, reduced-motion overrides, and the battery-saver auto-toggle (updateConfig({ respectBatteryStatus: false }) to opt out — on by default, and on a low unplugged battery it disables edge animations). | |
registry | DiagramRegistry | THIS diagram's contribution registry — shapes, named styles, link/label templates, markers, anchors, connection points, connectors, animations. The module-level registerShape() / defineStyle() / … remain the PROCESS-WIDE registry and still work exactly as before; this one shadows it for this diagram only. That distinction is the whole reason it exists: the registries used to be module-scope `M | |
container | HTMLElement | Escape hatches for hosts and tests. | |
scheduler | RenderScheduler | ||
patcher | VNodePatcher |
Members
setNodes(nodes: NodeInput[]): voidsetEdges(edges: EdgeInput[]): voidsetGroups(groups: Array<GroupSpec | GroupModel>): void— Reconcile the zones (groups) — add, restyle, remove. Removing a zone keeps its boxes.getModel(): DiagramModelgetEngine(): DiagramEnginegetCommentStore(): CommentStore | null— The comment store, whencommentswas enabled;nullotherwise.on<K extends DiagramEventName>(event: K, handler: DiagramEventHandler<K>): Unsubscribeoff<K extends DiagramEventName>(event: K, handler: DiagramEventHandler<K>): voidsetTheme(theme: Theme): void— Theme swap (re-injects this instance's CSS variable block only).setColorMode(mode: ColorMode, themes?: ThemeSet): void— Follow the OS colour scheme ('system'), or pin light/dark.
'system' also honours prefers-contrast: more and forced-colors by
upgrading to the high-contrast theme — an accessibility preference outranks
an aesthetic one.
getColorMode(): ColorMode | undefinedsetTokenBridge(bridge: TokenBridge | null | undefined): void— Re-point Grafloria's CSS variables at the host design system's tokens.setHighlightConnected(value: boolean | HighlightConnectedOptions): void— Turn the selected nodes' line highlight on (true, or options) or off (false) — seeCreateDiagramOptions.highlightConnected. Repaints.setHighlighterConfig(value: boolean | Partial<HighlighterConfig>): void— Turn the outline layer on (true, or an object of kinds) or off (false) — seeCreateDiagramOptions.highlighterConfig. Repaints.getHighlightConnected(): boolean | HighlightConnectedOptions— The currenthighlightConnectedsetting (falsewhen off).export(format?: ExportFormat, options?: ExportOptions): Promise<string>— Export the CURRENT view.'svg'returns SVG source;'png' | 'jpeg' | 'webp' | 'pdf'return adata:URL.
Pass { embedModel: true } (PNG and SVG) and the diagram model rides inside
the artifact — the exported file re-opens as an editable diagram.
THE ASYNC ONE, and the only one. If a custom node's renderCustomNode returned a
promise — "I draw later: a rAF, a fetch, a framework's render, a web font" — this
waits for it before reading the host, bounded by
{@link ExportOptions.customNodeTimeout}. The synchronous entry points below cannot,
and say so in their warnings. Read the fidelity report through
{@link ExportOptions.onWarnings}, which fires on every format.
exportSvgString(options?: ExportOptions): SvgExportResult— Synchronous, DOM-free, deterministic. Carrieswarnings.
Synchronous means a widget whose painter is still running is captured as it stands
and REPORTED, not waited for — await export('svg') is the entry point that waits.
exportPdf(options?: ExportOptions): PdfExportResult— A real vector PDF: paths stay paths, text stays selectable text.getQualityState(): { tier: LODLevel; governor?: GovernorState }— The LOD tier actually rendered, and the adaptive governor's last verdict.fitView(padding?: number): void— Frame all content.render(): void— Queue a repaint (coalesced into one frame).renderNow(): void— Repaint synchronously — use when you must measure right after a change.batchUpdate(mutate: (model: DiagramModel) => void): void— Apply many mutations as ONE frame.
tsdiagram.batchUpdate((model) => {
for (const n of model.getNodes()) n.setPosition(n.position.x + 10, n.position.y);
});
Two distinct things are coalesced, and they are coalesced in two different places, which is worth being precise about:
- Events.
DiagramModel.beginBatch()QUEUES its change events instead of firing them, so a thousandsetPosition()calls do not walk a thousand listener chains on their way to the same rAF.- Frames.
RenderSchedulerfolds everyschedule()in a tick into one rAF callback, so the thousand mutations produce exactly onerender()and onereconcile()— one patch, not a thousand.
- Frames.
Nesting is depth-counted (it bottoms out in DiagramEntity), so a batch
inside a batch is still one frame. mutate throwing does not strand the
model in batch mode.
It never paints synchronously — that is the point. If you need the DOM to be
correct before you measure it, follow with renderNow().
exportText(options?: ExportTextOptions): string— Mermaid-compatible text export (with the lossless sidecar by default) — feed the result back toloadTextfor a full round-trip.loadText(text: string, options?: ImportTextOptions): ImportTextResult— Parse Mermaid-compatible text (sidecar-aware) and reconcile it INTO the live diagram through the same spec reconcilersetNodes/setEdgesuse — listeners, plugins, and the renderer all stay attached.dispose(): voidgetDraggingNodeIds(): string[]— The nodes currently being dragged (past the movement threshold). Custom node components receive this as thedraggingprop.beginLabelEdit( target: { type: 'node' | 'link-label'; nodeId?: string; linkId?: string; labelIndex?: number }, opts?: { seed?: string } ): boolean— visio-depth — open the in-place label editor programmatically: a node's label ({ type: 'node', nodeId }) or a link label ({ type: 'link-label', linkId, labelIndex }). The seam a host's context-menu Rename / F2 binding uses; the same editor + undoable commit that double-click opens.seedreplaces the text the editor opens with (type-to-replace). Returns false when the target is missing, not editable, or the instance is readonly.
Was this page helpful?