1👍
✅
You can calculate the percentage in the formatter function like so:
formatter: function(value, ctx) {
const max = ctx.dataset.data.reduce((acc, curr, index) => {
const isVisible = ctx.chart.getDataVisibility(index)
if (isVisible) {
acc += curr;
}
return acc;
}, 0)
return Math.round(value * 100 / max).toFixed(0) + "%";
},
Live example:
Chart.register(ChartDataLabels);
const data = [{
lifetime_viewing_subs: 11497117,
name: "US"
},
{
lifetime_viewing_subs: 3777651,
name: "LATAM"
},
{
lifetime_viewing_subs: 2494138,
name: "EMEA"
}
];
const lifetime_viewing_subs_total = data
.map((item) => item.lifetime_viewing_subs)
.reduce((prev, next) => prev + next);
const options = {
type: 'pie',
data: {
labels: data.map((s) => s.name),
datasets: [{
label: '# of Votes',
data: data.map((s) => s.lifetime_viewing_subs / lifetime_viewing_subs_total),
backgroundColor: [
"rgba(255, 99, 132, 0.2)",
"rgba(54, 162, 235, 0.2)",
"rgba(255, 206, 86, 0.2)"
],
borderColor: [
"rgba(255, 99, 132, 1)",
"rgba(54, 162, 235, 1)",
"rgba(255, 206, 86, 1)"
],
borderWidth: 1
}]
},
options: {
plugins: {
legend: {
position: "bottom",
align: "center"
},
datalabels: {
color: function(context) {
return context.dataset.borderColor;
},
anchor: "center",
backgroundColor: function(context) {
return context.dataset.background;
},
borderRadius: 100,
borderWidth: 2,
borderColor: function(context) {
return context.dataset.borderColor;
},
display: function(context) {
var dataset = context.dataset;
var value = dataset.data[context.dataIndex];
return value;
},
formatter: function(value, ctx) {
const max = ctx.dataset.data.reduce((acc, curr, index) => {
const isVisible = ctx.chart.getDataVisibility(index)
if (isVisible) {
acc += curr;
}
return acc;
}, 0)
return Math.round(value * 100 / max).toFixed(0) + "%";
},
font: {
weight: 500,
size: "14rem"
}
}
}
}
}
var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdn.jsdelivr.net/npm/chart.js/dist/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels"></script>
</body>
0👍
I don’t understand what is the logic that you want to re-distribute but anyway I wrote some logic for re-distribute the data when you turn off/on
the legend items.
import React from "react";
import { Chart as ChartJS, ArcElement, Tooltip, Legend } from "chart.js";
import { Pie } from "react-chartjs-2";
import ChartDataLabels from "chartjs-plugin-datalabels";
ChartJS.register(ChartDataLabels, ArcElement, Tooltip, Legend);
export const data = [
{ lifetime_viewing_subs: 11497117, name: "US" },
{ lifetime_viewing_subs: 3777651, name: "LATAM" },
{ lifetime_viewing_subs: 2494138, name: "EMEA" }
];
var defaultLegendClickHandler = ChartJS.defaults.plugins.legend.onClick;
const lifetime_viewing_subs_total = data
.map((item) => item.lifetime_viewing_subs)
.reduce((prev, next) => prev + next);
export const pieoptions = {
responsive: true,
plugins: {
legend: {
onClick(event, legendItem, legend) {
let index = legendItem.index;
let ci = legend.chart;
let tmpData;
legend.chart.data.datasets.forEach((d, i) => {
let dividerSize = d.data.length;
console.log(d)
d.data.forEach((pie, j) => {
if (index === j) {
// clicked item is it
tmpData = d.data[index];
// you can define here what you want
// for clicked label
// d.data[j] = 0.20;
// curently i will clear value
d.data[j] = 0;
} else {
// here you can work on other pieces
// you can update next two pieces
// d.data[j] = d.data[j] + 0.22
d.data[j] = pie + 0.2
}
//
});
});
ci.update();
},
position: "bottom",
align: "center"
},
datalabels: {
color: function (context) {
return context.dataset.borderColor;
},
anchor: "center",
backgroundColor: function (context) {
return context.dataset.background;
},
borderRadius: 100,
borderWidth: 2,
borderColor: function (context) {
return context.dataset.borderColor;
},
display: function (context) {
var dataset = context.dataset;
var value = dataset.data[context.dataIndex];
// console.log("context.dataIndex: ", context.dataIndex); // 0,1,2
// console.log("dataset: ", dataset); // the dataset object
// console.log("value: ", value); // 0.1403653100534158, 0.647035726341284, 0.21259896360530017
return value;
},
formatter: function (value) {
return Math.round(value * 100).toFixed(0) + "%";
},
font: {
weight: 500,
size: "14rem"
}
}
}
};
export const piedata = {
labels: data.map((s) => s.name),
datasets: [
{
data: data.map(
(s) => s.lifetime_viewing_subs / lifetime_viewing_subs_total
),
backgroundColor: [
"rgba(255, 99, 132, 0.2)",
"rgba(54, 162, 235, 0.2)",
"rgba(255, 206, 86, 0.2)"
],
borderColor: [
"rgba(255, 99, 132, 1)",
"rgba(54, 162, 235, 1)",
"rgba(255, 206, 86, 1)"
],
fill: true,
borderWidth: 1
}
]
};
export function App() {
return (
<Pie options={pieoptions} plugins={[ChartDataLabels]} data={piedata} />
);
}
I have made override of plugins/legend/onclick method , like this
plugins: {
legend: {
onClick(event, legendItem, legend) {
let index = legendItem.index;
let ci = legend.chart;
let tmpData;
legend.chart.data.datasets.forEach((d, i) => {
let dividerSize = d.data.length;
console.log(d)
d.data.forEach((pie, j) => {
if (index === j) {
// clicked item is it
tmpData = d.data[index];
// you can define here what you want
// for clicked label
// d.data[j] = 0.20;
// curently i will clear value
d.data[j] = 0;
} else {
// here you can work on other pieces
// you can update next two pieces
// d.data[j] = d.data[j] + 0.22
d.data[j] = pie + 0.2
}
//
});
});
ci.update();
}
you can redesign
action like you want, working example playground
Source:stackexchange.com