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.
Most (about 90%) of the renderer code was inspired by this post:
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.
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.ts is responsible for adding event listeners and providing the correct information to the renderer.
Note: I specifically used
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.
Thank you, and have a great day!