HTML5 Canvas: Zooming

JavascriptCanvas

Javascript Problem Overview


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. :(

Javascript Solutions


Solution 1 - Javascript

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.

Solution 2 - Javascript

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.

Here is a fiddle

Solution 3 - Javascript

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).

Solution 4 - Javascript

Canvas zoom and pan

<!DOCTYPE html>
<html>
<body>

<canvas id="myCanvas" width="" height=""
style="border:1px solid #d3d3d3;">
Your browser does not support the canvas element.
</canvas>

<script>
console.log("canvas")
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)=>{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];
}

</script>

</body>
</html>

Solution 5 - Javascript

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.

Solution 6 - Javascript

One option is to use css zoom feature:

$("#canvas_id").css("zoom","x%"); 

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionjack mooreView Question on Stackoverflow
Solution 1 - JavascriptCastrohengeView Answer on Stackoverflow
Solution 2 - JavascriptGOKView Answer on Stackoverflow
Solution 3 - JavascriptKyle JonesView Answer on Stackoverflow
Solution 4 - Javascripta.gulcanView Answer on Stackoverflow
Solution 5 - JavascriptKarlView Answer on Stackoverflow
Solution 6 - JavascriptmbastolaView Answer on Stackoverflow