Reputation: 77
I am building an interactive map of a small geographical area using HTML canvas. The canvas will be the full width and height of the map image used. The map will have a few points dotted on it, and when one is clicked, the canvas should centre on this point and then zoom in on it.
I have so far tried this by using translate
on the drawing context, drawing the map image so that the clicked point sits in the centre of the canvas, and then using scale
to zoom, as follows:
var clickX = e.offsetX || (e.pageX - canvas.offsetLeft);
var clickY = e.offsetY || (e.pageY - canvas.offsetTop);
clickedPoint = { x: clickX, y: clickY };
ctx.translate(
canvas.width/2 - clickedPoint.x,
canvas.height/2 - clickedPoint.y
);
ctx.scale(2, 2);
However, when I draw at this point, the image doesn't appear where expected. I'm guessing because the translated point doesn't line up after the scale function, as the translate happens correctly without the scale, but I can't seem to get this working - can anyone explain how to resolve this?
EDIT: example link - http://staging.clicky.co.uk/canvas/
Upvotes: 2
Views: 2442
Reputation: 54039
To scale and zoom at a point on the canvas you must know the current zoom / scale and current origin. If you do not track this information you can not correctly scale at a point on the canvas.
If you have the scale and origin which from default is scale = 1
, and origin = {x:0,y:0}
// scale is current scale
// origin is current origin
function scaleAt (at, amount) { // at in screen coords amount is amount to scale
scale *= amount;
origin.x = at.x - (at.x - origin.x) * amount;
origin.y = at.y - (at.y - origin.y) * amount;
};
var scale = 1;
const origin = {x : 0, y : 0};
// in mouse event
// scale is change in scale
scaleAt(clickedPoint,2); // scale 2 times at clickedPoint
// then set the transform
ctx.setTransform(scale,0,0,scale,origin.x,origin.y)
To center a point on an image at the center of the canvas using a fixed scale
// scale and origin from above code.
// newScale is absolute scale
function scaleMoveCenter (point, newScale) {
scale = newScale;
origin.x = canvas.width / 2 - point.x * scale;
origin.y = canvas.height / 2 - point.y * scale;
}
// in mouse event
scaleMoveCenter (clickedPoint,2);
// then set the transform
ctx.setTransform(scale,0,0,scale,origin.x,origin.y)
If the canvas already has a scale and origin set that is not default you need to find the point in that coordinate system.
//
const realPos = {};
realPos.x = (clickedPoint.x - origin.x ) / scale;
realPos.y = (clickedPoint.y - origin.y ) / scale;
// increase scale by 2
scaleMoveCenter (realPos ,scale * 2);
// then set the transform
ctx.setTransform(scale,0,0,scale,origin.x,origin.y)
Upvotes: 4