admin管理员组

文章数量:1410682

I have a canvas, size 400 x 400. On it, i have drawn a map area, 200 x 200. I have translated this to the center of the canvas. I can zoom in and out, all is well. But, when i pan, it zooms from the center of my map area. I want it to always zoom from the center of the canvas no matter where the map area is. I think i need to negate the pan coords somehow, but i can't figure it out. Here is my code:

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var canvas1 = document.getElementById("canvasX");
var ctxX = canvas1.getContext("2d");

var cw = canvas.width;
var ch = canvas.height;
var mapW = 200;
var mapH = 200;
var panX=0;
var panY=0;
var scaleFactor=1.00;

drawTranslated();

function zoomIn(){
    scaleFactor*=1.1; 
  drawTranslated(); 
}

function zoomOut(){
    scaleFactor/=1.1; 
  drawTranslated(); 
}

function panUp(){
    panY-=25; 
    drawTranslated(); 
}

function panDown(){
    panY+=25; 
  drawTranslated();
}

function panLeft(){
    panX-=25; 
  drawTranslated(); 
}

function panRight(){
    panX+=25; 
  drawTranslated(); 
}

function drawTranslated(){
    // canvas
    ctx.clearRect(0,0,cw,ch);
    ctx.save();
    ctx.translate(cw/2, ch/2);
    ctx.translate(panX,panY);
    ctx.scale(scaleFactor, scaleFactor);
    ctx.fillStyle = "Green";
    ctx.fillRect(mapW/-2, mapH/-2, mapW, mapH);
    ctx.restore();

  // canvasX
  ctxX.clearRect(0,0,cw,ch);
  ctxX.save();
  ctxX.translate(cw/2, ch/2);               
  ctxX.beginPath();

  ctxX.moveTo(0, 25);
  ctxX.lineTo(0, -25);
  ctxX.moveTo(-25, 0);
  ctxX.lineTo(25, 0);

  ctxX.closePath();
  ctxX.lineWidth = 1;
  ctxX.strokeStyle = 'Black';
  ctxX.stroke();
  ctxX.restore();
}
#wrapper {position: relative;}
canvas {position: absolute; border: 1px solid Black;}
<!DOCTYPE html>
<html>
<body>
    <div id="wrapper">
    <button id="zoomin" class="nav" title="Zoom In" onclick="zoomIn()">&#43;</button>
    <button id="zoomout" class="nav" title="Zoom Out" onclick="zoomOut()">&#8722;</button>
    <button id="panup" class="nav" title="Up" onclick="panUp()">&#8679;</button>
    <button id="pandown" class="nav" title="Down" onclick="panDown()">&#8681;</button>
    <button id="panleft" class="nav" title="Left" onclick="panLeft()">&#8678;</button>
    <button id="panright" class="nav" title="Right" onclick="panRight()">&#8680;</button>
    </div>
    <div id="wrapper">
    <canvas id="myCanvas" width="400" height="400"></canvas>
    <canvas id="canvasX" width="400" height="400"></canvas>
    </div>
</body>
</html>

I have a canvas, size 400 x 400. On it, i have drawn a map area, 200 x 200. I have translated this to the center of the canvas. I can zoom in and out, all is well. But, when i pan, it zooms from the center of my map area. I want it to always zoom from the center of the canvas no matter where the map area is. I think i need to negate the pan coords somehow, but i can't figure it out. Here is my code:

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var canvas1 = document.getElementById("canvasX");
var ctxX = canvas1.getContext("2d");

var cw = canvas.width;
var ch = canvas.height;
var mapW = 200;
var mapH = 200;
var panX=0;
var panY=0;
var scaleFactor=1.00;

drawTranslated();

function zoomIn(){
    scaleFactor*=1.1; 
  drawTranslated(); 
}

function zoomOut(){
    scaleFactor/=1.1; 
  drawTranslated(); 
}

function panUp(){
    panY-=25; 
    drawTranslated(); 
}

function panDown(){
    panY+=25; 
  drawTranslated();
}

function panLeft(){
    panX-=25; 
  drawTranslated(); 
}

function panRight(){
    panX+=25; 
  drawTranslated(); 
}

