SVG on the server
The core of ireko and toSVG need no DOM. A layout and its SVG are pure functions of the input. Thus you can make diagrams on a server, in a build step, in a worker or in a test.
A file from a script
Section titled “A file from a script”// diagram.ts: node diagram.ts > diagram.svgimport { layout } from "ireko";import { toSVG } from "ireko/svg";import { parse } from "ireko/text";
const parsed = parse(` build "CI" nested grid(columns: 4) { checkout lint test deploy } checkout -> lint lint -> test test -> deploy`);if (!parsed.ok) throw new Error(parsed.error.message);
process.stdout.write(toSVG(layout(parsed.input), { title: "The CI pipeline" }));build "CI" nested grid(columns: 4) {
checkout lint test deploy
}
checkout -> lint
lint -> test
test -> deployIn server rendering
Section titled “In server rendering”LayoutSvg from ireko/react has no state and no effects, so React renders it on the server. This site uses it for each figure: the HTML has the diagram before any script runs.
// An Astro page, a Next.js server component or renderToStringimport { layout } from "ireko";import { LayoutSvg } from "ireko/react";
export function Architecture({ input }) { return <LayoutSvg layout={layout(input)} title="The architecture" className="diagram" />;}Measure the labels
Section titled “Measure the labels”Without a size, each leaf gets the nodeSize of the layout (120 by 48). For labels of different lengths, give a measure function. It gets each leaf, and gives its size or undefined.
import { layout } from "ireko";
// An estimate with no font engine: 7 pixels for each character, and 24 pixels of padding.const result = layout(input, { measure: (node) => ({ width: Math.max(60, 7 * (node.label ?? node.id).length + 24), height: 32 }),});In a browser, measure the real text with a canvas: ctx.measureText(label).width. On a server, use the metrics of your font, or a library that reads them. A leaf with a size in its spec keeps that size.
Theme and styles
Section titled “Theme and styles”toSVG writes the colors as attributes, so the file looks correct alone. It also writes classes, so a page can change the colors with CSS:
toSVG(result, { theme: { background: "transparent", fontFamily: "Inter, sans-serif", accent: "#d43c3c" }, padding: 24, labels: true, background: false,});| Option | Default | Meaning |
|---|---|---|
theme | lightTheme | The colors and fonts. A partial theme replaces only its values. |
padding | 16 | The space around the layout, in pixels. |
title | none | The title of the image, for assistive technology. Give one. |
labels | true | With false, the output has no text. |
background | true | With false, the output has no background rectangle. |
Stable output
Section titled “Stable output”The same input and options give the same SVG, byte for byte. The engine uses no random numbers and no clock, and toSVG writes each number with three decimals or fewer. Thus a snapshot test of a diagram is stable:
import { expect, it } from "vitest";
it("draws the architecture", async () => { await expect(toSVG(layout(input))).toMatchFileSnapshot("./architecture.svg");});The tests of ireko do the same for each example of the gallery.
Other formats
Section titled “Other formats”- PNG: draw the SVG with a headless browser, or with an SVG library, for example
resvg. - JSON: the layout is JSON. Store it, and draw it later in any renderer.
- Canvas on a server:
drawFramefromireko/canvasdraws on any 2D context with the methods ofContext2D, for example the canvas of a Node.js library.