如何使用object-fit将鼠标位置转换为画布坐标:contain

问题描述 投票:0回答:1

使用 object-fit: contains 允许调整画布大小以适合容器。

此代码片段使用鼠标事件位置绘制一个圆:

canvas.width=1920;
canvas.height=1200;
const ctx=canvas.getContext("2d");
ctx.lineWidth = 10;
ctx.strokeRect(0,0,canvas.width,canvas.height);
canvas.onmousemove = (e) => {
  ctx.clearRect(0,0,canvas.width,canvas.height);
  ctx.strokeRect(0,0,canvas.width,canvas.height);
  ctx.beginPath();
  const x = parseInt(e.offsetX*canvas.width/canvas.offsetWidth);
  const y = parseInt(e.offsetY*canvas.height/canvas.offsetHeight);
  ctx.arc(x,y, 10, 0, 2 * Math.PI);
  ctx.stroke();
  pt.innerText=`${x}x${y}`;
}
#container {
  height: 150px;
}
#canvas {
  object-fit: contain;
  width: 100%;
  height: 100%;
  border: 1px solid red;
}
<div id="container">
  <canvas id="canvas"></canvas>
</div>
<div id="pt"></div>

圆圈和鼠标指针仅在画布中间匹配。在其他位置我们得到类似的东西 enter image description here

事件坐标似乎覆盖了整个区域,包括信箱。删除

object-fit: contain;
在鼠标位置上绘制圆圈(但不适合它)。
如何将鼠标事件位置转换为画布坐标?它需要获取信箱高度和宽度?

javascript canvas mouseevent object-fit
1个回答
0
投票

这个相当棘手。问题是 canvas 元素占据了其父元素 100% 的宽度和高度 - 因此在本例中是视口的整个宽度。然而,由于将高度限制为固定像素大小并使用 CSS

object-fit: contain
属性,屏幕上画布的实际大小要小得多。

所以第一步是计算实际面积:

    let onScreenHeight = e.target.parentElement.getBoundingClientRect().height;
    let scaleWidth = onScreenHeight / canvas.height;
    let scaleHeight = e.target.parentElement.getBoundingClientRect().width / canvas.width;
    let onScreenWidth = canvas.width * scaleWidth;

这将使用 150 像素高度(如指定的 cia CSS)和 240 像素宽度。

下一步是计算该区域的“虚拟”宽度和高度,同时考虑视口的实际尺寸。

    let virtualWidth = onScreenWidth / scaleHeight;
    let virtualHeight = onScreenHeight / scaleWidth;

正如我们现在所知的虚拟尺寸,剩下的就是检查我们是否将鼠标悬停在它上面!这是通过将鼠标坐标转换到虚拟坐标空间来完成的,如果结果数字 >0 并且 < virtualWidth we know that we're inside the canvas - horizontally.

如果我们将这个数字除以

virtualWidth
,我们会得到一个因子,我们可以用它来乘以画布实际宽度,最终得到屏幕上的真实x坐标。

    let x = ((mouseX - canvas.width / 2 + virtualWidth / 2) / virtualWidth) * canvas.width;
    let y = ((mouseY - canvas.height / 2 + virtualHeight / 2) / virtualHeight) * canvas.height;

所有东西放在一起:

canvas.width = 1920;
canvas.height = 1200;
const ctx = canvas.getContext("2d");
ctx.lineWidth = 10;
ctx.strokeRect(0, 0, canvas.width, canvas.height);
canvas.onmousemove = (e) => {
    let onScreenHeight = e.target.parentElement.getBoundingClientRect().height;
    let scaleWidth = onScreenHeight / canvas.height;
    let scaleHeight = e.target.parentElement.getBoundingClientRect().width / canvas.width;
    let onScreenWidth = canvas.width * scaleWidth;
    let virtualWidth = onScreenWidth / scaleHeight;
    let virtualHeight = onScreenHeight / scaleWidth;
    
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.strokeRect(0, 0, canvas.width, canvas.height);
    ctx.beginPath();
    let mouseX = parseInt(e.offsetX * canvas.width / canvas.offsetWidth);
    let mouseY = parseInt(e.offsetY * canvas.height / canvas.offsetHeight);

    let x = ((mouseX - canvas.width / 2 + virtualWidth / 2) / virtualWidth) * canvas.width;
    let y = ((mouseY - canvas.height / 2 + virtualHeight / 2) / virtualHeight) * canvas.height
    ctx.arc(x, y, 10, 0, 2 * Math.PI);
    ctx.stroke();
}
#container {
  height: 150px;
}
#canvas {
  object-fit: contain;
  width: 100%;
  height: 100%;
  border: 1px solid red;
}
<div id="container">
  <canvas id="canvas"></canvas>
</div>

© www.soinside.com 2019 - 2024. All rights reserved.