如何在使用object-fit: contain时将鼠标位置转换为画布坐标
解决
object-fit: contain下画布鼠标坐标偏差问题 使用object-fit: contain可以调整画布大小以适配容器,但当前代码中通过鼠标事件绘制圆形时,仅在画布中间位置能和指针匹配,其他位置会出现偏差——这是因为鼠标事件的坐标覆盖了包含黑边(留白)的整个canvas元素区域,直接按元素宽高比例转换坐标的逻辑忽略了contain带来的留白偏移。
问题根源
object-fit: contain会让画布保持原始宽高比缩放到容器内,当容器比例和画布原始比例不一致时,某一方向会出现留白(黑边)。但offsetX/offsetY是相对于canvas元素的整体尺寸(含留白),直接用e.offsetX * canvas.width / canvas.offsetWidth计算会把留白区域的坐标也算进去,导致偏移。
解决方案:计算有效区域的偏移和缩放比例
需要先算出画布实际显示内容在canvas元素内的位置(留白的偏移量)和缩放比例,再将鼠标坐标转换为画布原始坐标:
修改后的完整代码
<div id="container"> <canvas id="canvas"></canvas> </div> <div id="pt"></div>
#container { height: 150px; } #canvas { object-fit: contain; width: 100%; height: 100%; border: 1px solid red; }
const canvas = document.getElementById('canvas'); const pt = document.getElementById('pt'); // 画布原始尺寸 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); // 计算画布元素的显示尺寸和原始尺寸的比例 const canvasRatio = canvas.width / canvas.height; const elementRatio = e.target.offsetWidth / e.target.offsetHeight; let scale, offsetX, offsetY; if (elementRatio > canvasRatio) { // 容器更宽,上下留白 scale = e.target.offsetHeight / canvas.height; offsetX = (e.target.offsetWidth - canvas.width * scale) / 2; offsetY = 0; } else { // 容器更高,左右留白 scale = e.target.offsetWidth / canvas.width; offsetX = 0; offsetY = (e.target.offsetHeight - canvas.height * scale) / 2; } // 转换鼠标坐标到画布原始坐标 const x = Math.round((e.offsetX - offsetX) / scale); const y = Math.round((e.offsetY - offsetY) / scale); ctx.beginPath(); ctx.arc(x, y, 10, 0, 2 * Math.PI); ctx.stroke(); pt.innerText = `${x}x${y}`; };
逻辑说明
- 计算比例:对比画布原始宽高比和canvas元素的显示宽高比,判断是上下留白还是左右留白
- 计算缩放比例:根据匹配的方向(宽或高)算出实际的缩放倍数
- 计算偏移量:算出留白区域的宽度/高度,得到有效绘制区域的起始坐标
- 转换坐标:用鼠标的
offsetX/offsetY减去留白偏移,再除以缩放比例,得到画布原始尺寸下的坐标
这样就能确保鼠标指针和绘制的圆形在任何位置都精准匹配,同时保留object-fit: contain的适配效果。
内容的提问来源于stack exchange,提问作者mpromonet
相关产品推荐
相关产品推荐

