Is there any easy way how to zoom in and back out in canvas (JavaScript)? Basically I have a 400x400px canvas and I'd like to be able to zoom in with 'mousedown' (2x) and go back with 'mouseup'.
Spent last two days googling, but no luck so far. :(
Is there any easy way how to zoom in and back out in canvas (JavaScript)? Basically I have a 400x400px canvas and I'd like to be able to zoom in with 'mousedown' (2x) and go back with 'mouseup'.
Spent last two days googling, but no luck so far. :(
Building on the suggestion of using drawImage you could also combine this with scale function.
So before you draw the image scale the context to the zoom level you want:
ctx.scale(2, 2) // Doubles size of anything draw to canvas.
I've created a small example here http://jsfiddle.net/mBzVR/4/ that uses drawImage and scale to zoom in on mousedown and out on mouseup.
Try this out:
<!DOCTYPE HTML>
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js"></script>
<style>
body {
margin: 0px;
padding: 0px;
}
#wrapper {
position: relative;
border: 1px solid #9C9898;
width: 578px;
height: 200px;
}
#buttonWrapper {
position: absolute;
width: 30px;
top: 2px;
right: 2px;
}
input[type="button"] {
padding: 5px;
width: 30px;
margin: 0px 0px 2px 0px;
}
</style>
<script>
function draw(scale, translatePos) {
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
// clear canvas
context.clearRect(0, 0, canvas.width, canvas.height);
context.save();
context.translate(translatePos.x, translatePos.y);
context.scale(scale, scale);
context.beginPath(); // begin custom shape
context.moveTo(-119, -20);
context.bezierCurveTo(-159, 0, -159, 50, -59, 50);
context.bezierCurveTo(-39, 80, 31, 80, 51, 50);
context.bezierCurveTo(131, 50, 131, 20, 101, 0);
context.bezierCurveTo(141, -60, 81, -70, 51, -50);
context.bezierCurveTo(31, -95, -39, -80, -39, -50);
context.bezierCurveTo(-89, -95, -139, -80, -119, -20);
context.closePath(); // complete custom shape
var grd = context.createLinearGradient(-59, -100, 81, 100);
grd.addColorStop(0, "#8ED6FF"); // light blue
grd.addColorStop(1, "#004CB3"); // dark blue
context.fillStyle = grd;
context.fill();
context.lineWidth = 5;
context.strokeStyle = "#0000ff";
context.stroke();
context.restore();
}
window.onload = function() {
var canvas = document.getElementById("myCanvas");
var translatePos = {
x: canvas.width / 2,
y: canvas.height / 2
};
var scale = 1.0;
var scaleMultiplier = 0.8;
var startDragOffset = {};
var mouseDown = false;
// add button event listeners
document.getElementById("plus").addEventListener("click", function() {
scale /= scaleMultiplier;
draw(scale, translatePos);
}, false);
document.getElementById("minus").addEventListener("click", function() {
scale *= scaleMultiplier;
draw(scale, translatePos);
}, false);
// add event listeners to handle screen drag
canvas.addEventListener("mousedown", function(evt) {
mouseDown = true;
startDragOffset.x = evt.clientX - translatePos.x;
startDragOffset.y = evt.clientY - translatePos.y;
});
canvas.addEventListener("mouseup", function(evt) {
mouseDown = false;
});
canvas.addEventListener("mouseover", function(evt) {
mouseDown = false;
});
canvas.addEventListener("mouseout", function(evt) {
mouseDown = false;
});
canvas.addEventListener("mousemove", function(evt) {
if (mouseDown) {
translatePos.x = evt.clientX - startDragOffset.x;
translatePos.y = evt.clientY - startDragOffset.y;
draw(scale, translatePos);
}
});
draw(scale, translatePos);
};
jQuery(document).ready(function() {
$("#wrapper").mouseover(function(e) {
$('#status').html(e.pageX + ', ' + e.pageY);
});
})
</script>
</head>
<body onmousedown="return false;">
<div id="wrapper">
<canvas id="myCanvas" width="578" height="200">
</canvas>
<div id="buttonWrapper">
<input type="button" id="plus" value="+"><input type="button" id="minus" value="-">
</div>
</div>
<h2 id="status">
0, 0
</h2>
</body>
</html>
This works perfectly for me with zooming and mouse movement. You can customize it to use the mouse wheel up & down.
translatePos
so that the view remains centered. Right now if you change the offset and zoom, it will zoom on the center of the image and not where your current center of the canvas is. I can't find a way to update the translatePos
after rescaling to keep the zoom centered properly. Any suggestion ? –
Glandule Canvas zoom and pan
var ox = 0,
oy = 0,
px = 0,
py = 0,
scx = 1,
scy = 1;
var canvas = document.getElementById("myCanvas");
canvas.onmousedown = (e) => {
px = e.x;
py = e.y;
canvas.onmousemove = (e) => {
ox -= e.x - px;
oy -= e.y - py;
px = e.x;
py = e.y;
};
};
canvas.onmouseup = () => {
canvas.onmousemove = null;
};
canvas.onwheel = (e) => {
e.preventDefault();
let bfzx, bfzy, afzx, afzy;
[bfzx, bfzy] = StoW(e.x, e.y);
scx -= (10 * scx) / e.deltaY;
scy -= (10 * scy) / e.deltaY;
[afzx, afzy] = StoW(e.x, e.y);
ox += bfzx - afzx;
oy += bfzy - afzy;
};
var ctx = canvas.getContext("2d");
function draw() {
window.requestAnimationFrame(draw);
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (let i = 0; i <= 100; i += 10) {
let sx = 0,
sy = i;
let ex = 100,
ey = i;
[sx, sy] = WtoS(sx, sy);
[ex, ey] = WtoS(ex, ey);
ctx.beginPath();
ctx.moveTo(sx, sy);
ctx.lineTo(ex, ey);
ctx.stroke();
}
for (let i = 0; i <= 100; i += 10) {
let sx = i,
sy = 0;
let ex = i,
ey = 100;
[sx, sy] = WtoS(sx, sy);
[ex, ey] = WtoS(ex, ey);
ctx.beginPath();
ctx.moveTo(sx, sy);
ctx.lineTo(ex, ey);
ctx.stroke();
}
}
draw();
function WtoS(wx, wy) {
let sx = (wx - ox) * scx;
let sy = (wy - oy) * scy;
return [sx, sy];
}
function StoW(sx, sy) {
let wx = sx / scx + ox;
let wy = sy / scy + oy;
return [wx, wy];
}
<!DOCTYPE html>
<html>
<body>
<canvas id="myCanvas" width="" height="" style="border: 1px solid #d3d3d3">
Your browser does not support the canvas element.
</canvas>
</body>
</html>
If you have a source image or canvas element and your 400x400 canvas you want to draw into you can use the drawImage method to achieve zooming.
So for example, the full view might be like this
ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, canvas.width, canvas.height);
And a zoomed view might be like this
ctx.drawImage(img, img.width / 4, img.height / 4, img.width / 2, img.height / 2, 0, 0, canvas.width, canvas.height);
The first parameter to drawImage is the image element or canvas element to draw, the next 4 are the x, y, width and height to sample from the source and the last 4 parameters are the x, y, width and height of the region to draw in the canvas. It will then handle the scaling for you.
You would just need to pick the width and height for the source sample based on the zoom level and the x and y based on where the mouse is clicked minus half the calculated width and height (but you will need to ensure the rectangle isn't out of bounds).
IIRC Canvas is a raster style bitmap. it wont be zoomable because there's no stored information to zoom to.
Your best bet is to keep two copies in memory (zoomed and non) and swap them on mouse click.
Here my zoom function :
Zoom(factor_x, factor_y, graph = this.graph, translate_x=this.ctx.canvas.width/2,translate_y=this.ctx.canvas.height/2){
const new_scale_x = this.scale_x * factor_x
const new_scale_y = this.scale_y * factor_y
// Update values
this.translate_x += translate_x * ((this.scale_x - new_scale_x))
this.translate_y += translate_y * ((this.scale_y - new_scale_y))
this.scale_x = new_scale_x
this.scale_y = new_scale_y
this.ctx.setTransform(this.scale_x, 0, 0, this.scale_y, this.translate_x, this.translate_y) // Transform
DrawGraph(graph)
},
For zoom the factor can be 1,3 and for dezoom 0,7 for exemple
One option is to use css zoom feature:
$("#canvas_id").css("zoom","x%");
© 2022 - 2024 — McMap. All rights reserved.