当图例项变为 off/on 时,如何在 charts.js 饼图中重新分配值?
How can I re-distribute values within a charts.js pie chart when a legend item is turned off/on?
我已经将数据分布在整个饼图中,总计等于 100%(我认为大声笑)如果您不介意,请验证这是正确的。但是我希望能够在我转动 off/on 图例项时重新分发数据。
这是组件的示例
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" }
];
const lifetime_viewing_subs_total = data.map(item => item.lifetime_viewing_subs).reduce((prev, next) => prev + next);
export const pieoptions = {
responsive: true,
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];
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} />
);
}
提前致谢
您可以像这样在格式化程序函数中计算百分比:
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) + "%";
},
实例:
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>
我不明白你想要 re-distribute 的逻辑是什么,但无论如何我为 re-distribute 数据写了一些逻辑,当你 turn off/on
图例项。
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} />
);
}
我已经覆盖了 plugins/legend/onclick 方法,像这样
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();
}
你可以 redesign
随心所欲地操作,工作示例 playground
我已经将数据分布在整个饼图中,总计等于 100%(我认为大声笑)如果您不介意,请验证这是正确的。但是我希望能够在我转动 off/on 图例项时重新分发数据。
这是组件的示例
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" }
];
const lifetime_viewing_subs_total = data.map(item => item.lifetime_viewing_subs).reduce((prev, next) => prev + next);
export const pieoptions = {
responsive: true,
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];
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} />
);
}
提前致谢
您可以像这样在格式化程序函数中计算百分比:
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) + "%";
},
实例:
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>
我不明白你想要 re-distribute 的逻辑是什么,但无论如何我为 re-distribute 数据写了一些逻辑,当你 turn off/on
图例项。
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} />
);
}
我已经覆盖了 plugins/legend/onclick 方法,像这样
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();
}
你可以 redesign
随心所欲地操作,工作示例 playground