How to bound image pan when zooming (HTML Canvas)

Viewed 3892

I'm trying to limit boundaries and I'm running into issues. I'm upscaling an image from another canvas and then implementing zoom and pan. My issue (code below) is with limiting/capping the offsetx/y so that you never see the whitespace; only parts of the image.

Pardon the mess! Any help is appreciated! :P

var zoomIntensity = 0.2;

var canvas = document.getElementById("canvas");
var canvas2 = document.getElementById("canvas2");
var context = canvas.getContext("2d");
var context2 = canvas2.getContext("2d");
var width = 200;
var height = 200;

var scale = 1;
var originx = 0;
var originy = 0;

var offset = {x:0, y:0};

//fill smaller canvas with random pixels
for(var x = 0; x < 100; x++)
for(var y = 0; y < 100; y++)
{
  var rando = function(){return Math.floor(Math.random() * 9)};
  var val = rando();
  context2.fillStyle = "#" + val + val + val;
  context2.fillRect(x,y,1,1);
}

//draw the larger canvas
function draw()
{
  context.imageSmoothingEnabled = false;
    
    // Clear screen to white.
    context.fillStyle = "white";
    context.fillRect(originx - offset.x, originy - offset.y, width/scale, height/scale);
  context.drawImage(canvas2, 0,0, width, height);
}

// Draw loop at 60FPS.
setInterval(draw, 1000/60);

canvas.onmousewheel = function (event){
    event.preventDefault();
    
    // Get mouse offset.
    var mousex = event.clientX - canvas.offsetLeft;
    var mousey = event.clientY - canvas.offsetTop;
    
    // Normalize wheel to +1 or -1.
    var wheel = event.wheelDelta/120;

    // Compute zoom factor.
    var zoom = Math.exp(wheel*zoomIntensity);
    
    // Translate so the visible origin is at the context's origin.
    context.translate(originx - offset.x, originy - offset.y); //offset is panning
    
    //make sure we don't zoom out further than normal scale
    var resultingScale = scale * zoom;
    if(resultingScale < 1)
     zoom = 1/scale;
  
    // Compute the new visible origin. Originally the mouse is at a
    // distance mouse/scale from the corner, we want the point under
    // the mouse to remain in the same place after the zoom, but this
    // is at mouse/new_scale away from the corner. Therefore we need to
    // shift the origin (coordinates of the corner) to account for this.
    originx -= mousex/(scale*zoom) - mousex/scale;
    originy -= mousey/(scale*zoom) - mousey/scale;
    
    // Scale it (centered around the origin due to the trasnslate above).
    context.scale(zoom, zoom);
    
    // Offset the visible origin to it's proper position.
    context.translate(-originx + offset.x, -originy + offset.y); //offset is panning

    // Update scale and others.
    scale *= zoom;
}

document.onkeydown = function (evt)
{
 var offsetx = 0;
  var offsety = 0;
  
 switch(evt.which)
 {
      case 37: //left
        offsetx = 1;
        break;
      case 38: //up
        offsety = 1;
        break;
      case 39: //right
        offsetx = -1
        break;
      case 40: //down
        offsety = -1;
        break;
  }
  
  offsetx /= scale;
  offsety /= scale;
  
  offset.x += offsetx;
  offset.y += offsety;
  
  context.translate(offsetx,offsety);
}
<canvas id="canvas" width="200" height="200"></canvas>
<canvas id="canvas2" width="100" height="100"></canvas>

1 Answers
Related