ChartJS 3.9中如何将双层环形图外层改为方括号样式?
实现带方括号样式外层的双层环形图(Chart.js)
要实现外层方括号样式(保留两端刻度)的双层环形图,原生Chart.js的doughnut配置无法满足这种非闭合的自定义边框需求,最可靠的方式是用自定义插件手动绘制外层方括号,同时保留内层环形的动态数据特性。
核心思路
- 移除原有的外层doughnut数据集,专注用插件绘制方括号外框
- 在Chart.js的
afterDraw钩子中,基于图表当前尺寸动态计算坐标,绘制外弧、左右刻度线 - 确保插件适配响应式,窗口大小变化时自动重绘
完整代码示例
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js"></script> <div class="wrap__chart"> <canvas id="chart1"></canvas> </div> <style> .wrap__chart {width: 50vw; margin: 0 auto;} </style> <script> const chart1 = document.getElementById('chart1').getContext('2d'); // 自定义插件:绘制方括号外层 const bracketPlugin = { id: 'bracketOuter', afterDraw: (chart) => { const ctx = chart.ctx; const centerX = chart.chartArea.left + chart.chartArea.width / 2; const centerY = chart.chartArea.top + chart.chartArea.height / 2; const outerRadius = Math.min(chart.chartArea.width, chart.chartArea.height) / 2; const innerRadius = outerRadius * 0.95; // 和内层环形的radius对应 const circumference = 300; // 方括号的弧长(对应原需求的300度) const startAngle = (360 - circumference) / 2; // 计算起始角度,让弧居中 const endAngle = startAngle + circumference; // 转换角度为弧度(Chart.js用弧度计算) const startRadian = (startAngle * Math.PI) / 180; const endRadian = (endAngle * Math.PI) / 180; ctx.save(); ctx.lineWidth = 4; // 方括号线条宽度 ctx.strokeStyle = 'black'; // 绘制外弧 ctx.beginPath(); ctx.arc(centerX, centerY, outerRadius, startRadian, endRadian); ctx.stroke(); // 绘制左刻度线(垂直于弧的端点) ctx.beginPath(); const leftX = centerX + outerRadius * Math.cos(startRadian); const leftY = centerY + outerRadius * Math.sin(startRadian); const leftInnerX = centerX + innerRadius * Math.cos(startRadian); const leftInnerY = centerY + innerRadius * Math.sin(startRadian); ctx.moveTo(leftX, leftY); ctx.lineTo(leftInnerX, leftInnerY); ctx.stroke(); // 绘制右刻度线 ctx.beginPath(); const rightX = centerX + outerRadius * Math.cos(endRadian); const rightY = centerY + outerRadius * Math.sin(endRadian); const rightInnerX = centerX + innerRadius * Math.cos(endRadian); const rightInnerY = centerY + innerRadius * Math.sin(endRadian); ctx.moveTo(rightX, rightY); ctx.lineTo(rightInnerX, rightInnerY); ctx.stroke(); ctx.restore(); } }; // 初始化图表 new Chart(chart1, { type: 'doughnut', plugins: [bracketPlugin], // 挂载自定义插件 data: { datasets: [{ data: [14, 14, 22, 37, 13], // 内层动态数据,可随时替换 backgroundColor: ['#f5ce42', '#ccc3a3', '#fc95f2', '#cdb2ed', '#423225'], radius: '95%', // 和插件里的innerRadius对应 borderColor: 'black', borderAlign: 'inside', borderWidth: 1 }] }, options: { responsive: true, maintainAspectRatio: false, // 配合容器宽度实现响应式 cutout: '80%', // 控制内层环形的内半径,按需调整 plugins: { legend: { position: 'bottom' // 图例位置,按需调整 } } } }); </script>
关键细节说明
- 插件的坐标计算:通过
chart.chartArea获取图表的实际绘制区域,确保方括号始终居中,且适配容器尺寸变化 - 角度转换:Chart.js内部用弧度计算角度,所以需要把我们习惯的角度(0-360度)转换成弧度
- 响应式适配:开启
responsive: true和maintainAspectRatio: false,配合容器的50vw宽度,窗口大小变化时图表会自动重绘,插件也会重新计算坐标绘制方括号 - 动态数据:内层数据集的
data可以随时替换,图表会自动更新,不影响外层方括号的样式
为什么之前的方法无效?
- Chart.js 3.x中,
borderWidth只能是数值,不支持对象形式(比如{top:1, right:1}),所以设置后会破坏图表结构 borderColor同样只能是单一颜色或对应数据集的颜色数组,无法单独控制某一段边框cutout是控制整个环形的内半径,无法针对某一段切片自定义样式
内容的提问来源于stack exchange,提问作者user19881049
相关产品推荐
相关产品推荐

