I am working on a canvas application where I want to add a zoom feature. However, I am struggling to draw pixels after any zoom thats greater than 1 is applied.
It just draws the pixel on the place where it would be correct if the origin was at the left top corner.
I need a calculation that finds the correct pixel, while zoom and translate is applied to the context of my canvas.
Here is my zoom function
<code> zoom(e: WheelEvent) {
this.zoomLevel -= e.deltaY * 0.01;
this.zoomLevel = Math.round(Math.max(1, Math.min(this.zoomLevel, 10)));
const rect = this.canvas.getBoundingClientRect();
if (this.zoomLevel == 1) {
this.originX = Math.round((e.clientX - rect.left) / (rect.right - rect.left) * this.dimensions[0])
this.originY = Math.round((e.clientY - rect.top) / (rect.bottom - rect.top) * this.dimensions[1])
this.ctx.translate(this.originX, this.originY);
this.ctx.scale(this.zoomLevel, this.zoomLevel)
this.ctx.translate(-this.originX, -this.originY);
<code> zoom(e: WheelEvent) {
this.zoomLevel -= e.deltaY * 0.01;
this.zoomLevel = Math.round(Math.max(1, Math.min(this.zoomLevel, 10)));
this.resizeCanvas();
const rect = this.canvas.getBoundingClientRect();
if (this.zoomLevel == 1) {
this.originX = 0;
this.originY = 0;
}
else {
this.originX = Math.round((e.clientX - rect.left) / (rect.right - rect.left) * this.dimensions[0])
this.originY = Math.round((e.clientY - rect.top) / (rect.bottom - rect.top) * this.dimensions[1])
}
this.ctx.translate(this.originX, this.originY);
this.ctx.scale(this.zoomLevel, this.zoomLevel)
this.ctx.translate(-this.originX, -this.originY);
this.drawAllPixels();
}
</code>
zoom(e: WheelEvent) {
this.zoomLevel -= e.deltaY * 0.01;
this.zoomLevel = Math.round(Math.max(1, Math.min(this.zoomLevel, 10)));
this.resizeCanvas();
const rect = this.canvas.getBoundingClientRect();
if (this.zoomLevel == 1) {
this.originX = 0;
this.originY = 0;
}
else {
this.originX = Math.round((e.clientX - rect.left) / (rect.right - rect.left) * this.dimensions[0])
this.originY = Math.round((e.clientY - rect.top) / (rect.bottom - rect.top) * this.dimensions[1])
}
this.ctx.translate(this.originX, this.originY);
this.ctx.scale(this.zoomLevel, this.zoomLevel)
this.ctx.translate(-this.originX, -this.originY);
this.drawAllPixels();
}
Here is the function where I am trying to calculate the pixels X and Y index, over which the user is hovering
const mouseX = e.clientX;
const mouseY = e.clientY;
const rect = this.canvas.getBoundingClientRect();
const scaleFactor = this.zoomLevel;
console.log(this.originX, this.originY, scaleFactor)
const pixelX = Math.floor((mouseX - rect.left) * (this.dimensions[0] / rect.width)); // This formular only works when this.zoomLevel is 1
const pixelY = Math.floor((mouseY - rect.top) * (this.dimensions[1] / rect.height)); // This formular only works when this.zoomLevel is 1
const p = this.pixelArr.find(item => item.x === pixelX && item.y === pixelY);
this.drawPreviewPixel(pixelX, pixelY, p?.color);
<code>onHover(e: any) {
const mouseX = e.clientX;
const mouseY = e.clientY;
const rect = this.canvas.getBoundingClientRect();
const scaleFactor = this.zoomLevel;
console.log(this.originX, this.originY, scaleFactor)
const pixelX = Math.floor((mouseX - rect.left) * (this.dimensions[0] / rect.width)); // This formular only works when this.zoomLevel is 1
const pixelY = Math.floor((mouseY - rect.top) * (this.dimensions[1] / rect.height)); // This formular only works when this.zoomLevel is 1
const p = this.pixelArr.find(item => item.x === pixelX && item.y === pixelY);
this.drawPreviewPixel(pixelX, pixelY, p?.color);
</code>
onHover(e: any) {
const mouseX = e.clientX;
const mouseY = e.clientY;
const rect = this.canvas.getBoundingClientRect();
const scaleFactor = this.zoomLevel;
console.log(this.originX, this.originY, scaleFactor)
const pixelX = Math.floor((mouseX - rect.left) * (this.dimensions[0] / rect.width)); // This formular only works when this.zoomLevel is 1
const pixelY = Math.floor((mouseY - rect.top) * (this.dimensions[1] / rect.height)); // This formular only works when this.zoomLevel is 1
const p = this.pixelArr.find(item => item.x === pixelX && item.y === pixelY);
this.drawPreviewPixel(pixelX, pixelY, p?.color);
I am able to zoom in and out the canvas, but I am having trouble calculating the correct canvas coordinates from screen coordinates when a zoom and origin is applied.
The this.drawPreviewPixel successfully works on any zoom when I manually input the X and Y index (where the pixel should be drawn).
I also can successfully use drawPreviewPixel, when I zoom in at the exact left top corner.