You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ChartJS 3.9中如何将双层环形图外层改为方括号样式?

实现带方括号样式外层的双层环形图(Chart.js)

要实现外层方括号样式(保留两端刻度)的双层环形图,原生Chart.js的doughnut配置无法满足这种非闭合的自定义边框需求,最可靠的方式是用自定义插件手动绘制外层方括号,同时保留内层环形的动态数据特性。

核心思路

  1. 移除原有的外层doughnut数据集,专注用插件绘制方括号外框
  2. 在Chart.js的afterDraw钩子中,基于图表当前尺寸动态计算坐标,绘制外弧、左右刻度线
  3. 确保插件适配响应式,窗口大小变化时自动重绘

完整代码示例

<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>

关键细节说明

  1. 插件的坐标计算:通过chart.chartArea获取图表的实际绘制区域,确保方括号始终居中,且适配容器尺寸变化
  2. 角度转换:Chart.js内部用弧度计算角度,所以需要把我们习惯的角度(0-360度)转换成弧度
  3. 响应式适配:开启responsive: true和maintainAspectRatio: false,配合容器的50vw宽度,窗口大小变化时图表会自动重绘,插件也会重新计算坐标绘制方括号
  4. 动态数据:内层数据集的data可以随时替换,图表会自动更新,不影响外层方括号的样式

为什么之前的方法无效?

  • Chart.js 3.x中,borderWidth只能是数值,不支持对象形式(比如{top:1, right:1}),所以设置后会破坏图表结构
  • borderColor同样只能是单一颜色或对应数据集的颜色数组,无法单独控制某一段边框
  • cutout是控制整个环形的内半径,无法针对某一段切片自定义样式

内容的提问来源于stack exchange,提问作者user19881049

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 07:00:57