React Chart.js plugin renders stale data

31 views Asked by At

I am rendering a series of Doughtnut charts with center text rendered via plugin.

While initial render is working as expected, when I implement a client side search and hence re-render the series of doughnuts, the plugin pulls in irrelevant dataset and hence renders the wrong Center text.

Note: Doughnut still renders correctly after searching. It's the Center Text that is causing the issue.

What I tried: I changed the plugin methods (from beforeDatasetsDraw) to other plugin methods, hoping that the render lifecycle could be the issue. But no luck there.

Refer images for better clarity.

What am I missing ?

DoughNut:

<>
  {props.microservices &&
    Array.isArray(props.microservices) &&
    props.microservices.map((e) => (
      <>
        <p>{e?.serviceInfo?.name}</p>
        <DoughnutChart
          containerClassName="h-[75px] flex justify-center"
          data={{
            datasets: [
              {
                data: [Math.round(e.cpu), 100 - Math.round(e.cpu)],
                weight: 3,
                backgroundColor:
                  Math.round(e.cpu) === 0
                    ? ["transparent", "transparent"]
                    : ["#BB723F", "#21262D"],
                borderColor: "#232323",
                borderWidth: 0,
              },
              {
                weight: 3,
                data: [100],
                borderColor: "#232323",
                borderWidth: 0,
                backgroundColor:
                  Math.round(e.cpu) === 0 || Math.round(e.memory) === 0
                    ? ["transparent"]
                    : ["#29292A"],
              },
              {
                data: [Math.round(e.memory), 100 - Math.round(e.memory)],
                weight: 3,
                borderColor: "#232323",
                borderWidth: 0,
                backgroundColor:
                  Math.round(e.memory) === 0
                    ? ["transparent", "transparent"]
                    : ["#31737B", "transparent"],
              },
            ],
          }}
          options={{
            responsive: true,
            cutout: "80%",
            plugins: {
              tooltip: {
                enabled: false,
              },
              datalabels: {
                display: false,
              },
            },
          }}
          plugins={[
            centerText({
              text: e.serviceInfo?.name,
              fillColor:
                Math.round(e.cpu) === 0 || Math.round(e.memory) === 0
                  ? "#3E4249"
                  : "#0C1117",
              arcX: props.isPopUp ? 30 : 34,
              arcY: 38,
              arcRadius: props.isPopUp ? 24 : 27,
              arcStart: 0,
              arcEnd: 2 * Math.PI,
              activePods: e.serviceInfo?.activePods,
              totalPods: 16,
              isDisabledDoughNut:
                Math.round(e.cpu) === 0 || Math.round(e.memory) === 0,
            }),
          ]}
          isDisabledDoughNut={
            Math.round(e.cpu) === 0 || Math.round(e.memory) === 0
          }
          onClickHandler={(_) => {
            const {
              cpu,
              memory,
              traffic,
              errorRate,
              serviceInfo: { instance, activePods },
            } = e;
            props.setOverLayData({
              cpu,
              memory,
              traffic,
              errorRate,
              activePods,
              totalPods: 99,
              title: instance?.split("-").join(" "),
            });
            props.op.current?.toggle(_);
          }}
        />
      </>
    ))}
</>

Center Text Plugin:

const centerText = ({
  text = "HELLO WORLD",
  fillColor = "#F86E6E",
  textColor = "#fff",
  arcX = 220,
  arcY = 230,
  arcRadius = 200,
  arcStart = 0,
  arcEnd = 2 * Math.PI,
  isDisabledDoughNut = false,
  activePods = 0,
  totalPods = 0,
}) => ({
  id: "centerText",
  beforeDatasetsDraw(chart) {
    let warningIcon;
    if (isDisabledDoughNut) {
      warningIcon = new Image();
      warningIcon.src = `data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMS41ODIiIGhlaWdodD0iMTAiIHZpZXdCb3g9IjAgMCAxMS41ODIgMTAiPgogIDxwYXRoIGlkPSJ3YXJuaW5nX0ZJTEwxX3dnaHQzMDBfR1JBRDBfb3BzejI0IiBkPSJNNzQuNjE4LTgzMGw1Ljc5MS0xMEw4Ni4yLTgzMFptNS43OTEtMS41MzlhLjQ0Ni40NDYsMCwwLDAsLjMyOS0uMTMzLjQ0Ni40NDYsMCwwLDAsLjEzMy0uMzI5LjQ0Ny40NDcsMCwwLDAtLjEzMy0uMzI5LjQ0Ny40NDcsMCwwLDAtLjMyOS0uMTMzLjQ0Ny40NDcsMCwwLDAtLjMyOS4xMzMuNDQ3LjQ0NywwLDAsMC0uMTMzLjMyOS40NDYuNDQ2LDAsMCwwLC4xMzMuMzI5QS40NDYuNDQ2LDAsMCwwLDgwLjQwOS04MzEuNTM2Wm0tLjQyOS0xLjQ5NGguODU3di0yLjg1N2gtLjg1N1oiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC03NC42MTggODM5Ljk5NykiIGZpbGw9IiNmYmZiZmMiLz4KPC9zdmc+Cg==`;
    }
    const { ctx } = chart;
    ctx.save();
    const x = chart.getDatasetMeta(0).data[0].x;
    const y = chart.getDatasetMeta(0).data[0].y;

    ctx.beginPath();
    ctx.arc(arcX, arcY, arcRadius, arcStart, arcEnd);
    ctx.fillStyle = fillColor;
    ctx.fill();
    ctx.stroke();
    ctx.textAlign = "center";
    ctx.textBaseline = "middle";
    ctx.font = "12px Helvetica";
    ctx.fillStyle = textColor;
    ctx.fillText(text, x - 1, y - 5);

    if (!isDisabledDoughNut) {
      ctx.font = "8px Helvetica";
      ctx.fillText(`${activePods}/${totalPods}`, x, y + 10);
    }

    if (isDisabledDoughNut && warningIcon.complete) {
      ctx.drawImage(warningIcon, x - 5, y + 5, 10, 10);
    }
  },
});

on render the doughnut and center text are OK.

After searching the center text is wrong

1

There are 1 answers

0
Rajkumar Somasundaram On

For those arriving at this question in the future, adding the following to the chart component resolved my issue.

redraw={true}