You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何用Chart.js在同一Canvas内实现环形图内嵌不同数据的饼图

How to Render a Doughnut Chart with an Inner Pie Chart on the Same Canvas in Chart.js

Got it, let's break this down step by step. You can absolutely stack a pie chart inside a doughnut chart on the same Canvas using Chart.js—we just need to leverage the same canvas context and adjust the layout of the inner pie chart to fit within the doughnut's cutout.

Step 1: Set Up Your HTML Canvas

First, create a single canvas element to hold both charts:

<canvas id="dualChart" width="400" height="400"></canvas>

Step 2: Define Your Independent Datasets

Create separate data objects for the outer doughnut and inner pie chart:

// Outer Doughnut Chart Data
const doughnutDataset = {
  labels: ['Segment A', 'Segment B', 'Segment C', 'Segment D'],
  datasets: [{
    data: [30, 20, 25, 25],
    backgroundColor: ['#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0'],
    borderWidth: 0
  }]
};

// Inner Pie Chart Data
const pieDataset = {
  labels: ['Inner X', 'Inner Y', 'Inner Z'],
  datasets: [{
    data: [50, 30, 20],
    backgroundColor: ['#9966FF', '#FF9F40', '#FF6B6B'],
    borderWidth: 0
  }]
};

Step 3: Initialize the Outer Doughnut Chart

First, render the doughnut chart with a large enough cutout to make space for the inner pie. The cutout value is a percentage of the outer radius—we'll use 70% here to leave a wide inner area:

const ctx = document.getElementById('dualChart').getContext('2d');

// Outer Doughnut Chart
const doughnutChart = new Chart(ctx, {
  type: 'doughnut',
  data: doughnutDataset,
  options: {
    responsive: true,
    maintainAspectRatio: true,
    cutout: '70%', // Critical: Creates space for the inner pie
    plugins: {
      legend: {
        position: 'bottom', // Move legend below to avoid overlapping
        labels: {
          boxWidth: 12
        }
      },
      tooltip: {
        callbacks: {
          label: (ctx) => `${ctx.label}: ${ctx.parsed}%`
        }
      }
    }
  }
});

Step 4: Render the Inner Pie Chart

Now, create a second Chart instance using the same canvas context. We'll use a beforeDraw hook to shrink the pie chart's drawing area so it fits perfectly inside the doughnut's cutout:

// Inner Pie Chart
const pieChart = new Chart(ctx, {
  type: 'pie',
  data: pieDataset,
  options: {
    responsive: true,
    maintainAspectRatio: false,
    animation: { duration: 0 }, // Disable animation to avoid conflict with doughnut
    plugins: {
      legend: { display: false }, // Hide inner pie legend (optional)
      tooltip: {
        callbacks: {
          label: (ctx) => `${ctx.label}: ${ctx.parsed}%`
        }
      }
    },
    beforeDraw: (chart) => {
      // Calculate the center and radius for the inner pie
      const chartCenterX = chart.getDatasetMeta(0).data[0].x;
      const chartCenterY = chart.getDatasetMeta(0).data[0].y;
      const innerRadius = Math.min(chart.width, chart.height) / 2 * 0.3; // Match doughnut's cutout

      // Adjust the chart's drawing area to center the pie
      chart.chartArea = {
        left: chartCenterX - innerRadius,
        top: chartCenterY - innerRadius,
        right: chartCenterX + innerRadius,
        bottom: chartCenterY + innerRadius
      };
    }
  }
});

Step 5: Handle Responsive Resizing

Make sure both charts resize properly when the window changes:

window.addEventListener('resize', () => {
  doughnutChart.resize();
  pieChart.resize();
});

Key Notes & Troubleshooting

  • Interaction Conflicts: Since both charts share the same canvas, hover/click events might overlap. If this is an issue, you can customize the interaction options (e.g., set interaction.mode: 'nearest') or use a plugin to handle event delegation.
  • Cutout Size: Adjust the doughnut's cutout percentage and the inner pie's innerRadius value to get the perfect fit—tweak these numbers based on your desired visual style.
  • Color Contrast: Ensure the inner pie's colors are distinct from the outer doughnut so the two charts are easily distinguishable.

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

火山引擎 最新活动