如何用Chart.js在同一Canvas内实现环形图内嵌不同数据的饼图
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
interactionoptions (e.g., setinteraction.mode: 'nearest') or use a plugin to handle event delegation. - Cutout Size: Adjust the doughnut's
cutoutpercentage and the inner pie'sinnerRadiusvalue 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




