I am following a YouTube tutorial on making a drawing app.
He has built a zooming function that only zooms into the middle of the canvas. I would like to implement zooming like google maps, so that the cursor stays on the same point.
useLayoutEffect(() => {
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);
const scaledWidth = canvas.width * scale;
const scaledHeight = canvas.height * scale;
const scaleOffsetX = (scaledWidth - canvas.width) * 0.5;
const scaleOffsetY = (scaledHeight - canvas.height) * 0.5;
setScaleOffset((prevValue) => ({
x: scaleOffsetX,
y: scaleOffsetY,
}));
ctx.save();
ctx.translate(
panOffset.x * scale - scaleOffsetX,
panOffset.y * scale - scaleOffsetY
);
ctx.scale(scale, scale);
elements.forEach((element) => {
if (action === "writing" && selectedElement.id === element.id) return;
drawElement(ctx, element);
});
ctx.restore();
}, [elements, action, selectedElement, panOffset, scale]);
I have tried everything i can think of and have been through every forum post, and cannot find anything that makes enough sense to me that i can slot in to my existing code. I have tried matrix multiplication (which i don't understand the maths behind so i can't do more than copy/paste).
The scale is offset by a calculation that halves the value of the difference between the viewport and the scaled canvas size. I tried to change the 0.5 to the value of the mouse across the screen as a percentage (0.5 of the width of the viewport), which works great until i move the mouse and the whole canvas suddenly shifts.
If you want to implement "zoom to point" or "zoom to cursor" you can do it by calculating the difference of cursor positions. You have to take the mouse position before zooming and after zooming and take the offset.