可行,但需用 getboundingclientrect 校正坐标、网格聚合数据、canvas 渲染并处理缩放/滚动/iframe/触摸等细节。

直接用纯 HTML + JavaScript 实现点击热力图,不依赖第三方可视化库(如 ECharts、D3),是完全可行的,但关键在于:你得自己采集坐标、聚合数据、渲染 canvas 或 DOM 层叠点。浏览器原生支持足够,难点在坐标归一化和性能控制——尤其页面有滚动、缩放或响应式布局时,clientX/clientY 会立刻失效。
怎么准确捕获真实点击位置(避开 scroll/zoom 影响)
很多实现直接监听 click 事件取 e.clientX 和 e.clientY,结果热力图偏移、错位。根本原因是没转成相对于目标容器(比如 <main></main> 或整个视口)的坐标。
- 用
element.getBoundingClientRect()获取容器左上角在视口中的绝对位置,再用e.clientX - rect.left算出相对 X;Y 同理 - 如果页面允许滚动,必须监听
scroll并重置热力图容器的transform或重新计算基准 rect,否则历史点会“漂移” - 移动端要额外处理
touchstart,且注意touches[0]的坐标字段是clientX/clientY,不是pageX/pageY
热力图数据怎么存和聚合(别用数组 push 每次都遍历)
每点都存原始坐标,1000 次点击后渲染前再遍历聚合?CPU 瞬间拉满。实际应边采集边聚合成网格(grid-based)或 KD 树结构,但简单项目用二维数组桶就够了。
- 预设热力图分辨率,比如把容器宽高各分为 50 格 → 得到 2500 个格子,用
grid[x][y]++计数 - X 坐标归一化:
Math.floor((x / containerWidth) * 50),Y 同理;注意边界取Math.min(x, 49)防越界 - 不要用对象键拼接
"x_y"存,哈希冲突+字符串开销大;数组索引访问快一个数量级
canvas 渲染热力图比 div 层叠更稳(尤其大量点击时)
用一堆 <div style="position: absolute; background: rgba(255,0,0,0.3)"> 叠加?500+ 点就开始卡顿,且无法做高斯模糊扩散。canvas 是唯一合理选择。<ul>
<li>创建固定尺寸 <code><canvas></canvas>,width/height 设为容器 clientWidth/clientHeight,避免设备像素比(dpr)导致模糊
ctx.getImageData() 批量写像素:对每个非零格子,按权重往周围 3×3 区域写 RGBA 值,再用 ctx.putImageData() 一次性刷屏const r = Math.min(255, 100 + value * 2) 这类线性/指数公式,平滑且无分支用户隐私和性能必须手动关(Chrome 默认不发 click 事件给 iframe)
如果热力图嵌在 iframe 里(比如分析后台嵌入的客户页面),click 事件默认被屏蔽,且 document.hasFocus() 可能始终返回 false。
- 主页面需加
sandbox="allow-scripts allow-same-origin",否则 JS 根本跑不起来 - 采集脚本里加
if (!document.hasFocus()) return,避免后台标签页误采 - 高频点击时加节流:用
setTimeout缓存 100ms 内所有点,再统一聚合,防止 canvas 频繁重绘
真正难的不是画出红点,而是让坐标在各种缩放、滚动、iframe、移动端 touch 下都对得上——这些细节没压住,热力图就是一张好看但不准的假图。











