A Diagram Renderer of your own
A Diagram Renderer turns the source text of one format into an SVG string. The editor shows the result as an image, so its SVG never runs script in the page.
Quick start
This one sends Mermaid source to a rendering service you host and returns what it answers:
import type { DiagramRenderer } from '@tiptap-pro/extension-diagrams'
export function serviceDiagramRenderer(endpoint: string): DiagramRenderer {
return {
id: 'mermaid-service',
label: 'Mermaid (service)',
formats: ['mermaid'],
async render({ source, theme, raster }) {
const response = await fetch(endpoint, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ source, theme, htmlLabels: !raster }),
})
if (!response.ok) throw new Error(`The diagram service answered ${response.status}`)
const svg = await response.text()
const root = new DOMParser().parseFromString(svg, 'image/svg+xml').documentElement
const width = Number.parseFloat(root.getAttribute('width') ?? '') || 600
const height = Number.parseFloat(root.getAttribute('height') ?? '') || 400
return { svg, width, height }
},
}
}Diagrams.configure({
diagramRenderers: [serviceDiagramRenderer('https://diagrams.example.com/mermaid/svg')],
})Members
A Diagram Renderer is { id, label?, formats, draws?, render, editing? }.
| Member | Type | Description |
|---|---|---|
id | string | Names the Renderer |
label | string | Optional. For a menu |
formats | readonly FlowDiagramFormat[] | The diagram formats it draws |
draws | (source: string) => boolean | Optional. Whether it draws this source, such as only some Mermaid kinds. Without it, every source |
render | (input) => Promise<{ svg, width, height }> | Draws the source, described below |
editing | DiagramEditing | Optional. Finds text and shapes in its pictures, see Editing in the picture |
Which Renderer draws a diagram
- The first registered Diagram Renderer whose
formatsinclude the diagram's format, and whosedrawsdoes not decline the source, draws the diagram. - A kind no Renderer draws shows what
unavailablereturns, with the reason'unsupported-kind'. The source stays in the document. - A format of your own needs no other registration. See Other formats.
What render receives
| Input | Type | Description |
|---|---|---|
format | FlowDiagramFormat | mermaid, drawio, bpmn or a format of your own, one of the Renderer's formats |
source | string | The diagram source text, as the document stores it |
theme | DiagramTheme | Resolved colors and fonts, read from the --tt-flow-diagram-* custom properties (Diagrams) |
raster | boolean | true when the SVG becomes a PNG, a WebP, a JPEG or a picture in Word |
When raster is true, labels must be SVG text: the SVG must hold no foreignObject, which
the browser does not let a canvas export.
What render returns
| Result | Type | Description |
|---|---|---|
svg | string | A standalone SVG string with a width and a height |
width, height | number | The size of the drawing in pixels |
Editing in the picture
A double click on a text and dragging a shape need to know where things are in the picture. Only
the Renderer knows its markup, so it says so through editing. Every function receives the SVG
it returned, as a string, and the diagram's source.
| Member | Signature | Without it |
|---|---|---|
labelAt | (svg, point, source) => DiagramLabelHit | null | A double click opens nothing |
nodeAt | (svg, point, source) => DiagramNodeHit | null | No shape can be dragged |
movePositions | (svg, positions, source) => string | null | No shape can be dragged; stored offsets are not drawn |
pointis in the SVG's own units, through itsviewBox.DiagramLabelHitis{ target, label, box }.targetnames the text in the source, such as{ kind: 'node', id: 'A' }, and the extension writes the new text there.DiagramNodeHitis{ id, label, box },idas the source names the shape.movePositionsreturns the picture with each shape moved by its offset,nullwhen nothing moved.- Return
nullfor a kind your Renderer does not handle.
A Renderer that draws with mermaid.js reuses the built-in one:
import { mermaidDiagramEditing } from '@tiptap-pro/extension-diagrams/mermaid'
const renderer = { id: 'my-mermaid', formats: ['mermaid'], render, editing: mermaidDiagramEditing }Keeping the page safe
- The SVG is shown in an
<img>, so scripts and outside resources in it never run or load in the editor. - The source must not be evaluated in the page. Render it on a server or in a sandboxed iframe, as the built-in Renderers do.
- A library that only parses text and needs no DOM can draw in a Web Worker instead, as the Pele Renderer does.