I've created a touch event to be able to zoom into an image, saved the x and y values in the touchstart
imageContainer.addEventListener("touchstart", function (event) {
event.preventDefault();
if (event.touches.length === 2) {
let touch1s = [event.touches[0].pageX, event.touches[0].pageY];
let touch2s = [event.touches[1].pageX, event.touches[1].pageY];
x = Math.abs(touch1s[0] + touch2s[0]) / 2;
y = Math.abs(touch1s[1] + touch2s[1]) / 2;
originalDistance = Math.hypot(event.touches[0].pageX - event.touches[1].pageX,event.touches[0].pageY - event.touches[1].pageY );
zoomDrag[0].disable();
}
});
In the touchmove
event listener I have added in functionality to be able to zoom in and out on the point of my finger,
imageContainer.addEventListener("touchmove", function (event) {
event.preventDefault();
if (event.touches.length === 2) {
let currentDistance = Math.hypot(event.touches[0].pageX - event.touches[1].pageX,event.touches[0].pageY - event.touches[1].pageY);
if (originalDistance < currentDistance) {
if (gsap.getProperty(imageContainer, "scale") <= maxScale) {
zoom_control(imageContainer, x, y, "+=0.4");
}
} else if (originalDistance > currentDistance) {
if (gsap.getProperty(imageContainer, "scale") >= minScale) {
zoom_control(imageContainer, x, y, "-=0.4");
}
}
}
});
However when I implement the GSAP Draggable library and perform a drag when I am zoomed in, and try to zoom back in/out, the transform origin isn't where it should be.
Math isn't my strong suit so what would the formula be to make the transform origin correct?
Here is the code for zoom_control
for those asking
function zoom_control(item, posX, posY, scale) {
if (!isNaN(posX) && !isNaN(posY)) {
smoothOriginChange(item, `${posX}px ${posY}px`);
}
gsap.to(item, {
scale: scale
});
}
function smoothOriginChange(targets, transformOrigin) {
gsap.utils.toArray(targets).forEach(function (target) {
let before = target.getBoundingClientRect();
gsap.set(target, { transformOrigin: transformOrigin });
let after = target.getBoundingClientRect();
gsap.set(target, {
x: "+=" + (before.left - after.left),
y: "+=" + (before.top - after.top)
});
});
}`
Okay so whilst Grin's method works and can get the job done, I resorted to using the HammerJS library. Whilst it has known bugs and hasn't been updated for a while, it gets the job done. The finished product can be seen in the working demo
https://codepen.io/wescritch98/pen/wBwmvmm
But the code usage has been significantly reduced in my js file.
let hammer = new Hammer(imageContainer),
hammer.get("pinch").set({ enable: true });
hammer.on("pinchstart", (e) => {
//transform X and Y are defines by the touch events offset X and Y values
transformX = e.srcEvent.offsetX;
transformY = e.srcEvent.offsetY;
// We disable the Draggable functionality to avoid the jittery look when pinching with 2 or more fingers
zoomDrag[0].disable();
});
hammer.on("pinch", (e) => {
switch (e.additionalEvent) {
// The pinch out is the zooming in functionality
case "pinchout":
/*
* Will stop the image going above whatever maxScale number we have applied
* Otherwise the scale will default to the maxScale
*/
if (gsap.getProperty(imageContainer, "scale") <= maxScale) {
zoom_control(imageContainer, transformX, transformY, "+=0.4");
} else {
gsap.to(imageContainer, {
scale: maxScale
});
}
break;
// The pinch in is the zooming out functionality
case "pinchin":
/*
* Will stop the image going above whatever maxScale number we have applied
* Otherwise the scale will default to the maxScale
*/
if (gsap.getProperty(imageContainer, "scale") >= minScale) {
zoom_control(imageContainer, transformX, transformY, "-=0.4");
} else {
gsap.to(imageContainer, {
scale: minScale
});
}
break;
}
});
hammer.on("pinchend", () => {
// We reenable the Draggable event
zoomDrag[0].enable();
});
function zoom_control(item, posX, posY, scale) {
if (!isNaN(posX) && !isNaN(posY)) {
smoothOriginChange(item, `${posX}px ${posY}px`);
}
gsap.to(item, {
scale: scale
});
}
// This makes the transform origin change smoothly and stop a jump every time we zoom in on a new place
function smoothOriginChange(targets, transformOrigin) {
gsap.utils.toArray(targets).forEach(function (target) {
let before = target.getBoundingClientRect();
gsap.set(target, { transformOrigin: transformOrigin });
let after = target.getBoundingClientRect();
gsap.set(target, {
x: `+= ${before.left - after.left}`,
y: `+= ${before.top - after.top}`
});
});
}