Export
SVG
const { svg, clip } = await editor.exportAsSVG({ svgMode: "web" })
svg: string— serialised SVG markupclip: { x, y, width, height }— viewport of the rendered diagram
ExportOptions:
| Field | Type | Default | Effect |
|---|---|---|---|
svgMode | "web" | "compat" | "web" | "web" keeps CSS variables for theme-adaptive rendering; "compat" resolves them and inlines fonts/attributes (PDF/PPT/Inkscape). |
margin | number | { top?, right?, bottom?, left?: number } | 0 | Extra space around the diagram bounding box. |
keepOriginalSize | boolean | false | If true, do not normalise the viewBox to the diagram bounds — preserve the editor's current pan/zoom framing. |
include | string[] | — | Render only the listed element ids. Mutually exclusive with exclude. |
exclude | string[] | — | Render everything except the listed element ids. |
Headless SVG export (no mounted editor)
import { ApollonEditor, importDiagram } from "@tumaet/apollon"
const svgExport = await ApollonEditor.exportModelAsSvg(importDiagram(model), {
svgMode: "compat",
})
exportModelAsSvg mounts the editor off-screen and serialises the rendered SVG,
so it needs a DOM plus canvas measureText and getBBox. To render saved models
in a batch — e.g. reviewing diagram submission versions — without a browser, use
the jsdom + canvas recipe in Headless rendering
(a browser is the heavier, pixel-exact alternative).
In a real browser the export is self-contained: it injects the layout CSS and
Inter font it needs, so you do not import @tumaet/apollon/style.css just to
export. (style.css is still required to mount the interactive
editor.)
:::tip Always normalise first
Pass models through importDiagram(...) before exporting. It upgrades v2 / v3
payloads to the current v4 shape; feeding a stale shape straight in is a common
cause of garbled output.
:::
The standalone server's conversion worker is the reference jsdom setup: it registers Inter on a Skia canvas, shims
getBBox, and pre-seeds handle geometry. See Headless rendering.
PNG / PDF
For browsers and embedders, import the ready-made helpers from
@tumaet/apollon/export. They consume the compat-mode SVG produced above and
work around the browser's canvas-area limit — svgToPng rasterises in wasm
memory instead of a <canvas>, and svgToPdf emits true vector PDF.
import { svgToPng, svgToPdf } from "@tumaet/apollon/export"
import resvgWasmUrl from "@resvg/resvg-wasm/index_bg.wasm?url" // Vite — see below
const { svg, clip } = await editor.exportAsSVG({ svgMode: "compat" })
const { blob, clamped } = await svgToPng(svg, clip, {
scale: 1.5,
background: "#ffffff", // or null for transparent
wasmInput: fetch(resvgWasmUrl),
})
const pdfBlob = await svgToPdf(svg, clip, { title: "diagram" })
@resvg/resvg-wasm, jspdf and svg2pdf.js are optional dependencies the
consumer installs (npm install @resvg/resvg-wasm jspdf svg2pdf.js); they load
lazily, so importing the editor never pulls them in. Over-budget diagrams come
back with clamped: true and a reduced appliedScale; an over-budget PNG throws
RasterTooLargeError. Inter ships Regular + Bold only, so italics render upright
— matching the server.
Loading the resvg wasm per bundler
svgToPng needs the @resvg/resvg-wasm binary, passed as wasmInput (anything
resvg's initWasm accepts — fetch(url) is idiomatic). The library does not
bundle the wasm, so how you get the URL depends on your bundler:
- Vite —
import resvgWasmUrl from "@resvg/resvg-wasm/index_bg.wasm?url"(the snippet above). - Webpack 5 — add a rule
{ test: /\.wasm$/, type: "asset/resource" }, thenconst resvgWasmUrl = new URL("@resvg/resvg-wasm/index_bg.wasm", import.meta.url).href. - Angular — copy the binary with an
assetsglob (node_modules/@resvg/resvg-wasm/index_bg.wasm→assets/resvg/), thenwasmInput: fetch("assets/resvg/index_bg.wasm").
svgToPdf needs no wasm. Both helpers inline the Inter font in the browser, so
you only set fontBuffers / fonts for headless Node.
Server-side instead? The standalone server renders SVG, PNG, and PDF over HTTP via a Skia canvas +
pdfmake— see the Conversion API.
JSON
const model = editor.model // UMLModel
const json = JSON.stringify(model)
Round-trip safe: editor.model = JSON.parse(json).
Wire-format versions
The library reads v2, v3, and v4 model JSON. Use importDiagram(any) to
normalise any version to the current v4 shape before assigning to editor.model
or passing to exportModelAsSvg.
import { importDiagram } from "@tumaet/apollon"
editor.model = importDiagram(maybeV2OrV3Json)
The v4 shape is published as a versioned JSON Schema — see the Model JSON contract for the schema, the field-by-field shape, and the versioning policy.