Canvas 是绘制可控雷达图的唯一靠谱选择:像素级控制、路径重绘快、坐标映射直白;需统一用弧度计算顶点,基于中心偏移定位,手动实现悬停检测与兼容处理。

用 <canvas> 手动画雷达图比用 SVG 更可控
纯 HTML + CSS 做不了真正的雷达图,<svg> 虽能描点连线,但动态悬停、坐标换算、扇形填充、响应式缩放都得自己算——反而更费劲。Canvas 是唯一靠谱的选择:像素级控制、路径重绘快、事件坐标映射直白。
关键不是“能不能”,而是“改起来痛不痛”。Canvas 里每个顶点坐标由极坐标转直角坐标生成:Math.cos(angle) * radius 和 Math.sin(angle) * radius,角度要统一用弧度,别漏了 Math.PI / 180 换算。
- 数据维度必须 ≥ 3,否则画不出闭合多边形;少于 3 维会降级成线段或点,
ctx.closePath()仍能执行但视觉无效 - 所有坐标需基于 canvas 中心偏移计算,别直接用
0,0当原点,否则图形会贴左上角裁切 -
ctx.fillText()显示数值时,记得用ctx.textAlign = 'center'和ctx.textBaseline = 'middle'对齐,否则文字飘在圈外
悬停检测不能只靠 mousemove,得做点内距离判断
雷达图的“悬停”不是 hover 某个 DOM 元素,而是判断鼠标是否落在某个技能扇区的多边形内部。Canvas 没有内置事件委托,必须手动做点在多边形内的判定(比如射线法或叉积法),isPointInPath() 只对当前路径有效,且不支持 fill 区域的实时重绘。
常见错误是把鼠标坐标直接当 Canvas 坐标用——忘了 getBoundingClientRect() 获取 canvas 相对于视口的位置,再减去 offset 才是真实 canvas 坐标。
立即学习“前端免费学习笔记(深入)”;
- 每次
mousemove都要重算所有顶点构成的扇区路径,再调用ctx.isPointInPath(x, y),但注意:该方法只对最近一次beginPath()到closePath()之间的路径生效 - 如果扇区用了渐变填充或透明度,
isPointInPath()仍可工作,但别依赖像素采样(getImageData()太慢,且跨域 canvas 不允许) - 悬停高亮建议用临时 overlay canvas 叠在主 canvas 上,避免反复清空重绘主图影响性能
requestAnimationFrame 不适合雷达图悬停动画
雷达图的悬停反馈是离散状态切换(进/出某区域),不是连续运动轨迹,用 requestAnimationFrame 反而增加 CPU 占用、引入不必要的帧率抖动。直接用 setTimeout 或事件节流(如 lodash.throttle 30ms)就够了。
真正需要动画的地方只有两个:数值从 0 过渡到目标值(初始加载)、悬停时扇区边框淡入。这两个都用 CSS transition 配合 canvas 的 globalAlpha 或 strokeStyle 动态改色更轻量。
- 别在
mousemove里每帧调用clearRect()+ 重绘全图,只重绘被影响的扇区和数值标签 - 移动端要监听
touchmove,且 touch 坐标同样要转换,touches[0]的 clientX/Y 也得减 canvas offset - Chrome DevTools 的 Rendering 面板打开 “Paint flashing”,能立刻看出是不是在无意义重绘
IE11 下 canvas.toDataURL('image/png') 会丢透明通道
导出雷达图为图片时,IE11 对 toDataURL() 支持不完整,alpha 通道会被强制转为黑底,导致扇区边缘发灰。这不是 bug,是 IE 的 canvas 实现限制——它默认用 canvas.getContext('2d').globalCompositeOperation = 'source-over',且不支持 'image/webp' 等替代格式。
绕过办法只有一个:服务端渲染。前端把顶点坐标、颜色数组、文字内容 JSON 序列化后 POST 给后端,用 Node.js 的 canvas 模块(非浏览器版)或 Python 的 Pillow 生成真 PNG。
- 别尝试用
filter: url(#blur)在 canvas 上模拟阴影——IE11 不支持 SVG filter 引用 canvas - 如果必须前端导出,降级方案是用
canvas.toBlob()(IE11 不支持),所以得 fallback 到canvas.msToBlob(),再用URL.createObjectURL()创建下载链接 - 所有颜色值务必用
rgba(r,g,b,a)写全,别省略 alpha,否则 IE11 会当成 1,导致半透效果失效
Canvas 雷达图的麻烦不在画图本身,而在坐标系统、事件映射、浏览器兼容这三层嵌套的隐性约束。漏掉任意一层,悬停就会失灵、导出就会变色、移动端就会错位——这些都不是代码写错了,是没意识到 canvas 坐标从来就不是页面坐标。



















