Canvas雷达图核心是动态多边形路径+坐标映射+事件反查;通过极坐标转直角坐标绘制骨架,即以中心(cx,cy)、半径rMax,按2π/n×i计算各维度角度并归一化映射像素位置。

用 Canvas 路径 API 绘制可交互的雷达图,核心在于:动态生成多边形路径 + 坐标映射计算 + 事件坐标反查。不依赖第三方库也能实现点击高亮、悬停提示、数据联动等基础交互。
一、构建雷达图骨架:极坐标转直角坐标的路径绘制
雷达图本质是正多边形(n 边形)+ 各维度射线 + 数据点连线。关键步骤是将每个维度角度(2π/n × i)和归一化值映射为 canvas 像素坐标:
- 设定中心点 (cx, cy) 和最大半径 rMax
- 对第 i 个维度(0 ≤ i
- 若该维度原始值为 val[i],最大可能值为 maxVal[i],则归一化比例 ratio = val[i] / maxVal[i](建议统一用全局最大值做归一化更直观)
- 对应顶点坐标:x = cx + rMax * ratio * Math.cos(θ - Math.PI/2),y = cy + rMax * ratio * Math.sin(θ - Math.PI/2)(减 π/2 是为让 0° 指向上方,符合常规雷达图朝向)
用 ctx.beginPath() → 循环 ctx.lineTo(x, y) → ctx.closePath() 即可画出填充的数据多边形;叠加多层(如基准线、网格、标签线)只需重复此逻辑并调整透明度或线型。
二、添加交互响应:监听鼠标事件并反查当前维度
Canvas 本身无 DOM 子元素,所有交互需手动计算。重点是把鼠标位置 (clientX, clientY) 转为相对于 canvas 的坐标,再判断是否落在某条射线附近或某个扇区内:
立即学习“前端免费学习笔记(深入)”;
- 获取 canvas 相对页面位置:
const rect = canvas.getBoundingClientRect(),则画布内坐标为x = clientX - rect.left,y = clientY - rect.top - 计算相对于中心点的向量:
dx = x - cx,dy = y - cy - 求角度:
angle = Math.atan2(dy, dx) + Math.PI/2(补偿旋转,使 0 弧度对应顶部) - 归一化到 [0, 2π),再换算为维度索引:
index = Math.floor((angle % (2*Math.PI)) / (2*Math.PI/n)) % n - 可加容差判断(如 ±π/n × 0.3)提升点击宽容度;悬停时还可计算到各顶点距离,用于高亮最近维度
三、实现视觉反馈:动态重绘与状态管理
交互效果(如悬停高亮某维度、点击选中某组数据)不能靠 CSS,必须清空重绘。推荐结构化管理状态:
- 维护一个 activeIndex(当前悬停/选中的维度索引)和 selectedDataId(如点击某条雷达图后记录其 ID)
- 每次重绘前调用
ctx.clearRect(0, 0, canvas.width, canvas.height) - 先画背景网格、轴线、标签;再画所有数据图层;最后单独绘制高亮层(如加粗当前维度射线、填充 activeIndex 对应扇区、在顶点画圆点)
- 为避免闪烁,确保所有绘制操作在单次
requestAnimationFrame中完成
四、增强实用性:支持缩放、平移与数据更新
真实场景中常需查看密集维度或对比多组数据。可在基础路径逻辑上扩展:
-
缩放:引入 scale 参数,所有坐标乘以 scale,同时调整
ctx.scale(scale, scale)并修正中心点偏移 - 平移:维护 offsetX / offsetY,绘制时所有坐标加上偏移,并在事件坐标转换时减去
-
数据更新:封装绘图函数为
render(dataList, options),传入数组形式的多组数据(每组含 name 和 values 数组),循环绘制不同颜色图层,用图例 DOM 元素配合 toggle 显示/隐藏 - 导出图片:调用
canvas.toDataURL('image/png')即可保存当前视图
不复杂但容易忽略:务必在 canvas 初始化时设置 width 和 height 属性(非 CSS 样式),否则像素密度错乱导致模糊;移动端需监听 touchstart/touchmove 并用 touches[0] 替代 mouse 事件。



















