如何在堆叠条的顶部显示 "total" 总和标签

How to show a "total" sum label on the top of stacked bars

我希望每个堆叠条的“总”标签位置正好在整个条的上方。

我已经设法得到总和,但我无法将标签定位在顶部。

如果您注意到,标签位于底部:

我试过使用 anchoroffset 属性,但无法达到预期的结果。

代码:

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,看看它是如何工作的。