标签无法用于video或canvas的实时画面热区交互,因其仅支持静态img的usemap;正确方案是监听容器click事件,结合坐标换算与isPointInRect/isPointInPath/raycasting实现精准响应。

area 标签根本不能直接作用于 video 或 canvas 的画面投影
想用 <area> 点击热区响应视频帧或 WebGL 渲染画面?行不通。浏览器不把 <video></video>、<canvas></canvas> 或 <img alt="HTML使用area标签对多媒体投影画面进行交互的尝试" >(动态生成的)当作可映射的图像源——除非它是个静态 src 属性指向真实图片 URL 的 <img alt="HTML使用area标签对多媒体投影画面进行交互的尝试" >,且配合了 <map></map>。多媒体内容是实时渲染的,没有 DOM 像素坐标到 <area> 的绑定机制。
常见错误现象:click 事件完全不触发、area 高亮但无响应、控制台报 Failed to execute 'getElementById' on 'Document'(因 map name 匹配失败)。
-
<area>只支持<img alt="HTML使用area标签对多媒体投影画面进行交互的尝试" >的usemap属性,且该<img alt="HTML使用area标签对多媒体投影画面进行交互的尝试" >必须加载完成、尺寸固定、非 base64 动态 blob - video 播放中帧画面无法被
<map></map>捕获;canvas 绘制内容不在 HTML 图像映射体系内 - 即使强行把 canvas 转成
<img src="canvas.toDataURL()" alt="HTML使用area标签对多媒体投影画面进行交互的尝试" >,每帧都重绘 + 替换 img src,性能崩、延迟高、热区错位
替代方案:用绝对定位 + 事件坐标换算模拟 area 行为
真正可行的做法,是放弃 <area>,改用 getBoundingClientRect() + clientX/clientY 手动判断点击是否落在目标区域。适用于 <video></video> 全屏播放、<canvas></canvas> 渲染画面、甚至 WebRTC 远程流。
关键点在于:必须监听容器元素(如包裹 video 的 <div>)的 <code>click,而非 video 自身;再把鼠标坐标减去容器 offset,映射到视频/画布的逻辑坐标系(注意 video 的 videoWidth/videoHeight 与显示宽高的缩放比)。
立即学习“前端免费学习笔记(深入)”;
- 监听容器的
click,不是<video></video>的click(它默认不冒泡,且可能被控件遮挡) - 用
video.videoWidth和video.videoHeight做原始比例基准,别用offsetWidth/offsetHeight直接除(会忽略 letterboxing) - 热区定义建议用对象数组:[{x: 100, y: 80, width: 120, height: 90, id: "btn-play"}],便于循环
isPointInRect() - 移动端需同时处理
touchstart,并取touches[0]坐标
Canvas 场景下更推荐用 isPointInPath 配合 Path2D
如果画面由 <canvas></canvas> 渲染(比如投影校正后的画面、AR 叠加层),直接用 ctx.isPointInPath() 判断比矩形计算更灵活,尤其适合不规则热区(多边形按钮、扇形菜单)。
前提是:每次绘制热区时,用 new Path2D() 创建路径,并缓存起来;不要在点击时临时调用 beginPath() —— 路径状态不可靠,且性能差。
- 缓存
Path2D实例,例如const hotZoneA = new Path2D("M100,50 L200,50 L180,120 Z") - 点击回调里调用
ctx.isPointInPath(hotZoneA, x, y),x/y 是已换算到 canvas 坐标系的点 - 注意 canvas 的
transform(如scale()或setTransform())会影响isPointInPath判断,必要时先ctx.resetTransform() - 避免在
requestAnimationFrame循环里反复创建Path2D,内存泄漏风险高
WebGL 投影画面交互必须绕过 DOM,走 raycasting
如果是 Three.js 或原生 WebGL 渲染的投影画面(比如 360° 视频贴图、空间化 UI),<area> 完全失效,连模拟坐标换算都不适用——因为像素和三维空间之间隔着 MVP 矩阵。
正确路径是:从鼠标归一化设备坐标(NDC)出发,逆乘 viewProjection 矩阵,得到射线(ray),再与场景中带交互的 mesh 做相交检测(raycaster.intersectObjects())。Three.js 的 Raycaster 就是为此设计的。
- 别试图用
canvas.getBoundingClientRect()算二维坐标后“猜”三维位置——角度、fov、zNear/zFar 全部影响结果 - 确保交互 mesh 的
raycast属性为true,且 geometry 有有效 boundingSphere - 如果投影画面本身是 shader 渲染的(如畸变校正),热区应定义在原始 UV 或三维模型上,而非最终像素
- 性能敏感时,对 raycast 结果做防抖(如 50ms 内重复点击只算一次)
最易被忽略的一点:所有方案都依赖“画面尺寸稳定”。如果视频自动适应容器宽高比、canvas 被 CSS 缩放、或 WebGL renderer.setSize() 动态调整,坐标换算逻辑必须同步更新——否则热区漂移,用户点不准,问题很难复现。



















