javascript - 放大画布中的点
问题描述
我试图放大一个给定的点,老实说我无法理解我做错了什么。
首先,我得到鼠标点并使用画布变换矩阵在画布上下文中获取点(https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-gettransform)。
const domPoint = new window.DOMPoint(event.offsetX, event.offsetY);
const currMatrix = this.canvasManager.ctx.getTransform();
const canvasPoint = domPoint.matrixTransform(currMatrix);
然后我使用 getTransform(DOMMatrix 对象)中返回的矩阵进行翻译、缩放和翻译。
const m = currMatrix
.translateSelf(canvasPoint.x, canvasPoint.y)
.scaleSelf(scale, scale)
.translateSelf(-canvasPoint.x, -canvasPoint.y);
最后我使用最后一个矩阵设置变换。
this.ctx.setTransform(this.zoom.matrix)
我使用的方法是基于一个堆栈溢出答案。
这是我的代码
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var currMatrix = ctx.getTransform();
var plusBtn = document.getElementById("plus");
var minusBtn = document.getElementById("minus");
var infoP = document.getElementById("info");
var zoom;
var scale = 1;
const scaleFactor = 0.1;
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.setTransform(currMatrix)
ctx.fillStyle = "blue";
ctx.fillRect(50, 50, 100, 100);
}
draw()
function getDomPoint(event) {
const offSetCanvasLeft = canvas.getBoundingClientRect().left;
const offSetCanvasTop = canvas.getBoundingClientRect().top;
return {
x: event.pageX - offSetCanvasLeft,
y: event.pageY - offSetCanvasTop,
}
}
function domToCanvasPoint(point) {
const domPoint = new window.DOMPoint(point.x, point.y);
return domPoint.matrixTransform(currMatrix);
}
function updateScale() {
scale = zoom === 'in' ? scale + scaleFactor : scale - scaleFactor ;
setDebugInfo(scale)
}
function zoomMatrixIntoPoint(point) {
currMatrix = currMatrix
.translateSelf(point.x, point.y)
.scaleSelf(scale, scale)
.translateSelf(-point.x, -point.y);
}
function setDebugInfo(msg) {
infoP.innerHTML = msg;
}
canvas.addEventListener('mousedown', function(event) {
const domPoint = getDomPoint(event);
const canvasPoint = domToCanvasPoint(domPoint);
updateScale();
zoomMatrixIntoPoint(canvasPoint);
draw()
}, false);
plusBtn.addEventListener('click', function(event) {
zoom = 'in'
setDebugInfo(`ZOOM IN with scale ${scale}`)
}, false);
minusBtn.addEventListener('click', function(event) {
zoom = 'out'
setDebugInfo(`ZOOM OUT with scale ${scale}`)
}, false);
<canvas id="myCanvas" width="300" height="300" style="border:1px solid black"></canvas>
<button id="plus">+</button>
<button id="minus">-</button>
<p id="info">info here!</p>
将不胜感激任何帮助。谢谢你。
解决方案
您的问题是一个简单的逻辑错误。
curMatrix
您每次都在保留和更新它。这意味着您传递给的所有值translateSelf
都scaleSelf
与之前的值相关。
但是,当您执行scale -= scaleFactor
或时scale += scaleFactor
,scale
是绝对比例值。
因此,当您稍后使用它时scaleSelf
,您会快速设置一个巨大的绝对比例值,直到小于1
.
(1.1 * 1.2 * 1.3 * 1.4 * 1.5 * 1.6) => real scale is 5.8
和
(1.1 * 1.2 * 1.3 * 1.2 * 1.1 * 1) => real scale is 2.3
^-- click zoom-out
所以你需要修复的是设置这个scale
值的行:而不是增加这个值,设置它总是1
基于。
scale = zoom === 'in' ? 1 + scaleFactor : 1 - scaleFactor ;
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var currMatrix = ctx.getTransform();
var plusBtn = document.getElementById("plus");
var minusBtn = document.getElementById("minus");
var infoP = document.getElementById("info");
var zoom;
var scale = 1;
const scaleFactor = 0.1;
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.setTransform(currMatrix)
ctx.fillStyle = "blue";
ctx.fillRect(50, 50, 100, 100);
}
draw()
function getDomPoint(event) {
const offSetCanvasLeft = canvas.getBoundingClientRect().left;
const offSetCanvasTop = canvas.getBoundingClientRect().top;
return {
x: event.pageX - offSetCanvasLeft,
y: event.pageY - offSetCanvasTop,
}
}
function domToCanvasPoint(point) {
const domPoint = new window.DOMPoint(point.x, point.y);
return domPoint.matrixTransform(currMatrix);
}
function updateScale() {
scale = zoom === 'in' ? 1 + scaleFactor : 1 - scaleFactor;
setDebugInfo(scale)
}
function zoomMatrixIntoPoint(point) {
currMatrix
.translateSelf(point.x, point.y)
.scaleSelf(scale, scale)
.translateSelf(-point.x, -point.y);
}
function setDebugInfo(msg) {
infoP.innerHTML = msg;
}
canvas.addEventListener('mousedown', function(event) {
const domPoint = getDomPoint(event);
const canvasPoint = domToCanvasPoint(domPoint);
updateScale();
zoomMatrixIntoPoint(canvasPoint);
draw()
}, false);
plusBtn.addEventListener('click', function(event) {
zoom = 'in'
setDebugInfo(`ZOOM IN with scale ${scale}`)
}, false);
minusBtn.addEventListener('click', function(event) {
zoom = 'out'
setDebugInfo(`ZOOM OUT with scale ${scale}`)
}, false);
<canvas id="myCanvas" width="300" height="300" style="border:1px solid black"></canvas>
<button id="plus">+</button>
<button id="minus">-</button>
<p id="info">info here!</p>
另请注意,DOMMatrix#scale()接受可选的原点参数,这将允许您避免两个转换调用:
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var currMatrix = ctx.getTransform();
var plusBtn = document.getElementById("plus");
var minusBtn = document.getElementById("minus");
var infoP = document.getElementById("info");
var zoom;
var scale = 1;
const scaleFactor = 0.1;
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.setTransform(currMatrix)
ctx.fillStyle = "blue";
ctx.fillRect(50, 50, 100, 100);
}
draw()
function getDomPoint(event) {
const offSetCanvasLeft = canvas.getBoundingClientRect().left;
const offSetCanvasTop = canvas.getBoundingClientRect().top;
return {
x: event.pageX - offSetCanvasLeft,
y: event.pageY - offSetCanvasTop,
}
}
function domToCanvasPoint(point) {
const domPoint = new window.DOMPoint(point.x, point.y);
return domPoint.matrixTransform(currMatrix);
}
function updateScale() {
scale = zoom === 'in' ? 1 + scaleFactor : 1 - scaleFactor;
setDebugInfo(scale)
}
function zoomMatrixIntoPoint(point) {
currMatrix
// scaleSelf(scaleX, scaleY, scaleZ, originX, originY, originZ)
.scaleSelf(scale, scale, 1, point.x, point.y, 0)
}
function setDebugInfo(msg) {
infoP.innerHTML = msg;
}
canvas.addEventListener('mousedown', function(event) {
const domPoint = getDomPoint(event);
const canvasPoint = domToCanvasPoint(domPoint);
updateScale();
zoomMatrixIntoPoint(canvasPoint);
draw()
}, false);
plusBtn.addEventListener('click', function(event) {
zoom = 'in'
setDebugInfo(`ZOOM IN with scale ${scale}`)
}, false);
minusBtn.addEventListener('click', function(event) {
zoom = 'out'
setDebugInfo(`ZOOM OUT with scale ${scale}`)
}, false);
<canvas id="myCanvas" width="300" height="300" style="border:1px solid black"></canvas>
<button id="plus">+</button>
<button id="minus">-</button>
<p id="info">info here!</p>
如果你需要你所有的值都是绝对的(也就是翻译),那么只需每次创建一个新的 DOMMatrix ,并在这里保持你原来的比例增量:
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var currMatrix = ctx.getTransform();
var plusBtn = document.getElementById("plus");
var minusBtn = document.getElementById("minus");
var infoP = document.getElementById("info");
var zoom;
var scale = 1;
const scaleFactor = 0.1;
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.setTransform(currMatrix)
ctx.fillStyle = "blue";
ctx.fillRect(50, 50, 100, 100);
}
draw()
function getDomPoint(event) {
const offSetCanvasLeft = canvas.getBoundingClientRect().left;
const offSetCanvasTop = canvas.getBoundingClientRect().top;
return {
x: event.pageX - offSetCanvasLeft,
y: event.pageY - offSetCanvasTop,
}
}
function domToCanvasPoint(point) {
const domPoint = new window.DOMPoint(point.x, point.y);
return domPoint.matrixTransform(currMatrix);
}
function updateScale() {
scale = zoom === 'in' ? scale + scaleFactor : scale - scaleFactor;
setDebugInfo(scale)
}
function zoomMatrixIntoPoint(point) {
// create a new DOMMatrix
currMatrix = new DOMMatrix()
.scaleSelf(scale, scale, 1, point.x, point.y, 0)
}
function setDebugInfo(msg) {
infoP.innerHTML = msg;
}
canvas.addEventListener('mousedown', function(event) {
const domPoint = getDomPoint(event);
const canvasPoint = domToCanvasPoint(domPoint);
updateScale();
zoomMatrixIntoPoint(canvasPoint);
draw()
}, false);
plusBtn.addEventListener('click', function(event) {
zoom = 'in'
setDebugInfo(`ZOOM IN with scale ${scale}`)
}, false);
minusBtn.addEventListener('click', function(event) {
zoom = 'out'
setDebugInfo(`ZOOM OUT with scale ${scale}`)
}, false);
<canvas id="myCanvas" width="300" height="300" style="border:1px solid black"></canvas>
<button id="plus">+</button>
<button id="minus">-</button>
<p id="info">info here!</p>
推荐阅读
- rabbitmq - 如何将 RabbitMQ 扩展到某些消费者
- prolog - 打印列表元素 - 这两种解决方案有何不同?
- excel - Excel Offset - 合并少数 Excel 工作表中的数据
- typescript - nestjs and typeorm - failing to setup the dependency injection
- c++ - GoogleTest:EXPECT_THROW 捕获不同的类型?
- javascript - 如何使用 javascript 和媒体查询创建响应式网站?
- python - Docker python3:找不到'__main__'模块
- reactjs - 将 props 传递给 Field validate 会给出以前的 props 值
- sql - SQL Server 中的日期排序
- ruby-on-rails - 如何将 HTML 文件存储到 Rails 模型中