JS Canvas 放大和缩小翻译不会居中

Posted

技术标签:

【中文标题】JS Canvas 放大和缩小翻译不会居中【英文标题】:JS Canvas Zoom in and Zoom out translate doesn't settle to center 【发布时间】:2019-06-20 19:33:52 【问题描述】:

我正在开发自己的画布抽屉项目,只是卡在了放大/缩小功能中。在我的项目中,我使用缩放和平移来进行缩放,因为我想将所有画布及其元素保持在中心。 在画了一点点之后(不是数学天才),我成功绘制了以下公式用于翻译过程,因此画布在缩放后将保持在其视口的中间:旧的宽度和高度 / 2 -新的宽度和高度(旧的宽度和高度乘以比例步长,在我的例子中是 1.1)/2。 从逻辑上讲,这应该使它起作用。但是在尝试了几次放大和缩小之后,我可以清楚地看到画布有一点偏移,并且它没有居中到视口的中间(我的视口是指代表画布的描边正方形)。

我将我的代码从我的项目中取出并放在小提琴中,就在这里:

https://jsfiddle.net/s82qambx/3/

index.html

<div id="letse-canvas-container">
<canvas id="letse-canvas"  ></canvas>
<canvas id="letse-upper-canvas"  ></canvas>
</div>
<div id="buttons">
<button id="zoomin">
Zoom-in
</button>
<button id="zoomout">
Zoom-out
</button>
</div>

main.js

const canvas = 
canvas: document.getElementById('letse-canvas'),
upperCanvas: document.getElementById('letse-upper-canvas')
;

canvas.canvas.ctx = canvas.canvas.getContext('2d');
canvas.upperCanvas.ctx = canvas.upperCanvas.getContext('2d');

const CANVAS_STATE = 
    canvas: 
    zoom: 1,
width: 300,
height: 300



const Elements = [
    
    x: 20,
    y: 20,
    width: 30,
    height: 40
  ,
  
    x:170,
    y:30,
    width: 100,
    height: 100
  
];

const button = 
zoomin: document.getElementById('zoomin'),
zoomout: document.getElementById('zoomout')


button.zoomin.addEventListener('click', (e) => 
canvasZoomIn(e, canvas);
);
button.zoomout.addEventListener('click', (e) => 
canvasZoomOut(e, canvas);
);

function canvasZoomIn(e, canvas) 
const zoomData = getZoomData('in');

canvas.upperCanvas.ctx.scale(zoomData.zoomStep, zoomData.zoomStep);
canvas.upperCanvas.ctx.translate(zoomData.translateX, zoomData.translateY);
canvas.upperCanvas.ctx.clearRect(0, 0, 300, 300);

canvas.canvas.ctx.scale(zoomData.zoomStep, zoomData.zoomStep);
canvas.canvas.ctx.translate(zoomData.translateX, zoomData.translateY);
canvas.canvas.ctx.clearRect(0, 0, 300, 300);
Elements.forEach((element) => 
canvas.canvas.ctx.strokeRect(element.x, element.y, element.width, element.height);
);

CANVAS_STATE.canvas.zoom = zoomData.scale;
CANVAS_STATE.canvas.width = zoomData.docWidth;
CANVAS_STATE.canvas.height = zoomData.docHeight;

console.log(CANVAS_STATE.canvas.zoom, 'zoom');
console.log(CANVAS_STATE.canvas.width, 'width');
console.log(CANVAS_STATE.canvas.height, 'height');

canvas.canvas.ctx.strokeRect(0, 0, 300, 300);
canvas.canvas.ctx.beginPath();
canvas.canvas.ctx.moveTo(0, 150);
canvas.canvas.ctx.lineTo(300, 150);
canvas.canvas.ctx.stroke();
CANVAS_STATE.canvas.draggable = canvas.canvas.width < CANVAS_STATE.canvas.width || canvas.canvas.height < CANVAS_STATE.canvas.height;


function canvasZoomOut(e, canvas) 
const zoomData = getZoomData('out');

