Chart.js Pie, Doughnut, Radar & Polar Area — Complete Guide
Pie, doughnut, radar, and polar area charts excel at showing proportions, part-to-whole relationships, and multi-dimensional comparisons — things bar and line charts struggle with.
What You’ll Learn
By the end of this tutorial, you’ll build pie and doughnut charts with custom cutout sizes and percentage tooltips, add center text to doughnut charts using custom plugins, create radar/spider charts for comparing multiple variables across subjects, configure radial scales with point labels and grid lines, and build polar area charts with varying radii.
When to Use Circular and Radial Charts
Each chart type has a specific job:
- Pie chart: Shows how a total is divided into parts. Best with 2-5 slices. Example: market share by company.
- Doughnut chart: Same as pie, but the center hole can display summary information. Generally preferred over pie because the hole improves readability.
- Radar chart: Compares multiple variables across subjects. Example: comparing employee skills across 6 dimensions.
- Polar area: Like a pie chart but with equal angles and radii proportional to values. The varying radii make small values harder to miss.
Rule of thumb: If you need to compare values to each other, use a bar chart. If you need to show how a total is divided, use a doughnut. If the categories are the same across two or more subjects, use a radar.
Real-world use: Durga Antivirus Pro uses doughnut charts to show the breakdown of detected threats by type (malware 45%, phishing 30%, ransomware 15%, other 10%). A radar chart compares the detection performance across different operating systems (Windows, macOS, Linux, Android, iOS) to identify which platforms need improvement.
Where This Fits in Your Learning Path
flowchart LR
A["Chart.js Basics"] --> B["Line, Bar & Mixed Charts"]
B --> C["**Pie, Doughnut, Radar & Polar**"]
C --> D["Scatter & Bubble Charts"]
D --> E["Chart.js Advanced"]
style C fill:#f97316,stroke:#c2410c,color:#fff
style A fill:#e5e7eb,stroke:#9ca3af,color:#374151
style E fill:#22c55e,stroke:#16a34a,color:#22c55e
Pie Chart
A pie chart divides a circle into proportional slices. The angle of each slice is proportional to its value.
new Chart(ctx, {
type: 'pie',
data: {
labels: ['Red', 'Blue', 'Yellow', 'Green'],
datasets: [{
label: 'Color Distribution',
data: [30, 50, 15, 25],
backgroundColor: [
'rgb(255, 99, 132)',
'rgb(54, 162, 235)',
'rgb(255, 205, 86)',
'rgb(75, 192, 192)'
],
hoverOffset: 10 // Pull slice outward on hover
}]
},
options: {
responsive: true,
plugins: {
legend: {
position: 'right',
labels: { padding: 20 }
},
tooltip: {
callbacks: {
label: (context) => {
const total = context.dataset.data.reduce((a, b) => a + b, 0)
const pct = Math.round(context.parsed / total * 100)
return context.label + ': ' + context.parsed + ' (' + pct + '%)'
}
}
}
}
}
})Why the tooltip callback is important: Without it, the tooltip shows only the raw number. Adding the percentage helps viewers understand the proportion at a glance.
Doughnut Chart
Nearly identical to pie, but with a hole in the center:
type: 'doughnut',
options: {
cutout: '50%' // 0% = pie, 50% = standard donut, 90% = thin ring
}Doughnut with Center Text
One of the most requested features: display a total or summary in the center of the doughnut. Chart.js doesn’t support this natively, but you can add it with a custom plugin:
const centerTextPlugin = {
id: 'centerText',
beforeDraw: function(chart) {
const { width, height, ctx } = chart
ctx.restore()
const fontSize = (height / 150).toFixed(2)
ctx.font = fontSize + 'em sans-serif'
ctx.textBaseline = 'middle'
const total = chart.data.datasets[0].data.reduce((a, b) => a + b, 0)
const text = total.toString()
const textX = Math.round((width - ctx.measureText(text).width) / 2)
const textY = height / 2
ctx.fillText(text, textX, textY)
ctx.save()
}
}
new Chart(ctx, {
type: 'doughnut',
data: { /* ... */ },
options: { cutout: '70%' },
plugins: [centerTextPlugin]
})Multi-Dataset Doughnut (Nested Rings)
Add multiple datasets to create concentric rings:
datasets: [{
data: [30, 50, 20],
backgroundColor: ['red', 'blue', 'yellow']
}, {
data: [40, 30, 30],
backgroundColor: ['pink', 'lightblue', 'lightyellow']
}]Useful for comparing two levels of categorization — e.g., outer ring = category, inner ring = subcategory breakdown within the selected category.
Radar Chart
Radar charts (also called spider charts) plot values on multiple axes radiating from a center point. Each axis represents a variable.
new Chart(ctx, {
type: 'radar',
data: {
labels: ['Speed', 'Strength', 'Agility', 'Endurance', 'Accuracy', 'Strategy'],
datasets: [
{
label: 'Player A',
data: [90, 75, 85, 70, 80, 65],
backgroundColor: 'rgba(54, 162, 235, 0.2)',
borderColor: 'rgb(54, 162, 235)',
pointBackgroundColor: 'rgb(54, 162, 235)',
pointRadius: 4
},
{
label: 'Player B',
data: [70, 85, 60, 90, 75, 80],
backgroundColor: 'rgba(255, 99, 132, 0.2)',
borderColor: 'rgb(255, 99, 132)',
pointBackgroundColor: 'rgb(255, 99, 132)',
pointRadius: 4
}
]
},
options: {
responsive: true,
plugins: {
title: { display: true, text: 'Player Comparison' }
},
scales: {
r: {
beginAtZero: true,
max: 100,
ticks: { stepSize: 20, backdropColor: 'transparent' },
pointLabels: { font: { size: 12 }, color: '#666' },
grid: { color: 'rgba(0,0,0,0.1)' },
angleLines: { color: 'rgba(0,0,0,0.1)' }
}
}
}
})Reading a radar chart: Player A (blue) is strong in Speed and Accuracy. Player B (red) is strong in Strength and Endurance. The overlap reveals their relative strengths at a glance.
Key Radar Options
scales: {
r: {
beginAtZero: true, // Always true for honest comparison
min: 0, max: 100,
ticks: {
stepSize: 10, // Grid line interval
callback: (v) => v + '%',
backdropColor: 'rgba(255,255,255,0.8)' // Background behind tick labels
},
pointLabels: {
font: { size: 12, weight: 'bold' },
color: '#333',
padding: 20 // Distance from edge
},
grid: {
circular: false, // false = polygonal, true = circular
color: 'rgba(0,0,0,0.1)'
},
angleLines: {
display: true,
color: 'rgba(0,0,0,0.1)'
}
}
}Polar Area Chart
Similar to a pie chart, but each segment has the same angle and the radius varies with the value. This makes small values more visible than in a pie chart.
new Chart(ctx, {
type: 'polarArea',
data: {
labels: ['Red', 'Green', 'Yellow', 'Blue', 'Purple'],
datasets: [{
label: 'My Dataset',
data: [11, 16, 7, 3, 14],
backgroundColor: [
'rgba(255, 99, 132, 0.7)',
'rgba(75, 192, 192, 0.7)',
'rgba(255, 205, 86, 0.7)',
'rgba(54, 162, 235, 0.7)',
'rgba(153, 102, 255, 0.7)'
],
borderWidth: 1
}]
},
options: {
responsive: true,
plugins: { legend: { position: 'right' } },
scales: {
r: {
beginAtZero: true,
grid: { color: 'rgba(0,0,0,0.05)' }
}
}
}
})Common Options for Circular Charts
options: {
cutout: '50%', // Doughnut hole size (pie = 0)
radius: '100%', // Chart radius
rotation: 0, // Start angle in degrees
circumference: 360, // Sweep angle (360 = full circle, 180 = half)
animation: {
animateRotate: true, // Spin on load
animateScale: false // Grow from center on load
}
}Common Mistakes Beginners Make
1. Too Many Pie Slices
Pie charts with more than 5-7 slices become unreadable. Group small values into “Other” or switch to a bar chart.
2. Pie Without Percentage Tooltips
Without showing percentages, viewers can’t compare slice sizes accurately. Always add the tooltip callback shown above.
3. Radar Chart With Too Many Variables
More than 8-10 axes create a cluttered “spider web” that’s hard to read. Each additional axis reduces clarity.
4. Doughnut Cutout Too Large
For cutout values above 80%, the ring becomes too thin for effective visual comparison. Keep cutout between 40-70%.
5. Forgetting beginAtZero on Radar Axis
Radar charts without beginAtZero can exaggerate small differences. Always start radial axes at zero.
Practice Questions
What is the difference between a pie chart and a doughnut chart? A pie chart has a solid center (
cutout: 0). A doughnut has a hole (cutout: '50%'). Doughnuts are preferred because the center can display summary info.How do you display the total value in the center of a doughnut chart? Chart.js doesn’t have built-in support. Use a custom plugin with a
beforeDrawhook that draws text at the center of the canvas.What does the
hoverOffsetproperty do in a pie chart? It pulls the slice outward from the center when the user hovers over it, creating a “pop-out” effect.What’s the maximum recommended number of slices for a pie chart? 5-7. Beyond that, switch to a bar chart or group small values into “Other.”
When should you use a polar area chart instead of a pie chart? When you want small values to be more visible. In a polar area chart, each segment has the same angle but different radius, making all segments equally distinguishable.
Challenge
Create a skills assessment dashboard with:
- A radar chart comparing “Current” vs “Target” skill levels across 6-8 skills
- A doughnut chart showing time allocation (Learning, Building, Reviewing, Planning, Testing)
- Percentage values in the doughnut tooltips
- A slider that adjusts the target skill levels in the radar chart dynamically
FAQ
Try It Yourself: Skills Assessment Dashboard
Compare current vs target skill levels on a radar chart, and see your time allocation on a doughnut chart.
<!DOCTYPE html>
<html>
<head>
<title>Skills Assessment Dashboard</title>
<style>
body { font-family: sans-serif; padding: 20px; }
.dashboard { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; max-width: 800px; }
.card { border: 1px solid #ddd; border-radius: 8px; padding: 15px; }
.card h3 { margin: 0 0 10px 0; font-size: 14px; color: #666; }
</style>
</head>
<body>
<h2>Skills Assessment Dashboard</h2>
<div class="dashboard">
<div class="card"><h3>Skill Levels (Radar)</h3><canvas id="radarChart"></canvas></div>
<div class="card"><h3>Time Allocation (Doughnut)</h3><canvas id="doughnutChart"></canvas></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
new Chart(document.getElementById('radarChart'), { type: 'radar', data: { labels: ['JavaScript', 'Python', 'CSS', 'SQL', 'DevOps', 'Testing'], datasets: [{ label: 'Current', data: [85,70,75,60,40,55], backgroundColor: 'rgba(54,162,235,0.2)', borderColor: 'rgb(54,162,235)', pointBackgroundColor: 'rgb(54,162,235)' }, { label: 'Target', data: [90,85,80,80,70,75], backgroundColor: 'rgba(255,99,132,0.2)', borderColor: 'rgb(255,99,132)', pointBackgroundColor: 'rgb(255,99,132)' }] }, options: { responsive: true, scales: { r: { beginAtZero: true, max: 100, ticks: { stepSize: 20 } } } } })
new Chart(document.getElementById('doughnutChart'), { type: 'doughnut', data: { labels: ['Learning', 'Building', 'Reviewing', 'Planning', 'Testing'], datasets: [{ data: [35,30,15,12,8], backgroundColor: ['rgb(54,162,235)', 'rgb(75,192,192)', 'rgb(255,205,86)', 'rgb(153,102,255)', 'rgb(255,159,64)'] }] }, options: { responsive: true, cutout: '60%', plugins: { legend: { position: 'right' }, tooltip: { callbacks: { label: (ctx) => { const total = ctx.dataset.data.reduce((a,b)=>a+b,0); return ctx.label + ': ' + Math.round(ctx.parsed / total * 100) + '%' } } } } } })
</script>
</body>
</html>What to expect: Left side shows a radar chart comparing current skills (blue) against target skills (red) across 6 dimensions. Right side shows a doughnut chart of time allocation with percentage tooltips on hover.
What’s Next
| Tutorial | What You’ll Learn |
|---|---|
| Scatter & Bubble Charts | X/Y scatter plots, three-variable bubble charts |
| Chart.js Advanced | Animations, interactions, custom plugins |
Related topics: Chart.js Line & Bar, Data Visualization best practices.
What’s Next
Congratulations on completing this Chartjs Pie Doughnut tutorial! Here’s where to go from here:
- Practice daily — Consistency is more important than long study sessions
- Build a project — Apply what you learned by building something real
- Explore related topics — Check out other tutorials in the same category
- Join the community — Discuss with other learners and share your progress
Remember: every expert was once a beginner. Keep coding!
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro