ef-pan-zoom
Attributes
xnumberHorizontal pan offset in pixels
0ynumberVertical pan offset in pixels
0scalenumberZoom scale factor (0.1 to 5)
1auto-fitbooleanAuto-fit content on first render
falseMethods
screenToCanvas(screenX: number, screenY: number): { x: number, y: number }Convert screen coordinates to canvas coordinates
Object with x, y in canvas spacecanvasToScreen(canvasX: number, canvasY: number): { x: number, y: number }Convert canvas coordinates to screen coordinates
Object with x, y in screen spacereset(): voidReset to default transform (x=0, y=0, scale=1)
voidfitToContent(padding?: number): voidFit content to container with optional padding (0-1)
voidInteractive pan and zoom container with mouse/trackpad gesture support.
Basic Usage
Wrap any content to make it pannable and zoomable:
<ef-pan-zoom class="w-[720px] h-[480px] border border-gray-300 rounded"><ef-timegroup mode="contain" class="w-[1280px] h-[720px] bg-black"><ef-video src="https://assets.editframe.com/bars-n-tone.mp4" class="size-full object-contain"></ef-video></ef-timegroup></ef-pan-zoom>
Interaction: Click and drag to pan. Hold Cmd/Ctrl and scroll to zoom. Scroll to pan horizontally/vertically.
Auto-Fit Content
Automatically fit content to the container on load:
<ef-pan-zoom auto-fit class="w-[600px] h-[400px] border border-gray-300 rounded bg-gray-50"><ef-timegroup mode="contain" class="w-[1280px] h-[720px] bg-black"><ef-video src="https://assets.editframe.com/bars-n-tone.mp4" class="size-full object-contain"></ef-video></ef-timegroup></ef-pan-zoom>
The auto-fit attribute centers and scales content to fit with 5% padding.
Gesture Controls
Panning
Click and drag anywhere to pan the view:
<ef-pan-zoom class="w-[500px] h-[300px] border border-gray-300 rounded"><div class="w-[1000px] h-[600px] bg-gradient-to-br from-blue-500 to-purple-600 flex items-center justify-center"><p class="text-white text-2xl font-bold">Drag to pan</p></div></ef-pan-zoom>
Zooming
Hold Cmd (Mac) or Ctrl (Windows/Linux) and scroll to zoom:
<ef-pan-zoom class="w-[500px] h-[300px] border border-gray-300 rounded"><div class="w-[800px] h-[600px] bg-gradient-to-br from-green-500 to-teal-600 flex items-center justify-center"><p class="text-white text-2xl font-bold">Cmd/Ctrl + Scroll to zoom</p></div></ef-pan-zoom>
Zoom is centered on the cursor position — the point under the cursor remains fixed while zooming.
Trackpad Gestures
- Two-finger drag: Pan horizontally and vertically
- Pinch: Zoom in/out (with Cmd/Ctrl)
- Scroll: Pan without modifier keys
Programmatic Control
Set transform properties directly:
<div><ef-pan-zoom id="demo-panzoom" x="100" y="50" scale="1.5" class="w-[500px] h-[300px] border border-gray-300 rounded"><div class="w-[800px] h-[600px] bg-gradient-to-br from-red-500 to-pink-600 flex items-center justify-center"><p class="text-white text-2xl font-bold">Programmatic Transform</p></div></ef-pan-zoom><div class="mt-4 flex gap-2"><button onclick="document.getElementById('demo-panzoom').reset()" class="px-3 py-1 bg-blue-500 text-white rounded hover:bg-blue-600">Reset</button><button onclick="document.getElementById('demo-panzoom').fitToContent()" class="px-3 py-1 bg-green-500 text-white rounded hover:bg-green-600">Fit Content</button><button onclick="document.getElementById('demo-panzoom').scale = 2" class="px-3 py-1 bg-purple-500 text-white rounded hover:bg-purple-600">Zoom 2x</button></div></div>
Methods
reset()
Reset the view to default values:
const panZoom = document.querySelector('ef-pan-zoom');panZoom.reset(); // x=0, y=0, scale=1
fitToContent(padding)
Fit content to the container:
const panZoom = document.querySelector('ef-pan-zoom');panZoom.fitToContent(0.1); // 10% padding on each side
Padding is a factor from 0 to 1, where 0.1 = 10% padding.
screenToCanvas(screenX, screenY)
Convert screen coordinates (e.g., mouse event) to canvas coordinates:
panZoom.addEventListener('click', (e) => {const canvasPos = panZoom.screenToCanvas(e.clientX, e.clientY);console.log(`Clicked at canvas position: ${canvasPos.x}, ${canvasPos.y}`);});
Useful for hit detection and positioning elements in canvas space.
canvasToScreen(canvasX, canvasY)
Convert canvas coordinates to screen coordinates:
const screenPos = panZoom.canvasToScreen(element.x, element.y);tooltip.style.left = `${screenPos.x}px`;tooltip.style.top = `${screenPos.y}px`;
Useful for positioning overlays and tooltips relative to canvas elements.
Events
transform-changed
Fired when pan or zoom changes:
panZoom.addEventListener('transform-changed', (e) => {console.log('Transform:', e.detail); // { x, y, scale }});
Use this to sync UI controls or persist view state.
Context Provision
ef-pan-zoom provides transform data via Lit context. Child components can consume this to render overlays that match the transform:
import { consume } from '@lit/context';import { panZoomTransformContext } from '@editframe/elements';@consume({ context: panZoomTransformContext })panZoomTransform?: PanZoomTransform;
Overlay components (like selection handles) use this to align with the panned/zoomed content.
Video Preview with Pan-Zoom
Create a zoomable video preview:
<ef-pan-zoom auto-fit class="w-[720px] h-[480px] border border-gray-300 rounded bg-gray-900"><ef-timegroup mode="contain" class="w-[1920px] h-[1080px] bg-black"><ef-video src="https://assets.editframe.com/bars-n-tone.mp4" class="size-full object-contain"></ef-video><div class="absolute top-8 left-8 bg-white/90 backdrop-blur px-4 py-2 rounded"><p class="text-sm font-semibold">Zoomable Preview</p><p class="text-xs text-gray-600">Cmd/Ctrl + Scroll to zoom</p></div></ef-timegroup></ef-pan-zoom>
Styling
The element has overflow: hidden and position: relative by default. Style the container as needed:
<ef-pan-zoom class="w-full h-screen border-2 border-blue-500 rounded-lg shadow-xl"><!-- Content --></ef-pan-zoom>
Scale Limits
Scale is clamped between 0.1 and 5:
- Minimum: 0.1 (10% of original size)
- Maximum: 5 (500% of original size)
These limits prevent unusable zoom levels while allowing meaningful magnification.
Browser Navigation Prevention
ef-pan-zoom prevents browser back/forward navigation triggered by trackpad swipes. This ensures pan gestures don't accidentally navigate away from the page.
The element uses passive event listeners in capture phase to intercept and prevent default navigation behavior while still allowing normal pan/zoom interactions.