【问题标题】:How to zoom to center of canvas, not to center of context如何缩放到画布中心,而不是上下文中心
【发布时间】:2016-12-28 11:11:59
【问题描述】:

我有一个尺寸为 400 x 400 的画布。我在上面绘制了一个 200 x 200 的地图区域。 我已将其翻译到画布的中心。我可以放大和缩小,一切都很好。但是,当我平移时,它会从我的地图区域的中心缩放。无论地图区域在哪里,我都希望它始终从画布的中心缩放。我想我需要以某种方式否定泛坐标,但我想不通。 这是我的代码:

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(){
	document.getElementById("zoomin").click();
	{ scaleFactor*=1.1; drawTranslated(); };
}
function zoomOut(){
	document.getElementById("zoomout").click();
	{ scaleFactor/=1.1; drawTranslated(); };
}
function panUp(){
	document.getElementById("panup").click();
	{ panY-=25; drawTranslated(); };
}
function panDown(){
	document.getElementById("pandown").click();
	{ panY+=25; drawTranslated(); };
}
function panLeft(){
	document.getElementById("panleft").click();
	{ panX-=25; drawTranslated(); };
}
function panRight(){
	document.getElementById("panright").click();
	{ 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>

【问题讨论】:

    标签: javascript canvas zooming centering pan


    【解决方案1】:

    经过一段时间试图找到一些方程来解决这个问题,我想我已经找到了解决方案。

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

    通过先平移,然后缩放,它将从上下文的中心(在本例中为绿色正方形)缩放。但是,只需将其更改为:

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

    它将从画布的中心缩放。 它似乎做我想做的事,所以除非我弄错了,否则我相信这就是答案。

    我已经添加了另一个 sn-p。唯一的变化是这两条线,但我认为这对人们能够看到它所带来的不同是有帮助的。

    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() {
            document.getElementById("zoomin").click(); {
    	        scaleFactor *= 1.1;
    	        drawTranslated();
            };
        };
    
    	function zoomOut() {
    	  document.getElementById("zoomout").click(); {
    	    scaleFactor /= 1.1;
    	    drawTranslated();
    	  };
    	};
    
    	function panUp() {
    	  document.getElementById("panup").click(); {
    	    panY -= 25;
    	    drawTranslated();
    	  };
    	};
    
    	function panDown() {
    	  document.getElementById("pandown").click(); {
    	    panY += 25;
    	    drawTranslated();
    	  };
    	};
    
    	function panLeft() {
    	  document.getElementById("panleft").click(); {
    	    panX -= 25;
    	    drawTranslated();
    	  };
    	};
    
    	function panRight() {
    	  document.getElementById("panright").click(); {
    	    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>

    【讨论】:

      【解决方案2】:

      肯定有更好的方法,但在 Fabric.js 中你可以做到

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

      在此处查看更多信息Canvas

      对于更纯粹的解决方案,您还可以尝试使用

      将上下文翻译成画布大小的一半
      ctx.translate()
      

      可能有帮助的小提琴

      http://jsfiddle.net/m1erickson/QEuw4/

      【讨论】:

      • 我在这个项目中取得了很多进展,但随着我了解的更多,我会继续研究它。最初我有 Javascript 和 jQuery,但在它们之间感到困惑。我现在还不想使用库,也许当我好一点的时候,所以我想我现在只是在寻找一个纯 Javascript 解决方案。谢谢。
      • 我也对答案感兴趣,如果您找到解决方案,请告诉我!我有一些想法,但我相信其他人可以提出更好的解决方案
      • 我加了一个别人做的代码sn-p,可能有帮助!
      • 感谢小提琴 Muntasir。它非常有用,因为它让我不用问如何让我的点跳动:)
      • 不用担心。如果有帮助,请单击我的答案左侧的复选标记和向上箭头。
      猜你喜欢
      • 1970-01-01
      • 2015-06-21
      • 2020-04-08
      • 1970-01-01
      • 2015-11-22
      • 2018-03-07
      • 2015-04-27
      • 2015-09-01
      • 1970-01-01
      相关资源
      最近更新 更多