function drawTranslated(){
    // canvas
    ctx.clearRect(0,0,cw,ch);
    ctx.save();
    ctx.translate(cw/2, ch/2);
    ctx.translate(panX,panY);
    ctx.scale(scaleFactor, scaleFactor);
    ctx.fillStyle = "Green";
    ctx.fillRect(mapW/-2, mapH/-2, mapW, mapH);
    ctx.restore();

  // canvasX
  ctxX.clearRect(0,0,cw,ch);
  ctxX.save();
  ctxX.translate(cw/2, ch/2);               
  ctxX.beginPath();

  ctxX.moveTo(0, 25);
  ctxX.lineTo(0, -25);
  ctxX.moveTo(-25, 0);
  ctxX.lineTo(25, 0);

  ctxX.closePath();
  ctxX.lineWidth = 1;
  ctxX.strokeStyle = 'Black';
  ctxX.stroke();
  ctxX.restore();
}
#wrapper {position: relative;}
canvas {position: absolute; border: 1px solid Black;}
<!DOCTYPE html>
<html>
<body>
    <div id="wrapper">
    <button id="zoomin" class="nav" title="Zoom In" onclick="zoomIn()">&#43;</button>
    <button id="zoomout" class="nav" title="Zoom Out" onclick="zoomOut()">&#8722;</button>
    <button id="panup" class="nav" title="Up" onclick="panUp()">&#8679;</button>
    <button id="pandown" class="nav" title="Down" onclick="panDown()">&#8681;</button>
    <button id="panleft" class="nav" title="Left" onclick="panLeft()">&#8678;</button>
    <button id="panright" class="nav" title="Right" onclick="panRight()">&#8680;</button>
    </div>
    <div id="wrapper">
    <canvas id="myCanvas" width="400" height="400"></canvas>
    <canvas id="canvasX" width="400" height="400"></canvas>
    </div>
</body>
</html>

Share Improve this question edited Sep 7, 2023 at 17:21 RWC 5,0622 gold badges25 silver badges31 bronze badges asked Aug 22, 2016 at 1:51 Cyb3rMannCyb3rMann 1271 silver badge12 bronze badges 1
  • Nice code. Very effective. – RWC Commented Sep 7, 2023 at 17:16
Add a ment  | 

2 Answers 2

Reset to default 4

After some time of trying to find some equation to solve this, i think i have found the solution.

ctx.translate(panX,panY);
ctx.scale(scaleFactor, scaleFactor);

By panning first, then scaling, it will zoom from the center of the context (In this case the green square). However, simply changing it around to:

ctx.scale(scaleFactor, scaleFactor);
ctx.translate(panX,panY);

it will zoom from the center of the canvas. It seems to do what i want it to, so unless i am mistaken, i believe this is the answer.

I have included another snippet. The only changes are those 2 lines, but i think it would be helpful for people to able to see the difference it makes.

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var canvas1 = document.getElementById("canvasX");
var ctxX = canvas1.getContext("2d");

var cw = canvas.width;
var ch = canvas.height;
var mapW = 200;
var mapH = 200;
var panX = 0;
var panY = 0;
var scaleFactor = 1.00;

drawTranslated();

function zoomIn(){
    scaleFactor*=1.1; 
  drawTranslated(); 
}

function zoomOut(){
    scaleFactor/=1.1; 
  drawTranslated(); 
}

function panUp(){
    panY-=25; 
  drawTranslated(); 
}

function panDown(){
    panY+=25; 
  drawTranslated();
}

function panLeft(){
    panX-=25; 
  drawTranslated(); 
}

function panRight(){
    panX+=25; 
  drawTranslated(); 
}

    function drawTranslated() {

      // canvas
      ctx.clearRect(0, 0, cw, ch);
      ctx.save();
      ctx.translate(cw / 2, ch / 2);
      ctx.scale(scaleFactor, scaleFactor);
      ctx.translate(panX, panY);
      ctx.fillStyle = "Green";
      ctx.fillRect(mapW / -2, mapH / -2, mapW, mapH);
      ctx.restore();

      // canvasX
      ctxX.clearRect(0, 0, cw, ch);
      ctxX.save();
      ctxX.translate(cw / 2, ch / 2);
      ctxX.beginPath();

      ctxX.moveTo(0, 25);
      ctxX.lineTo(0, -25);
      ctxX.moveTo(-25, 0);
      ctxX.lineTo(25, 0);

      ctxX.closePath();
      ctxX.lineWidth = 1;
      ctxX.strokeStyle = 'Black';
      ctxX.stroke();
      ctxX.restore();
    };
#wrapper {
  position: relative;
}
canvas {
  position: absolute;
  border: 1px solid Black;
}
<div id="wrapper">
  <button id="zoomin" class="nav" title="Zoom In" onclick="zoomIn()">&#43;</button>
  <button id="zoomout" class="nav" title="Zoom Out" onclick="zoomOut()">&#8722;</button>
  <button id="panup" class="nav" title="Up" onclick="panUp()">&#8679;</button>
  <button id="pandown" class="nav" title="Down" onclick="panDown()">&#8681;</button>
  <button id="panleft" class="nav" title="Left" onclick="panLeft()">&#8678;</button>
  <button id="panright" class="nav" title="Right" onclick="panRight()">&#8680;</button>
</div>
<div id="wrapper">
  <canvas id="canvas" width="400" height="400"></canvas>
  <canvas id="canvasX" width="400" height="400"></canvas>
</div>

There surely is a better way but in Fabric.js you can do

canvas.zoomToPoint(new fabric.Point(canvas.width / 2, canvas.height / 2), canvas.getZoom() / ZOOM_PERCENT);

See more here Canvas

For a more pure solution, you can also try translating the context by half the canvas size using

ctx.translate()

A fiddle that might help

http://jsfiddle/m1erickson/QEuw4/

本文标签: javascriptHow to zoom to center of canvasnot to center of contextStack Overflow