lightweight-charts icon indicating copy to clipboard operation
lightweight-charts copied to clipboard

Chart isn't updated when primitive is detached using plugins-example

Open Rafael-Ramblas opened this issue 9 months ago • 3 comments

Lightweight Charts™ Version: 4.1.4

Importing the code from the band-indicator example and using in a React component there's an issue with detaching the primitive using a controlled state, as shown in the code below, the chart isn't updated after executing the function detachPrimitive.

The problem relies on the file plugin-base.ts that implements the method for detaching the primitive. The method doesn't call the requestUpdate function before destroying the instance data. If we add the line this.requestUpdate(); before this._requestUpdate = undefined; the feature works as expected.

const colors = {
  backgroundColor: "black",
  lineColor: "#2962FF",
  textColor: "white",
  areaTopColor: "#2962FF",
  areaBottomColor: "rgba(41, 98, 255, 0.28)",
};

const bandIndicator = new BandsIndicator();

const ChartComponent = ({
  data,
  showBands,
}: {
  data: LineData[];
  showBands: boolean;
}) => {
  const chartContainerRef = useRef<HTMLDivElement>(null);
  const lineSeries = useRef<ReturnType<IChartApi["addLineSeries"]>>(null);

  useEffect(() => {
    const { backgroundColor, textColor } = colors;
    const handleResize = () => {
      chart.applyOptions({ width: chartContainerRef.current.clientWidth });
    };

    const chart = createChart(chartContainerRef.current, {
      layout: {
        background: { type: ColorType.Solid, color: backgroundColor },
        textColor,
      },
      width: chartContainerRef.current.clientWidth,
      height: 300,
    });

    lineSeries.current = chart.addLineSeries();
    lineSeries.current.setData(data);

    chart.timeScale().fitContent();

    window.addEventListener("resize", handleResize);

    return () => {
      window.removeEventListener("resize", handleResize);
      chart.remove();
    };
  }, [data]);

  useEffect(() => {
    if (!lineSeries.current) return;
    if (showBands) {
      lineSeries.current.attachPrimitive(bandIndicator);
    } else {
      lineSeries.current.detachPrimitive(bandIndicator);
    }
  }, [showBands]);

  return <div ref={chartContainerRef} />;
};

const ChartWidget = (props: any) => {
  const [showBands, setShowBands] = React.useState(false);
  const sampleData = React.useMemo(() => generateLineData(), []);
  return (
    <>
      <ChartComponent data={sampleData} showBands={showBands} />
      <button onClick={() => setShowBands(!showBands)}>Toggle Bands</button>
    </>
  );
};

Actual behavior:

The chat isn't updated when the method detachPrimitive is executed.

Expected behavior:

The chart should update and remove the primitive draw.

CodeSandbox/JSFiddle/etc link:

https://codesandbox.io/p/sandbox/jolly-christian-lkmqnh

Rafael-Ramblas avatar May 12 '24 21:05 Rafael-Ramblas