ZoomPan
3 partsDemo
Anatomy
Import the parts and compose them. Each part forwards attributes to its underlying element.
import {
ViewportRoot,
ViewportSurface,
ViewportContent,
} from '@robonen/primitives/canvas/zoom-pan';
<ViewportRoot>
<ViewportSurface />
<ViewportContent />
</ViewportRoot>API Reference
ViewportRoot
ViewportRoot| Prop | Type | Description |
|---|---|---|
viewport? | Viewport | undefined | Two-way bound value (v-model:viewport). |
| Event | Payload |
|---|---|
update:viewport | [value: Viewport | undefined] |
ViewportSurface
ViewportSurfaceThe clipping / interaction pane. Clips the content (`overflow: hidden`), disables native touch gestures (`touch-action: none`), reports its live bounding rect into the context as the screen origin for coordinate math, and hosts the wheel / pinch / drag / dblclick / keyboard pan-zoom layer (`useZoomPan`). Carries `role` / `tabindex` for the a11y keyboard layer and reflects gesture state via `data-panning` / `data-zooming` / `data-measured`. Rendered by `ViewportRoot` by default; place directly only when composing the parts manually.
No props or events — renders its element and forwards attributes.
ViewportContent
ViewportContentThe single transformed layer. Everything a consumer renders inside the viewport lives here, so pan/zoom is one GPU-composited `transform` rather than a per-element restyle. `transform-origin: 0 0` is required — the coordinate formulas in `utils.ts` assume top-left scaling. `will-change: transform` is toggled on ONLY while interacting (never permanently): a pinned hint locks the compositor's raster scale, so the cached texture is GPU-upscaled and the content blurs at high zoom — toggling it lets the layer re-rasterise crisply once motion settles (see `useInteractionState`). Pure presentational; renders the default slot.
No props or events — renders its element and forwards attributes.