如何使雷达图(Radar Chart)的刻度在网格线之间居中?
解决雷达图刻度位于网格线之间的问题
要实现将1-5的刻度数值放在雷达图网格线之间,需通过隐藏默认刻度+自定义插件绘制刻度的方式实现,具体调整如下:
步骤1:隐藏默认刻度
在scales.r.ticks中添加display: false,关闭默认刻度的渲染:
ticks: { display: false, // 隐藏默认刻度 backdropPadding: { x: 16, y: 16 }, z: 10, backdropColor: "transparent", color: "red", backgroundColor: "black", stepSize: 1 }
步骤2:编写自定义插件绘制中间刻度
启用并修改自定义插件,计算每个刻度对应的径向位置(网格线中间),然后绘制文本:
plugins: [ { id: "middleTicks", afterDraw: (chart) => { const { ctx, scales: { r } } = chart; const min = r.min; const max = r.max; const step = r.ticks.stepSize; const centerX = r.xCenter; const centerY = r.yCenter; const radiusStep = (r.maxRadius - r.minRadius) / ((max - min) / step); ctx.fillStyle = "red"; // 刻度文字颜色 ctx.textAlign = "center"; ctx.textBaseline = "middle"; // 绘制1到5的刻度,每个刻度在相邻网格线中间 for (let i = min + step; i <= max; i++) { // 计算当前刻度的径向半径(网格线中间位置) const radius = r.minRadius + (i - min - 0.5) * radiusStep; // 遍历每个角度方向,绘制刻度(雷达图每个轴都要显示) r.points.forEach((point) => { const angle = Math.atan2(point.y - centerY, point.x - centerX); const x = centerX + radius * Math.cos(angle); const y = centerY + radius * Math.sin(angle); ctx.fillText(i.toString(), x, y); }); } } } ]
完整修改后的代码
const ctx = document.getElementById("myChart"); new Chart(ctx, { type: "radar", data: { labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange", "Turquesa"], datasets: [ { data: [4, 3.5, 2, 5, 4.5, 4, 2], borderWidth: 1, backgroundColor: "#ECAE4880", borderColor: "#FBDDAD", color: "#f00" } ] }, options: { elements: { point: { pointStyle: false } }, scales: { r: { min: 0, max: 5, backgroundColor: "#FDF7EC", ticks: { display: false, // 隐藏默认刻度 backdropPadding: { x: 16, y: 16 }, z: 10, backdropColor: "transparent", color: "red", backgroundColor: "black", stepSize: 1 }, grid: { color: "#EA910B", backgroundColor: "red" }, angleLines: { color: "transparent" } } }, plugins: { legend: { display: false }, title: { display: false }, subtitle: { display: false } } }, plugins: [ { id: "middleTicks", afterDraw: (chart) => { const { ctx, scales: { r } } = chart; const min = r.min; const max = r.max; const step = r.ticks.stepSize; const centerX = r.xCenter; const centerY = r.yCenter; const radiusStep = (r.maxRadius - r.minRadius) / ((max - min) / step); ctx.fillStyle = "red"; ctx.textAlign = "center"; ctx.textBaseline = "middle"; for (let i = min + step; i <= max; i++) { const radius = r.minRadius + (i - min - 0.5) * radiusStep; r.points.forEach((point) => { const angle = Math.atan2(point.y - centerY, point.x - centerX); const x = centerX + radius * Math.cos(angle); const y = centerY + radius * Math.sin(angle); ctx.fillText(i.toString(), x, y); }); } } } ] });
原理说明
- 隐藏默认刻度避免视觉冲突,通过插件手动计算每个刻度的位置:每个刻度的径向位置是相邻两条网格线的中间点(即
(当前刻度值 - 0.5)对应的半径)。 - 遍历雷达图的每个角度轴,在对应位置绘制刻度文本,确保所有方向的刻度都显示在网格线之间。
内容的提问来源于stack exchange,提问作者Luane
相关产品推荐
相关产品推荐

