A Svelte library for panning and zooming in SVG, Canvas and HTML.
pnpm add panera
Peer requirement: svelte ^4 || ^5
<script>
import { Panera, Svg } from 'panera';
let width = 800,
height = 300;
let pan;
function reset() {
pan.reset();
}
function to() {
pan.to({ x: 80, y: 40, width: 200, height: 120 }, { duration: 600 });
}
</script>
<button on:click={reset}>Reset</button> <button on:click={to}>Zoom to rect</button>
<Panera bind:this={pan} {width} {height}>
<Svg>
<rect fill="tomato" x="80" y="40" width="200" height="120" />
</Svg>
</Panera>
<Panera /><Svg />, <Canvas />, <Html />bind:this: to(), reset(), interpolate(), getView(), getBox()<Panera /> propswidth?: number | null — container width in pixels (required for fits)height?: number | null - container height in pixels (required for fits)duration?: number — default 1000 ms (used by to() & reset())easing?: (t:number)=>number — default cubicInOutbound?: boolean — clamp view inside container (default true)debugBox?: boolean — overlay a non-scaling red debug rect (default false)debugZoom?: boolean — disable zooming, helpful in conjuction with debugBox (default false)bind:this)reset(opts?)
opts = { duration?: number, easing?: (t)=>number, debugBox?, debugZoom? }
Reset the view back to k=1, x=0, y=0.
to(rect, opts?)
rect = {x, y, width, height}
opts = { duration?, easing?, bound?, debugBox?, debugZoom? }
Tweens to the fitted view of the rectangle.
interpolate(a, b, opts?)
a = { x, y, width, height }, b = { x, y, width, height }
opts = { t?: number, easing?: (t)=>number, bound?, debugBox?, debugZoom? }
Instant scrub (no tween). Fits both a and b, then blends view using t (after easing).
getView(): Readable<{ k:number, x:number, y:number }>
A Svelte store reflecting the current view.
getBox(): Readable<{ x:number, y:number, width:number, height: number }>
A Svelte store reflecting the current bounding box.
<Svg>
Renders a <svg> with viewBox and a <g> that applies:
transform="scale(k) translate(x, y)".
Debug rect uses vector-effect="non-scaling-stroke".
<Canvas>
DPR-aware canvas; applies scale(k) then translate(x, y).
Prop:
render(ctx, {k, x, y}, {width, height, dpr}) => void
<Html>
Absolutely-positioned HTML that follows the same transform via CSS:
transform: scale(k) translate(xpx, ypx); transform-origin: 0 0;
Place children with position:absolute; left/top in object coordinates.
pnpm format # prettier
pnpm lint # prettier check + eslint
pnpm test # vitest unit tests
pnpm prepack # build library to dist/ (svelte-package + publint)
pnpm storybook # run the local storybook page
pnpm pack # output a tarball
MIT