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

如何使用Chart.js实现饼图嵌套环形图的绘制?

实现Chart.js嵌套饼图+环形图的方案

嘿,我正好做过类似的需求!你要的这种内外层嵌套的饼图+环形图效果,其实不用分开画两个独立的图表,咱们可以在同一个Canvas元素上叠加两个Chart实例,轻松实现,而且完全保留各自数据的独立性,完美匹配你的需求。

核心实现思路

  • 复用同一个<canvas>容器,先后创建两个Chart实例:一个作为内部核心饼图,一个作为外层环形图。
  • 给外层环形图设置合适的cutoutPercentage参数,让它的空心区域刚好能容纳内部饼图。
  • 调整图例、布局等配置,避免两个图表的元素互相重叠干扰。

完整实现代码

首先确保HTML里有一个用于承载嵌套图表的Canvas:

<canvas id="nested_chart"></canvas>

然后是JavaScript逻辑,我们把两个图表的绘制逻辑整合,让它们共用同一个画布:

function drawNestedPieDoughnut(innerLabels, innerData, innerColors, outerLabels, outerData, outerColors, title) {
  const ctx = document.getElementById('nested_chart').getContext('2d');
  
  // 绘制内部饼图
  const innerPieChart = new Chart(ctx, {
    type: 'pie',
    data: {
      labels: innerLabels,
      datasets: [{
        backgroundColor: innerColors,
        data: innerData
      }]
    },
    options: {
      responsive: true,
      maintainAspectRatio: true,
      legend: {
        display: false, // 隐藏内部饼图图例,避免和外层重叠
      },
      tooltips: {
        callbacks: {
          label: function (tooltipItem, data) {
            // 保留你原有的时间格式化逻辑
            return secondsToHHMMSS(data['datasets'][0]['data'][tooltipItem['index']]);
          }
        }
      },
      layout: {
        padding: 20 // 给图表留边,避免内容溢出
      }
    }
  });

  // 绘制外层环形图,复用同一个画布上下文
  const outerDoughnutChart = new Chart(ctx, {
    type: 'doughnut',
    data: {
      labels: outerLabels,
      datasets: [{
        backgroundColor: outerColors,
        data: outerData
      }]
    },
    options: {
      responsive: true,
      maintainAspectRatio: true,
      cutoutPercentage: 60, // 控制环形空心大小,60表示空心占60%,可根据显示效果调整
      legend: {
        position: 'top',
      },
      title: {
        display: true,
        text: title
      },
      animation: {
        animateScale: true,
        animateRotate: true
      },
      layout: {
        padding: 20 // 和内部饼图保持一致的边距
      }
    }
  });

  // 返回两个实例,方便后续更新数据或调整配置
  return { innerPieChart, outerDoughnutChart };
}

// 保留你原有的时间格式化函数
function secondsToHHMMSS(seconds) {
  const hours = Math.floor(seconds / 3600);
  const minutes = Math.floor((seconds % 3600) / 60);
  const secs = seconds % 60;
  return `${hours}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
}

使用示例

你可以像这样调用函数,传入内外层各自的标签、数据和颜色:

// 内部饼图数据
const innerLabels = ['空闲', '忙碌'];
const innerData = [1200, 2400];
const innerColors = ['#FF6384', '#36A2EB'];

// 外部环形图数据
const outerLabels = ['处理中', '等待分配', '已完成'];
const outerData = [1800, 900, 900];
const outerColors = ['#FFCE56', '#4BC0C0', '#9966FF'];

// 绘制嵌套图表
drawNestedPieDoughnut(innerLabels, innerData, innerColors, outerLabels, outerData, outerColors, '运营状态统计');

关键参数说明

  • cutoutPercentage:环形图的核心参数,值越大空心区域越大。我这里设为60,你可以根据实际显示效果微调,直到内部饼图刚好填满空心区域。
  • legend.display:建议隐藏内部饼图的图例,避免和外层图例重叠;如果需要显示内部图例,可以调整图例的position到bottom等位置。
  • maintainAspectRatio:保持为true,确保图表始终是圆形,不会被容器拉伸变形。

这样实现的嵌套图表,内外层数据完全独立,各自的提示框、动画都能正常工作,完全满足你的需求~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 06:58:55