From 148fe22cd7c72bd738831c02d6c4f0cdbb02075b Mon Sep 17 00:00:00 2001 From: Marko Djordjevic Date: Tue, 17 Feb 2026 19:44:37 +0100 Subject: [PATCH] fix: guard crosshair move handler against re-entrant recursion from applyOptions --- src/components/CandleChart.tsx | 61 +++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/src/components/CandleChart.tsx b/src/components/CandleChart.tsx index e01dbbd..383a5a3 100644 --- a/src/components/CandleChart.tsx +++ b/src/components/CandleChart.tsx @@ -976,7 +976,9 @@ const CandleChart = forwardRef( if (!drawingState && !dragState) return; if (drawingState && !previewPrimitiveRef.current) return; + let isUpdating = false; const handleCrosshairMove = (param: any) => { + if (isUpdating) return; if (!param.point) return; const time = chartRef.current!.timeScale().coordinateToTime(param.point.x); @@ -986,36 +988,41 @@ const CandleChart = forwardRef( const currentPoint = { time, price }; - // Update preview primitive endpoint during drawing - if (drawingState && previewPrimitiveRef.current) { - if (previewPrimitiveRef.current instanceof TrendLine) { - previewPrimitiveRef.current.updatePoints( - drawingState.firstPoint as Point, - currentPoint as Point - ); - } else if (previewPrimitiveRef.current instanceof RectangleDrawingPrimitive) { - previewPrimitiveRef.current.updatePoints( - drawingState.firstPoint as RectanglePoint, - currentPoint as RectanglePoint - ); - } - seriesRef.current!.applyOptions({}); - } - - // Update line endpoint during dragging - if (dragState) { - const linePrimitive = linePrimitivesRef.current.get(dragState.lineId); - if (linePrimitive) { - const p1 = linePrimitive.getP1(); - const p2 = linePrimitive.getP2(); - - if (dragState.endpoint === 'p1') { - linePrimitive.updatePoints(currentPoint as Point, p2); - } else { - linePrimitive.updatePoints(p1, currentPoint as Point); + isUpdating = true; + try { + // Update preview primitive endpoint during drawing + if (drawingState && previewPrimitiveRef.current) { + if (previewPrimitiveRef.current instanceof TrendLine) { + previewPrimitiveRef.current.updatePoints( + drawingState.firstPoint as Point, + currentPoint as Point + ); + } else if (previewPrimitiveRef.current instanceof RectangleDrawingPrimitive) { + previewPrimitiveRef.current.updatePoints( + drawingState.firstPoint as RectanglePoint, + currentPoint as RectanglePoint + ); } seriesRef.current!.applyOptions({}); } + + // Update line endpoint during dragging + if (dragState) { + const linePrimitive = linePrimitivesRef.current.get(dragState.lineId); + if (linePrimitive) { + const p1 = linePrimitive.getP1(); + const p2 = linePrimitive.getP2(); + + if (dragState.endpoint === 'p1') { + linePrimitive.updatePoints(currentPoint as Point, p2); + } else { + linePrimitive.updatePoints(p1, currentPoint as Point); + } + seriesRef.current!.applyOptions({}); + } + } + } finally { + isUpdating = false; } };