Skip to main content

Export

SVG​

const { svg, clip } = await editor.exportAsSVG({ svgMode: "web" })
  • svg: string — serialised SVG markup
  • clip: { x, y, width, height } — viewport of the rendered diagram

ExportOptions:

FieldTypeDefaultEffect
svgMode"web" | "compat""web""web" keeps CSS variables for theme-adaptive rendering; "compat" resolves them and inlines fonts/attributes (PDF/PPT/Inkscape).
marginnumber | { top?, right?, bottom?, left?: number }0Extra space around the diagram bounding box.
keepOriginalSizebooleanfalseIf true, do not normalise the viewBox to the diagram bounds — preserve the editor's current pan/zoom framing.
includestring[]—Render only the listed element ids. Mutually exclusive with exclude.
excludestring[]—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 of @tumaet/apollon, so a normal install brings them in automatically (install them explicitly only under --omit=optional); 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" }, then const resvgWasmUrl = new URL("@resvg/resvg-wasm/index_bg.wasm", import.meta.url).href.
  • Angular — copy the binary with an assets glob (node_modules/@resvg/resvg-wasm/index_bg.wasm → assets/resvg/), then wasmInput: 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.