A Diagram Renderer of your own
Quick start
This Diagram Renderer sends Mermaid source to a rendering service you host:
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
| 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 |
rules | RendererRules | Optional. See Rules of your Renderer |
render | (input) => Promise<{ svg, width, height }> | Draws the source, described below |
editing | DiagramEditing | Optional. Finds texts and shapes in its SVG, see Editing in the diagram |
Which Renderer draws a diagram
The extension picks the first registered Diagram Renderer whose formats include the diagram's
format and whose draws does not decline the source. Empty source goes to the first Diagram
Renderer of its format, without asking draws.
A kind no Renderer draws shows what unavailable returns, with
the reason 'unsupported-kind'. The source stays in the document. Unlike a chart Renderer, a
declining Diagram Renderer never draws the diagram after all.
A format of your own
insertFlowDiagram and updateFlowDiagram accept a format while a registered Diagram Renderer
lists it in formats. It needs no other registration.
- The format's id has letters, digits,
_and-, up to 64 characters. - The source is stored as it is, up to 1,000,000 characters.
- A format no registered Diagram Renderer draws stays in the document unchanged and survives
every save. The diagram shows what
unavailablereturns.
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 an image in Word |
When raster is true, write labels as SVG text. The SVG must hold no foreignObject, because
the browser does not let a canvas export one.
What render returns
render returns { svg, width, height }. svg is a standalone SVG string with a width and a
height. width and height are numbers, the size of the drawing in pixels.
Editing in the diagram
A user can double click a text in a diagram to edit it, and drag a shape to move it. See
Editing in the diagram. Only the Renderer knows where texts and
shapes are in its SVG, so it tells the extension through editing. Every function of editing
receives the SVG that render 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, but stay in the document |
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' }. The extension writes the new text there.DiagramNodeHitis{ id, label, box }.idis the shape's id in the source.movePositionsreturns the SVG with each shape moved by its offset, ornullwhen nothing moved.- Return
nullfor a diagram kind your Renderer does not handle.
A Renderer that draws with mermaid.js can reuse the built-in editing:
import { mermaidDiagramEditing } from '@tiptap-pro/extension-diagrams/mermaid'
const renderer = { id: 'my-mermaid', formats: ['mermaid'], render, editing: mermaidDiagramEditing }Keeping your web page safe
The editor shows the SVG in an <img>, so scripts and outside resources in the SVG never run or
load in your web page.
Never evaluate the source in your web 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.