1👍
✅
Please take a look at below runnable code and see how it could be done.
When it comes to the
legend
, you’ll probably have to implement a solution as explained in this answer.
let data = [
{city: "Budapest", country: "Hungary"},
{city: "Shenzen", country: "China"},
{city: "Beijing", country: "China"},
{city: "Shenzen", country: "China"},
{city: "Istanbul", country: "Turkey"},
{city: "Ho Chi Minh", country: "Vietnam"},
{city: "Shenzen", country: "China"},
{city: "Debrecen", country: "Hungary"},
{city: "Budapest", country: "Hungary"},
{city: "Shenzen", country: "China"},
{city: "Shenzen", country: "China"},
{city: "Shenzen", country: "China"},
{city: "Istanbul", country: "Turkey"},
{city: "Budapest", country: "Hungary"},
{city: "Beijing", country: "China"},
{city: "Shenzen", country: "China"},
{city: "Shenzen", country: "China"},
{city: "Istanbul", country: "Turkey"}
];
const colors = ['204, 0, 0', '0, 0, 255', '0, 153, 0', '153, 51, 255'];
data = data
.sort((o1, o2) => o1.country.localeCompare(o2.country));
const countries = data
.reduce((acc, o) => {
let country = acc.find(v => v.country == o.country);
if (!country) {
country = { country: o.country, cities: 0 };
acc.push(country);
}
++country.cities;
return acc;
}, []);
countries.forEach((c, i) => c.color = colors[i]);
const cities = data
.reduce((acc, o) => {
let city = acc.find(v => v.city == o.city);
if (!city) {
city = { country: o.country, city: o.city, count: 0 };
acc.push(city);
}
++city.count;
return acc;
}, []);
cities.forEach(c => c.color = countries.find(o => o.country == c.country).color);
Chart.register(ChartDataLabels);
new Chart('myChart', {
type: 'doughnut',
data: {
datasets: [{
data: cities.map(o => o.count),
labels: cities.map(o => o.city),
backgroundColor: cities.map(c => 'rgba(' + c.color + ', 0.2)'),
borderWidth: 3
},
{
data: countries.map(c => c.cities),
labels: countries.map(c => c.country),
backgroundColor: countries.map(c => 'rgb(' + c.color + ', 0.4)'),
borderWidth: 3
}
]
},
options: {
cutout: '40%',
plugins: {
datalabels: {
textAlign: 'center',
formatter: (v, ctx) => {
const dataset = ctx.chart.data.datasets[ctx.datasetIndex];
return dataset.labels[ctx.dataIndex] + ': ' + dataset.data[ctx.dataIndex];
}
}
}
}
});
canvas {
max-height: 400px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.8.0/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2"></script>
<canvas id="myChart"></canvas>
Source:stackexchange.com