canvas.upperCanvas.ctx.scale(zoomData.zoomStep, zoomData.zoomStep);
canvas.upperCanvas.ctx.translate(zoomData.translateX, zoomData.translateY);
canvas.upperCanvas.ctx.clearRect(0, 0, canvas.canvas.width, canvas.canvas.height);

canvas.canvas.ctx.scale(zoomData.zoomStep, zoomData.zoomStep);
canvas.canvas.ctx.translate(zoomData.translateX, zoomData.translateY);
canvas.canvas.ctx.clearRect(0, 0, canvas.canvas.width, canvas.canvas.height);
Elements.forEach((element) => 
canvas.canvas.ctx.strokeRect(element.x, element.y, element.width, element.height);
);

CANVAS_STATE.canvas.zoom = zoomData.scale;
CANVAS_STATE.canvas.width = zoomData.docWidth;
CANVAS_STATE.canvas.height = zoomData.docHeight;

console.log(CANVAS_STATE.canvas.zoom, 'zoom');
console.log(CANVAS_STATE.canvas.width, 'width');
console.log(CANVAS_STATE.canvas.height, 'height');

canvas.canvas.ctx.strokeRect(0, 0, 300, 300);
canvas.canvas.ctx.beginPath();
canvas.canvas.ctx.moveTo(0, 150);
canvas.canvas.ctx.lineTo(300, 150);
canvas.canvas.ctx.stroke();
CANVAS_STATE.canvas.draggable = canvas.canvas.width < CANVAS_STATE.canvas.width || canvas.canvas.height < CANVAS_STATE.canvas.height;


function getZoomData(zoom) 
const zoomStep = zoom === 'in' ? 1.1 : 1 / 1.1;
const scale = CANVAS_STATE.canvas.zoom * zoomStep;
const docWidth = CANVAS_STATE.canvas.width * zoomStep;
const docHeight = CANVAS_STATE.canvas.height * zoomStep;
const translateX = CANVAS_STATE.canvas.width / 2 - docWidth / 2;
const translateY = CANVAS_STATE.canvas.height / 2 - docHeight / 2;

console.log(zoomStep);
console.log(scale, 'check');
console.log(docWidth);
console.log(docHeight);
console.log(translateX, 'check');
console.log(translateY, 'check');

return 
zoomStep,
scale,
docWidth,
docHeight,
translateX,
translateY
;

main.css

#letse-canvas-container 
position: relative;
float: left;


#letse-canvas 
border: 1px solid rgb(0, 0, 0);
/* visibility: hidden; */


#letse-upper-canvas 
/* position: absolute; */
/* top: 0px; */
left: 0px;
border: 1px solid;
/* visibility: hidden; */

有人可以提出一个理由吗?我在这里错过了什么?

【问题讨论】:

【参考方案1】:

好的!因此,在网上搜索并测试了几个选项后,我设法得出了正确的公式。我用过:

 function getZoomData(zoom) 
    const zoomStep = zoom === 'in' ? 1.1 : 1 / 1.1;
    const oldZoom = CANVAS_STATE.canvas.zoom;
    const newZoom = oldZoom * zoomStep;
    const zoomDifference = newZoom - oldZoom;
    const docWidth = CANVAS_STATE.canvas.width * newZoom;
    const docHeight = CANVAS_STATE.canvas.height * newZoom;
    const translateX = (-(canvas.canvas.width / 2 * zoomDifference / newZoom));
    const translateY = (-(canvas.canvas.height / 2 * zoomDifference / newZoom));

【讨论】:

以上是关于JS Canvas 放大和缩小翻译不会居中的主要内容,如果未能解决你的问题,请参考以下文章

前端面试 HTML— Svg 和Canvas有什么区别?

svg好还是canvas好

使用canvas画图,图形模糊怎么办

HTML5 Canvas元素绘制地图,已绘制出地图,并且地图可放大缩小,怎样实现鼠标移动到一幢楼时显示楼的名称

Java AWT 图形界面编程使用鼠标滚轮放大缩小 Canvas 画布 ( 鼠标滚轮事件监听器 MouseWheelListener )

canvas里有一张图,怎么实现鼠标可以拖动该图片移动,放大缩小旋转