HTML canvas如何检测旋转后的图像或矩形的有效点击事件?
HTML Canvas 旋转元素(矩形/图像)点击检测原生实现方案

以下两种方案均不依赖任何第三方库,可直接原生实现:
方案一:坐标逆变换法(性能最优,推荐)
核心原理是把点击坐标做反向旋转变换,还原到矩形未旋转的轴对齐坐标系下,再做简单的矩形范围判断即可,无额外渲染开销。
实现步骤:
- 预先记录矩形的基础属性:中心坐标
(cx, cy)、宽度w、高度h、旋转角度rotateAngle(需转换为弧度值) - 监听canvas点击事件,计算得到点击位置相对于canvas的坐标
(x, y) - 将点击坐标平移到以矩形中心为原点的坐标系:
const x1 = x - cx const y1 = y - cy - 对平移后的坐标执行反向旋转变换(旋转角度取负):
const cos = Math.cos(-rotateAngle) const sin = Math.sin(-rotateAngle) const rx = x1 * cos - y1 * sin const ry = x1 * sin + y1 * cos - 判断逆变换后的坐标是否落在原始轴对齐矩形范围内即可得到命中结果:
const isHit = Math.abs(rx) <= w/2 && Math.abs(ry) <= h/2
如果你的矩形是基于左上角定位而非中心定位,调整第一步的平移参数即可适配。
方案二:isPointInPath 路径检测法(写法最简,适合少量元素场景)
直接调用canvas原生的路径检测API,不用手动做矩阵计算,写法简单不容易出错。
代码示例:
const canvas = document.querySelector('canvas') const ctx = canvas.getContext('2d') // 定义矩形属性 const targetRect = { x: 100, // 左上角X坐标 y: 100, // 左上角Y坐标 width: 150, height: 80, rotate: 30 * Math.PI / 180 // 旋转角度转弧度 } // 绘制旋转矩形 function drawRect() { ctx.clearRect(0, 0, canvas.width, canvas.height) ctx.save() // 移动到矩形中心再旋转 ctx.translate(targetRect.x + targetRect.width/2, targetRect.y + targetRect.height/2) ctx.rotate(targetRect.rotate) ctx.beginPath() ctx.rect(-targetRect.width/2, -targetRect.height/2, targetRect.width, targetRect.height) ctx.fillStyle = '#2ecc71' ctx.fill() ctx.restore() } // 点击事件监听 canvas.addEventListener('click', e => { // 计算点击相对于canvas的坐标 const canvasBounding = canvas.getBoundingClientRect() const clickX = e.clientX - canvasBounding.left const clickY = e.clientY - canvasBounding.top // 重建旋转矩形的路径(不需要实际渲染到画布) ctx.save() ctx.translate(targetRect.x + targetRect.width/2, targetRect.y + targetRect.height/2) ctx.rotate(targetRect.rotate) ctx.beginPath() ctx.rect(-targetRect.width/2, -targetRect.height/2, targetRect.width, targetRect.height) const isHit = ctx.isPointInPath(clickX, clickY) ctx.restore() if (isHit) { console.log('点击命中旋转矩形') } }) drawRect()
方案选择建议
- 页面有大量可点击元素时选坐标逆变换法,纯数学计算性能远高于路径重建
- 元素数量少、或者需要检测不规则图形时选
isPointInPath法,维护成本更低
内容的提问来源于stack exchange,提问作者AmitSri
相关产品推荐
相关产品推荐

