如何在堆叠条的顶部显示 "total" 总和标签
How to show a "total" sum label on the top of stacked bars
我希望每个堆叠条的“总”标签位置正好在整个条的上方。
我已经设法得到总和,但我无法将标签定位在顶部。
如果您注意到,标签位于底部:
我试过使用 anchor
和 offset
属性,但无法达到预期的结果。
代码:
import * as React from "react";
import { Bar as RCBar } from "react-chartjs-2";
import { CategoryScale } from "chart.js";
import Chart from "chart.js/auto";
import events from "./events";
import chartOptions from "./chartOptions";
import ChartDataLabels from "chartjs-plugin-datalabels";
Chart.register(CategoryScale, ChartDataLabels);
const Graph = React.memo(() => {
const canvasRef = React.useRef(null);
const chartContainerRef = React.useRef(null);
const formatter = (value, ctx) => {
const datasets = ctx.chart.data.datasets.filter(
(ds) => !ds._meta?.[0].hidden
);
const foundDatasetIndex = datasets.indexOf(ctx.dataset);
if (foundDatasetIndex === datasets.length - 1) {
let sum = 0;
datasets.forEach((dataset) => {
sum += dataset.data[ctx.dataIndex];
});
return sum;
} else {
return "";
}
};
const generateChartData = React.useCallback(() => {
const labels = [];
const dataNew = [];
const dataSuccess = [];
const dataOnHold = [];
const dataCanceled = [];
events.forEach((event) => {
labels.push(event.trigger);
event.detailStatus.forEach((detailStatus) => {
if (detailStatus.code === 0) {
dataNew.push({
label: event.trigger,
sum: detailStatus.sum
});
}
if (detailStatus.code === 1) {
dataSuccess.push({
label: event.trigger,
sum: detailStatus.sum
});
}
if (detailStatus.code === 10) {
dataOnHold.push({
label: event.trigger,
sum: detailStatus.sum
});
}
if (detailStatus.code === 11) {
dataCanceled.push({
label: event.trigger,
sum: detailStatus.sum
});
}
});
});
return {
labels,
datasets: [
{
label: "New",
data: labels.map(
(label) =>
dataNew.find(({ label: labelInData }) => labelInData === label)
?.sum ?? 0
),
backgroundColor: "rgba(0, 120, 153, 1)",
borderColor: "rgba(255, 255, 255, 1)",
borderWidth: 2,
borderRadius: 5,
borderSkipped: "bottom",
barThickness: 15
},
{
label: "Finished",
data: labels.map(
(label) =>
dataSuccess.find(
({ label: labelInData }) => labelInData === label
)?.sum ?? 0
),
backgroundColor: "rgba(4, 198, 201, 1)",
borderColor: "rgba(255, 255, 255, 1)",
borderWidth: 2,
borderRadius: 5,
borderSkipped: "bottom",
barThickness: 15
},
{
label: "On hold",
data: labels.map(
(label) =>
dataOnHold.find(({ label: labelInData }) => labelInData === label)
?.sum ?? 0
),
backgroundColor: "rgba(211, 156, 247, 1)",
borderColor: "rgba(255, 255, 255, 1)",
borderWidth: 2,
borderRadius: 5,
borderSkipped: "bottom",
barThickness: 15
},
{
label: "Cancelled",
data: labels.map(
(label) =>
dataCanceled.find(
({ label: labelInData }) => labelInData === label
)?.sum ?? 0
),
backgroundColor: "rgba(168, 180, 189, 1)",
borderColor: "rgba(255, 255, 255, 1)",
borderWidth: 2,
borderRadius: 5,
borderSkipped: "bottom",
barThickness: 15
}
]
};
}, []);
return (
<div ref={chartContainerRef}>
<RCBar
options={{
...chartOptions,
plugins: {
...chartOptions.plugins,
datalabels: {
...chartOptions.plugins.datalabels,
formatter
}
}
}}
data={generateChartData()}
ref={canvasRef}
/>
</div>
);
});
export default Graph;
您需要更改 formatter
函数才能使其正常工作。
总值应仅出现在堆叠条形图的最高值上。然而,堆叠条不包含零值,也不包含来自隐藏 datasets
的值。我最终得到了以下可行的解决方案,但可能是 improved/simplified.
const formatter = (value, ctx) => {
const stackedValues = ctx.chart.data.datasets
.map((ds) => ds.data[ctx.dataIndex]);
const dsIdxLastVisibleNonZeroValue = stackedValues
.reduce((prev, curr, i) => !!curr && !ctx.chart.getDatasetMeta(i).hidden ? Math.max(prev, i) : prev, 0);
if (!!value && ctx.datasetIndex === dsIdxLastVisibleNonZeroValue) {
return stackedValues
.filter((ds, i) => !ctx.chart.getDatasetMeta(i).hidden)
.reduce((sum, v) => sum + v, 0);
} else {
return "";
}
};
请查看您修改后的 Code Sandbox,看看它是如何工作的。
我希望每个堆叠条的“总”标签位置正好在整个条的上方。
我已经设法得到总和,但我无法将标签定位在顶部。
如果您注意到,标签位于底部:
我试过使用 anchor
和 offset
属性,但无法达到预期的结果。
代码:
import * as React from "react";
import { Bar as RCBar } from "react-chartjs-2";
import { CategoryScale } from "chart.js";
import Chart from "chart.js/auto";
import events from "./events";
import chartOptions from "./chartOptions";
import ChartDataLabels from "chartjs-plugin-datalabels";
Chart.register(CategoryScale, ChartDataLabels);
const Graph = React.memo(() => {
const canvasRef = React.useRef(null);
const chartContainerRef = React.useRef(null);
const formatter = (value, ctx) => {
const datasets = ctx.chart.data.datasets.filter(
(ds) => !ds._meta?.[0].hidden
);
const foundDatasetIndex = datasets.indexOf(ctx.dataset);
if (foundDatasetIndex === datasets.length - 1) {
let sum = 0;
datasets.forEach((dataset) => {
sum += dataset.data[ctx.dataIndex];
});
return sum;
} else {
return "";
}
};
const generateChartData = React.useCallback(() => {
const labels = [];
const dataNew = [];
const dataSuccess = [];
const dataOnHold = [];
const dataCanceled = [];
events.forEach((event) => {
labels.push(event.trigger);
event.detailStatus.forEach((detailStatus) => {
if (detailStatus.code === 0) {
dataNew.push({
label: event.trigger,
sum: detailStatus.sum
});
}
if (detailStatus.code === 1) {
dataSuccess.push({
label: event.trigger,
sum: detailStatus.sum
});
}
if (detailStatus.code === 10) {
dataOnHold.push({
label: event.trigger,
sum: detailStatus.sum
});
}
if (detailStatus.code === 11) {
dataCanceled.push({
label: event.trigger,
sum: detailStatus.sum
});
}
});
});
return {
labels,
datasets: [
{
label: "New",
data: labels.map(
(label) =>
dataNew.find(({ label: labelInData }) => labelInData === label)
?.sum ?? 0
),
backgroundColor: "rgba(0, 120, 153, 1)",
borderColor: "rgba(255, 255, 255, 1)",
borderWidth: 2,
borderRadius: 5,
borderSkipped: "bottom",
barThickness: 15
},
{
label: "Finished",
data: labels.map(
(label) =>
dataSuccess.find(
({ label: labelInData }) => labelInData === label
)?.sum ?? 0
),
backgroundColor: "rgba(4, 198, 201, 1)",
borderColor: "rgba(255, 255, 255, 1)",
borderWidth: 2,
borderRadius: 5,
borderSkipped: "bottom",
barThickness: 15
},
{
label: "On hold",
data: labels.map(
(label) =>
dataOnHold.find(({ label: labelInData }) => labelInData === label)
?.sum ?? 0
),
backgroundColor: "rgba(211, 156, 247, 1)",
borderColor: "rgba(255, 255, 255, 1)",
borderWidth: 2,
borderRadius: 5,
borderSkipped: "bottom",
barThickness: 15
},
{
label: "Cancelled",
data: labels.map(
(label) =>
dataCanceled.find(
({ label: labelInData }) => labelInData === label
)?.sum ?? 0
),
backgroundColor: "rgba(168, 180, 189, 1)",
borderColor: "rgba(255, 255, 255, 1)",
borderWidth: 2,
borderRadius: 5,
borderSkipped: "bottom",
barThickness: 15
}
]
};
}, []);
return (
<div ref={chartContainerRef}>
<RCBar
options={{
...chartOptions,
plugins: {
...chartOptions.plugins,
datalabels: {
...chartOptions.plugins.datalabels,
formatter
}
}
}}
data={generateChartData()}
ref={canvasRef}
/>
</div>
);
});
export default Graph;
您需要更改 formatter
函数才能使其正常工作。
总值应仅出现在堆叠条形图的最高值上。然而,堆叠条不包含零值,也不包含来自隐藏 datasets
的值。我最终得到了以下可行的解决方案,但可能是 improved/simplified.
const formatter = (value, ctx) => {
const stackedValues = ctx.chart.data.datasets
.map((ds) => ds.data[ctx.dataIndex]);
const dsIdxLastVisibleNonZeroValue = stackedValues
.reduce((prev, curr, i) => !!curr && !ctx.chart.getDatasetMeta(i).hidden ? Math.max(prev, i) : prev, 0);
if (!!value && ctx.datasetIndex === dsIdxLastVisibleNonZeroValue) {
return stackedValues
.filter((ds, i) => !ctx.chart.getDatasetMeta(i).hidden)
.reduce((sum, v) => sum + v, 0);
} else {
return "";
}
};
请查看您修改后的 Code Sandbox,看看它是如何工作的。