Zoom + Pan + Clamp image preview with vanilla javascript.

Mykolas Mankevicius
2 min readNov 12, 2023

--

I recently needed to create a zoom + pan image preview, which should stick to a container for marko.ch. You can click on the squared image to open a dialog and see the result.

For the code, see this stackblitz.

It’s a simplified version of the complete setup I made for Marko. If you want the full gallery experience, let me know, and I’ll do a comprehensive write-up or finally film a little series.

References:

Most (about 90%) of the renderer code was inspired by this post:
Kacper Wdowik: Implementing Zoom and Pan in Just 69 Lines of Javascript.
I’ve adapted it into TypeScript and added clamping.

Then, there’s this tutorial by Sam Selikoff: Pan and Pinch to Zoom with React Use Gesture.

Renderer

The core of rendering the image within the container is within the `renderer.ts`. This file solely focuses on calculating the style for the image from provided values.

The math is mostly explained in Sam Selikoff’s tutorial, but I’ve used `transformOrigin` to calculate the offset for zoom/pinch zoom to the point of origin.
Note: This behaves oddly while the image is smaller than the container, but it works perfectly afterward.

I spent a lot of time figuring out the correct math for this and even wrote a simple tool to see if my assumptions were correct. 😀

Preview

The `preview.ts` is responsible for adding event listeners and providing the correct information to the renderer.

Note: I specifically used `MouseEvents` and `TouchEvents` rather than `PointerEvents`. The main reason is that iOS Safari only recently started supporting these events. The other reason is that I wanted perfect control over the gestures. There are many scripts/packages out there dealing with these, but I find them too opaque and unreliable. Using native event listeners for capturing gestures isn’t too difficult and offers better control.

Summary

I hope this demonstrates that seemingly challenging tasks, like implementing pinch zoom and pan functionality, can be achieved using just vanilla JavaScript and some HTML/CSS, without any external dependencies.

Thank you, and have a great day!

--

--

Mykolas Mankevicius
Mykolas Mankevicius

No responses yet