返回

在 object-fit: contain 中将鼠标位置转换为画布坐标:解决鼠标事件坐标不匹配

javascript

在 object-fit: contain 下将鼠标位置转换为画布坐标

简介

当使用 object-fit: contain 属性时,画布会调整大小以适合其容器。虽然这很方便,但会导致鼠标事件位置与画布坐标不匹配。本文将探讨如何解决此问题,以及如何计算 letterboxing(画布周围的空白区域)的尺寸。

问题

当使用 object-fit: contain 时,鼠标事件位置覆盖了包括 letterboxing 在内的整个区域。因此,无法直接将事件位置转换为画布坐标,因为 letterboxing 会影响位置。

解决方案

要将事件位置转换为画布坐标,我们需要减去 letterboxing 的尺寸:

  1. 计算 letterboxing 尺寸:

    • letterboxWidth = imageWidth - canvasWidth
    • letterboxHeight = imageHeight - canvasHeight
  2. 计算画布坐标:

    • canvasX = eventX - letterboxWidth / 2
    • canvasY = eventY - letterboxHeight / 2

通过使用这些公式,我们可以获得与事件位置相匹配的画布坐标。

示例

让我们修改前面的示例以解决这个问题:

canvas.onmousemove = (e) => {
  // 计算 letterboxing 的尺寸
  const letterboxWidth = imageWidth - canvas.width
  const letterboxHeight = imageHeight - canvas.height

  // 计算画布坐标
  const canvasX = e.offsetX - letterboxWidth / 2
  const canvasY = e.offsetY - letterboxHeight / 2

  ctx.clearRect(0,0,canvas.width,canvas.height);
  ctx.strokeRect(0,0,canvas.width,canvas.height);
  ctx.beginPath();
  ctx.arc(canvasX,canvasY, 10, 0, 2 * Math.PI);
  ctx.stroke();
  pt.innerText=`${canvasX}x${canvasY}`;
}

现在,圆形和鼠标指针将在画布的所有位置匹配。

常见问题解答

  • 为什么 object-fit: contain 会导致这个问题?

    • object-fit: contain 调整画布的大小以适合其容器,这意味着画布的尺寸可能与图像不同。这会导致 letterboxing,从而影响鼠标事件位置。
  • 我可以使用 getBoundingClientRect() 吗?

    • 否,getBoundingClientRect() 获取元素相对于视口的边界框,它不受 object-fit 的影响。
  • 如果图像的宽高比与容器的宽高比不同怎么办?

    • 在这种情况下,画布的尺寸仍应使用 min() 函数计算,但可能会在水平或垂直方向上出现 letterboxing。
  • 可以使用 JavaScript 监听 resize 事件吗?

    • 是的,如果您期望容器的大小发生变化,这可能是必要的。然而,它可能会产生额外的开销,并且在某些情况下可能不实用。
  • 是否可以在不使用 JavaScript 的情况下解决这个问题?

    • 否,object-fit 是一个 CSS 属性,它仅受浏览器处理。在不使用 JavaScript 的情况下,无法动态计算 letterboxing 的尺寸。

结论

解决 object-fit: contain 下鼠标位置和画布坐标不匹配的问题涉及计算 letterboxing 的尺寸并减去这些尺寸。通过使用本文提供的公式,您可以在所有情况下获得准确的画布坐标。