Skip to content
Folio

Diagrams

DiagramCanvas

A frame that a picture larger than it can be panned and zoomed inside.

Usage

When to reach for it

Any oversized figure — an SVG, an image, a table that will not fold. It knows nothing about nodes, which is what makes it reusable.

Ships from@misoto22/design/diagrams

TSX
import { DiagramCanvas } from '@misoto22/design/diagrams'

Notes

A frame that a picture larger than it can be moved around inside.

Pan with a drag, zoom with the controls or with ⌘/Ctrl and the wheel, and reset with a key. That is the whole of it — this is deliberately a VIEWPORT and not a diagram editor: nothing here knows what a node is, so it works for any oversized figure, an SVG, an image, a table that will not fold.

Three decisions here are not obvious.

A plain wheel scrolls the page, not the diagram. A canvas that swallows the wheel is a scroll trap: a reader flicking down an article hits the figure and the page stops moving for no reason they can see. Zooming needs the modifier — which is also the platform gesture for zoom everywhere else, and is what a trackpad pinch already sends.

The transform is on a wrapper, not on the content. The child keeps its own coordinate space, so a figure inside can still be measured, exported and read by anything that walks it. Scaling the child directly would make every getBoundingClientRect inside it a lie.

Keyboard first, and the frame is a real tab stop. + / - / 0 and the arrow keys move the view; the frame takes focus so they can be pressed at all. A canvas that only answers a drag is a canvas half the readers cannot operate.

Anatomy

DiagramCanvas anatomy
ElementDescription
FramerequiredThe outer box: a fixed height — 24rem unless height says otherwise — a hairline, the diagram ground, and overflow hidden. It is the window the artwork is bigger than.
ViewportrequiredThe focusable layer inside it: role="group" with a name, tabIndex 0, the drag handlers, the key handler and a focus ring drawn inside the frame. This is the tab stop, and it is what makes the keys pressable at all.
StagerequiredThe wrapper the translate and scale are applied to. The transform is on the wrapper and never on the child, so the figure inside keeps its own coordinate space and every measurement taken inside it stays true.
Zoom controlsThe cluster pinned to the bottom corner: zoom out, the current percentage — which is also the reset button, named for what it does — and zoom in. controls={false} removes the cluster and leaves the keys.
Keyboard hintrequiredA visually hidden paragraph, referenced by aria-describedby, saying that the frame drags and which keys pan, zoom and reset. Nothing on screen carries that sentence.

Best practices

Do

  • Name it. label is the group’s accessible name and it defaults to "Diagram canvas", so two canvases on one page announce the same thing until each is given its own.
  • Strip the figure inside to its artwork with heading={false}, legend="hidden" and cards={false}. Everything in the frame pans and zooms together, so a title left on travels away from the diagram it names and a key leaves the frame at exactly the zoom that made a reader want it.
  • Move the view through the ref — zoomIn, zoomOut, reset, centerOn — rather than re-rendering the child at a new size. centerOn takes a point in the content’s own coordinates, which is what a minimap reports back.
  • Hand onViewChange straight to a minimap. Each view carries the frame it was measured against as well as the scale and the offset, and that pair is the whole of the arithmetic a viewport rectangle is — the frame being the one number nothing outside the canvas can measure.

Don’t

  • Nothing clamps the pan. The offset is whatever the drag or the arrow keys left it at, so the artwork can be pushed entirely outside the frame; 0 and the reset button are the whole way back, and controls={false} without a replacement takes the pointer’s half of that away.
  • The scale stops at 0.35. A figure more than about three times the frame cannot be zoomed out far enough to be seen whole, so the frame has to be sized for the diagram — a minimap answers where you are, never what is there.
  • The wheel is left alone and the thumb is not: the frame sets touch-action to none, so a finger dragged inside it pans the diagram and never scrolls the page. A full-width canvas in an article is a band a touch reader has to swipe around rather than through, which is the argument for giving it a height short enough to leave page beside it.

Examples

default

A figure wider than the room it is given, in a frame that can be moved around it. A drag pans, the plate in the corner zooms, and the percentage between its two buttons is the reset; a plain wheel is deliberately left to the page, so only Command or Control with the wheel zooms. The frame is a real tab stop, so plus, minus, zero and the arrow keys do the same work with no pointer at all. The figure’s own heading, key and cards are turned off here because the canvas is holding artwork, not an article.

Request path4 elements and 3 relationships.EXTERNALBrowserCLOUDCloudFrontCDNSERVICEAPIFastAPIDATAPostgres

4 elements and 3 relationships.

  • Browser (external)
  • CloudFront (cloud) — CDN
  • API (backend) — FastAPI
  • Postgres (database)
  • BrowserCloudFront: HTTPS
  • CloudFrontAPI
  • APIPostgres: SQL

Drag to pan. Plus and minus zoom, zero resets, the arrow keys pan.

your own controls

controls={false} removes the plate in the corner, and everything it did has to be put back somewhere: zoomIn, zoomOut and reset live on the handle, and a ref is the only way to reach them. Turn the built-in controls off when the page already has a toolbar and two sets of zoom buttons would compete for the same job. Turning them off and supplying nothing leaves zoom to the modifier-wheel and the keyboard, neither of which a reader has any way to discover.

Request path3 elements and 2 relationships.CLOUDCloudFrontCDNSERVICEAPIFastAPIDATAPostgres

3 elements and 2 relationships.

  • CloudFront (cloud) — CDN
  • API (backend) — FastAPI
  • Postgres (database)
  • CloudFrontAPI: HTTPS
  • APIPostgres: SQL

Drag to pan. Plus and minus zoom, zero resets, the arrow keys pan.

following the view

onViewChange fires on every pan, zoom and reset with the same three numbers the canvas is transforming by, which is what a percentage readout, a minimap or a deep link into the diagram is built out of. centerOn goes the other way and takes a point in the artwork’s own coordinate space, not a node id — the canvas is a viewport and knows nothing about nodes, so a caller that wants to jump to one has to know where it was drawn.

Request path4 elements and 3 relationships.EXTERNALBrowserCLOUDCloudFrontSERVICEAPIDATAPostgres

4 elements and 3 relationships.

  • Browser (external)
  • CloudFront (cloud)
  • API (backend)
  • Postgres (database)
  • BrowserCloudFront
  • CloudFrontAPI
  • APIPostgres: SQL

Drag to pan. Plus and minus zoom, zero resets, the arrow keys pan.

100% at 0, 0

Keyboard

DiagramCanvas keyboard interactions
KeyDoes
+=Zooms in about the centre of the frame.
-Zooms out.
0Resets the scale and the offset together.
Pans. Shift pans further per press.

Accessibility

  • The frame is a real tab stop, so the keyboard controls can be pressed at all.
  • A plain wheel scrolls the page. Zoom needs the platform modifier, so the canvas is never a scroll trap in the middle of an article.