Interact.js Pinch-Zoom and Rotate Surface — Free JS Snippet

Interact.js Pinch-Zoom and Rotate Surface with Mouse Fallbacks · Mobile · Plain HTML, CSS & JS · Live preview

What's included

Features

Interact.js gesturable events with ds (scale change) and da (angle change)
One state object and one apply() function shared by every input method
Two-finger pan included via the gesture's midpoint movement
Wheel zoom with exponential scaling and Alt+wheel rotation
Slider and keyboard fallbacks so desktop users are not excluded
Scale clamped between 40% and 300%
touch-action: none so the browser does not claim the gesture
Double-click and Reset for recovery

About this UI Snippet

Interact.js Pinch-Zoom and Rotate Surface — HTML, CSS & JavaScript

Screenshot of the Interact.js Pinch-Zoom and Rotate Surface with Mouse Fallbacks snippet rendered live

Pinch to zoom and twist to rotate are the gestures people now expect from anything that looks like a photo, a map or a canvas. Implementing them from raw touch events means tracking two pointers, computing the distance between them to derive scale and the angle between them to derive rotation, handling pointers that appear and disappear mid-gesture, and doing it consistently across devices. Interact.js does that work and exposes a gesturable interaction whose events report the result directly: ds, the change in scale, and da, the change in angle in degrees, since the previous event.

The snippet keeps a single state object — x, y, scale and angle — and one apply() function that turns it into a CSS transform. Everything that can change the view edits the state and calls apply(): the draggable listener adds dx and dy, the gesturable listener multiplies scale by one plus ds and adds da to the angle, and, importantly, adds the gesture's midpoint movement so a two-finger pan is not lost. Centralising the transform in one function is what keeps the different input methods from fighting each other; if each wrote its own transform string, the last writer would erase the others' contributions.

Not every user has two fingers. On a desktop the gesturable interaction never fires, so a surface that supports only pinch is unusable there — a mistake common in gesture demos. The snippet therefore adds three fallbacks that edit the same state: the wheel zooms, Alt with the wheel rotates, and range sliders and keyboard shortcuts do both. The wheel handler uses exponential scaling, multiplying by e to the power of minus deltaY times a constant, so zooming feels equally fast at 50 percent and 300 percent instead of accelerating as you zoom in, and it registers with passive: false because calling preventDefault to stop the page scrolling is not allowed on passive listeners.

Two smaller details matter. The surface has touch-action: none, which tells the browser not to claim the gesture for its own page zoom or scroll; without it, pinching on a phone zooms the whole page instead of the photo. And scale is clamped between 0.4 and 3 through a shared clamp function, so no input path can shrink the card to nothing or blow it up beyond usefulness. Double-click, the Reset button and the keyboard provide simple recovery.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Ask an AI assistant like Claude to zoom toward the pointer position instead of the centre, add inertia after a drag, or support several stickers each with their own transform.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a pinch-zoom and rotate surface with Interact.js 1.10 loaded from a CDN.

Requirements:
- Keep one state object { x, y, scale, angle } and an apply() function that sets transform: translate() rotate() scale() on a photo card.
- Use interact(card).draggable(...) to add dx/dy and .gesturable(...) to multiply scale by (1 + e.ds), add e.da to the angle and add e.dx/e.dy for the two-finger pan; clamp scale to 0.4-3.
- Add wheel zoom (exponential, passive: false), Alt+wheel rotation, Zoom and Rotate range sliders, keyboard shortcuts (arrows, +/-, [ ]) and double-click/Reset, all editing the same state.
- Set touch-action: none on the stage and make it focusable with an aria-label.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Source Code

Requires
<div class="pz-app">
  <div class="pz-stage" id="pzStage" tabindex="0" aria-label="Photo surface. Drag to move, pinch or use controls to zoom and rotate.">
    <div class="pz-card" id="pzCard"><div class="pz-art" aria-hidden="true"><span>&#127748;</span></div><div class="pz-cap">Golden hour &middot; drag, pinch, rotate</div></div>
    <div class="pz-guide" aria-hidden="true">Two fingers: pinch to zoom, twist to rotate</div>
  </div>
  <div class="pz-controls">
    <label>Zoom <input type="range" id="pzZoom" min="0.4" max="3" step="0.01" value="1"><output id="pzZoomOut">100%</output></label>
    <label>Rotate <input type="range" id="pzRot" min="-180" max="180" step="1" value="0"><output id="pzRotOut">0&deg;</output></label>
    <button type="button" id="pzReset">Reset</button>
  </div>
  <p class="pz-tip"><b>Desktop:</b> drag to move &middot; wheel to zoom &middot; <kbd>Alt</kbd> + wheel to rotate &middot; double-click to reset. <b>Touch:</b> drag, pinch and twist.</p>
</div>

Step by step

How to Use

  1. 1
    Drag the photoDrag it with a mouse or one finger to move it around the surface.
  2. 2
    Zoom with the wheelScroll the mouse wheel over the surface to zoom in and out. On a touch screen, pinch instead.
  3. 3
    RotateHold Alt and scroll to rotate, or twist two fingers on a touch screen.
  4. 4
    Use the slidersDrag the Zoom and Rotate sliders; they stay in sync with every other input method.
  5. 5
    ResetDouble-click the surface or press Reset to return to the default view.

Real-world uses

Common Use Cases

Photo, map and canvas viewers
Add natural gestures to any surface. For pan-and-zoom on diagrams see the Panzoom floor plan.
Sticker and collage editors
Let users place, scale and rotate stickers with two fingers.
SHOP
Product try-on and preview tools
Position an item over a photo with gestures.
Learning gesture maths
See how scale and rotation deltas compose with drag into one transform.

Got questions?

Frequently Asked Questions

ds is the change in scale ratio since the last event, and da is the change in angle in degrees.

Add touch-action: none to the element so the browser does not use the gesture for page zoom or scroll.

Provide fallbacks that edit the same state: wheel to zoom, Alt+wheel to rotate, sliders and keyboard shortcuts.

Calling preventDefault to stop page scrolling is ignored on passive listeners, so register with { passive: false }.

Multiplying by exp(-delta * k) makes each notch change scale by the same ratio, so zoom speed feels consistent at any level.

Keep a single state object and a single function that writes the transform, and have every input edit the state.

Yes. Use the JSX, Vue, Angular or Tailwind export buttons on this page to convert the markup and styles. The behaviour comes from Interact.js, so in a framework project install it with npm install interactjs instead of the CDN tag, register it in useEffect / onMounted / ngAfterViewInit and keep the position in component state, and release it with interact(element).unset() when the component unmounts.