Use the live DiagramInstance to export the mounted diagram as a PNG, SVG, or PDF. The export contains the rendered scene graph rather than a screenshot: labels, edges, arrowheads, and effects remain part of the output.
Before you export
Mount a non-empty diagram and give its host a size. The following JavaScript example renders three nodes, then downloads a 2× PNG, an SVG, and a vector PDF.
tsimport { render } from '@grafloria/element';
const host = document.getElementById('diagram')!;
host.style.height = '400px';
const instance = render({
nodes: [
{ id: 'requirements', label: 'Requirements', position: { x: 60, y: 90 }, size: { width: 190, height: 78 } },
{ id: 'design', label: 'Design', position: { x: 340, y: 90 }, size: { width: 190, height: 78 } },
{ id: 'ship', label: 'Ship', position: { x: 620, y: 90 }, size: { width: 190, height: 78 } },
],
edges: [
{ id: 'requirements-design', source: 'requirements', target: 'design' },
{ id: 'design-ship', source: 'design', target: 'ship' },
],
}, host);
instance.renderNow();
function download(href: string, name: string): void {
const link = document.createElement('a');
link.href = href;
link.download = name;
link.click();
}
async function downloadFiles(): Promise<void> {
download(await instance.export('png', { scale: 2 }), 'diagram.png');
const svg = await instance.export('svg');
download(`data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`, 'diagram.svg');
download(await instance.export('pdf'), 'diagram.pdf');
}
void downloadFiles();
export() returns a promise. PNG and PDF results are data URLs; SVG is raw SVG source, so wrap it in an encoded data URL before downloading. Call it after the first paint; renderNow() makes that paint synchronous.
| Option | Type | Default | What it does |
|---|---|---|---|
format | 'png' | 'jpeg' | 'webp' | 'svg' | 'pdf' | — | Selects the output format. |
scale | number | — | Sets the raster export scale, such as 2 for a 2× PNG. |
embedModel | boolean | — | Embeds the diagram document in an SVG or PNG so the artifact can be reopened as an editable diagram. |
Export from framework bindings
The binding supplies the same instance through its initialization callback. Keep that instance in framework state or a ref, and call export() from the button handler.
jsimport { render } from '@grafloria/element';
const host = document.getElementById('diagram');
if (!host) throw new Error('Missing #diagram');
host.style.height = '400px';
const instance = render({
nodes: [
{ id: 'a', label: 'Requirements', position: { x: 60, y: 90 }, size: { width: 190, height: 78 } },
{ id: 'b', label: 'Design', position: { x: 340, y: 90 }, size: { width: 190, height: 78 } },
],
edges: [{ id: 'e1', source: 'a', target: 'b' }],
}, host);
instance.renderNow();
async function downloadPdf() {
const pdf = await instance.export('pdf');
const link = document.createElement('a');
link.href = pdf;
link.download = 'requirements.pdf';
link.click();
}
void downloadPdf();
tsimport { Component, viewChild } from '@angular/core';
import { DiagramCanvasComponent } from '@grafloria/angular';
@Component({
standalone: true,
imports: [DiagramCanvasComponent],
template: `
<button (click)="downloadPdf()">download PDF</button>
<grafloria-diagram-canvas [(nodes)]="nodes" [(edges)]="edges" style="display:block;height:400px" />
`,
})
export class ExportDiagramComponent {
canvas = viewChild.required(DiagramCanvasComponent);
nodes = [
{ id: 'a', label: 'Requirements', position: { x: 60, y: 90 }, size: { width: 190, height: 78 } },
{ id: 'b', label: 'Design', position: { x: 340, y: 90 }, size: { width: 190, height: 78 } },
];
edges = [{ id: 'e1', source: 'a', target: 'b' }];
async downloadPdf(): Promise<void> {
const href = await this.canvas().exportDiagram('pdf');
const link = document.createElement('a');
link.href = href;
link.download = 'requirements.pdf';
link.click();
}
}
tsximport { component$, $, noSerialize, useSignal } from '@builder.io/qwik';
import { GrafloriaFlow, type DiagramInstance } from '@grafloria/qwik';
const nodes = [
{ id: 'a', label: 'Requirements', position: { x: 60, y: 90 }, size: { width: 190, height: 78 } },
{ id: 'b', label: 'Design', position: { x: 340, y: 90 }, size: { width: 190, height: 78 } },
];
const edges = [{ id: 'e1', source: 'a', target: 'b' }];
export default component$(() => {
const instance = useSignal();
return (
<div>
<button onClick$={$(async () => {
const href = await instance.value!.export('pdf');
const link = document.createElement('a');
link.href = href;
link.download = 'requirements.pdf';
link.click();
})}>download PDF</button>
<GrafloriaFlow defaultNodes={nodes} defaultEdges={edges} style={{ display: 'block', height: '400px' }} onInit$={$((api: DiagramInstance) => { instance.value = noSerialize(api); })} />
</div>
);
});
tsximport { useRef } from 'react';
import { GrafloriaFlow } from '@grafloria/react';
import type { DiagramInstance } from '@grafloria/react';
const nodes = [
{ id: 'a', label: 'Requirements', position: { x: 60, y: 90 }, size: { width: 190, height: 78 } },
{ id: 'b', label: 'Design', position: { x: 340, y: 90 }, size: { width: 190, height: 78 } },
];
const edges = [{ id: 'e1', source: 'a', target: 'b' }];
export default function ExportDiagram() {
const instance = useRef(null as DiagramInstance | null);
const downloadPdf = async (): Promise<void> => {
const href = await instance.current!.export('pdf');
const link = document.createElement('a');
link.href = href;
link.download = 'requirements.pdf';
link.click();
};
return <div><button onClick={downloadPdf}>download PDF</button><GrafloriaFlow defaultNodes={nodes} defaultEdges={edges} style={{ display: 'block', height: 400 }} onInit={(api) => { instance.current = api; }} /></div>;
}
vue<script setup lang="ts"> import { GrafloriaFlow } from '@grafloria/vue'; import type { DiagramInstance } from '@grafloria/vue'; let instance: DiagramInstance | null = null; const nodes = [ { id: 'a', label: 'Requirements', position: { x: 60, y: 90 }, size: { width: 190, height: 78 } }, { id: 'b', label: 'Design', position: { x: 340, y: 90 }, size: { width: 190, height: 78 } }, ]; const edges = [{ id: 'e1', source: 'a', target: 'b' }]; async function downloadPdf(): Promise<void> { const href = await instance!.export('pdf'); const link = document.createElement('a'); link.href = href; link.download = 'requirements.pdf'; link.click(); } function onInit(api: DiagramInstance): void { instance = api; } </script> <template> <button @click="downloadPdf">download PDF</button> <div style="height:400px"><GrafloriaFlow :default-nodes="nodes" :default-edges="edges" style="height:100%" @init="onInit" /></div> </template>
Each sample mounts a visible diagram and downloads requirements.pdf. Use 'png' or 'svg' in the same handler for raster or SVG output. Angular names the binding shortcut exportDiagram(format, options); the other bindings expose instance.export().
Choose editable or presentation output
PDF is a vector presentation file: text remains selectable and paths remain paths. It is not the editable Grafloria document format. To preserve editability, export SVG or PNG with embedModel: true:
tsimport type { DiagramInstance } from '@grafloria/renderer';
async function exportEditable(instance: DiagramInstance): Promise<void> {
const editableSvg = await instance.export('svg', {
embedModel: true,
embedModelCreatedAt: '2020-01-01T00:00:00Z',
});
const editablePng = await instance.export('png', {
embedModel: true,
embedModelCreatedAt: '2020-01-01T00:00:00Z',
});
void editableSvg;
void editablePng;
}
The embedded document carries the nodes, links, positions, and styling needed to reopen the artifact as a live diagram. A plain SVG or PNG without embedModel is a flat export. The editable round-trip demo shows the original and the reopened diagram side by side: open the live demo.
See the result
- Download image demo shows labels, arrowheads, shadows, and a 2× PNG.
- PDF export demo shows selectable text and sharp vector paths.
Pitfalls
- Do not call
export()before the diagram has painted. Render first; otherwise export rejects instead of returning a blank image. - SVG is source text, not a data URL. Encode it when assigning it to an anchor.
- A 2× scale applies to raster output. SVG and PDF remain vector outputs.
embedModelis the option that makes SVG and PNG reopenable as editable diagrams; PDF is for vector presentation.
For the complete export surface, see The DiagramInstance. For saving a document rather than exporting a visual artifact, see Save and restore diagrams.
Was this page helpful?