Reputation: 3083
I have an image drawn in a canvas, and I want to be able to zoom in and zoom out with any scale, while keeping the image in the center. To do this, my approach is to change the scale of the canvas context and re-draw the image, but I need to calculate the top left corner of the new image, or else it won't be centred.
function zoom( canvas, context, scale ) {
var image = new Image();
image.src = canvas.toDataURL( 'image/png' );
canvas.clearRect( 0, 0, canvas.width, canvas.height );
context.scale( scale, scale );
var x = ???,
y = ???;
context.drawImage( image, x, y );
}
The question is how to calculate x
and y
in such a way that it works for any scale. I've figured out some special cases, but I can't find the general rule. When the scale is 0.5, the rule to keep the image centred is:
var x = canvas.width / 2,
y = canvas.height / 2;
When the scale is 2, the rule is:
var x = -canvas.width / 4,
y = -canvas.height / 4;
And when the scale is 3, the rule is:
var x = -canvas.width / 3,
y = -canvas.height / 3;
So what is the general rule? Or is there a better approach?
Upvotes: 3
Views: 4799
Reputation: 54026
For the center.
Best to do it this way. ctx
is canvas context
// scale the coordinate system to required scale and set the origin (0,0)
// to the center of the canvas
ctx.setTransform(scale, 0, 0, scale, ctx.canvas.width * 0.5, ctx.canvas.height * 0.5);
ctx.drawImage(image, image.width * -0.5, image.height * -0.5); // draw the image offset by half
Or you can avoid setting the transformation and just draw the image scaled
// get the position is half of the canvas width minus the scaled width of the image
var x = (ctx.canvas.width - image.width * scale) * 0.5;
var y = (ctx.canvas.height - image.height * scale) * 0.5;
ctx.drawImage(image, x, y, image.width * scale, image.height * scale); // drw image with scaled width and height
Or as you want, scale the canvas and keep the origin in the top left corner. Because the canvas does not change its actual size you have to invert the scale change, which just means divide its size by the scale rather than multiply.
ctx.scale(scale, scale);
var x = (ctx.canvas.width / scale - image.width) * 0.5;
var y = (ctx.canvas.height / scale - image.height) * 0.5;
ctx.drawImage(image, x, y);
Upvotes: 11
Reputation: 815
getWidth() {
return this.rect.width * this.scale;
}
getHeight() {
return this.rect.height * this.scale;
}
setScale(scale) {
const oldWidth = this.getWidth();
const oldHeight = this.getHeight();
this.scale = scale;
const newWidth = this.getWidth();
const newHeight = this.getHeight();
const addedWidth = newWidth - oldWidth;
const addedHeight = newHeight - oldHeight;
this.rect.pos.x -= addedWidth / 2;
this.rect.pos.y -= addedHeight / 2;
}
Upvotes: 0