()
| 2067 | }; |
| 2068 | |
| 2069 | const flushPendingAppends = (): boolean => { |
| 2070 | if (pendingAppendByIndex.size === 0) return false; |
| 2071 | |
| 2072 | appendedGpuThisFrame.clear(); |
| 2073 | |
| 2074 | const zoomRangeBefore = zoomState?.getRange() ?? null; |
| 2075 | const isFullSpanZoomBefore = isFullSpanZoomRange(zoomRangeBefore); |
| 2076 | const canAutoScroll = |
| 2077 | currentOptions.autoScroll === true && |
| 2078 | zoomState != null && |
| 2079 | currentOptions.xAxis.min == null && |
| 2080 | currentOptions.xAxis.max == null; |
| 2081 | |
| 2082 | // Capture the pre-append visible domain so we can preserve it for “panned away” behavior. |
| 2083 | const prevBaseXDomain = computeBaseXDomain(currentOptions, runtimeRawBoundsByIndex); |
| 2084 | const prevVisibleXDomain = zoomRangeBefore ? computeVisibleXDomain(prevBaseXDomain, zoomRangeBefore) : null; |
| 2085 | |
| 2086 | let didAppendAny = false; |
| 2087 | |
| 2088 | for (const [seriesIndex, points] of pendingAppendByIndex) { |
| 2089 | if (points.length === 0) continue; |
| 2090 | const s = currentOptions.series[seriesIndex]; |
| 2091 | if (!s || s.type === 'pie') continue; |
| 2092 | didAppendAny = true; |
| 2093 | |
| 2094 | if (s.type === 'candlestick') { |
| 2095 | // Handle candlestick OHLC data. |
| 2096 | let raw = runtimeRawDataByIndex[seriesIndex] as OHLCDataPoint[] | null; |
| 2097 | if (!raw) { |
| 2098 | const seed = (s.rawData ?? s.data) as ReadonlyArray<OHLCDataPoint>; |
| 2099 | raw = seed.length === 0 ? [] : seed.slice(); |
| 2100 | runtimeRawDataByIndex[seriesIndex] = raw; |
| 2101 | runtimeRawBoundsByIndex[seriesIndex] = s.rawBounds ?? null; |
| 2102 | } |
| 2103 | |
| 2104 | const ohlcPoints = points as unknown as ReadonlyArray<OHLCDataPoint>; |
| 2105 | raw.push(...ohlcPoints); |
| 2106 | runtimeRawBoundsByIndex[seriesIndex] = extendBoundsWithOHLCDataPoints( |
| 2107 | runtimeRawBoundsByIndex[seriesIndex], |
| 2108 | ohlcPoints |
| 2109 | ); |
| 2110 | } else { |
| 2111 | // Handle other cartesian series (line, area, bar, scatter). |
| 2112 | let raw = runtimeRawDataByIndex[seriesIndex] as DataPoint[] | null; |
| 2113 | if (!raw) { |
| 2114 | const seed = (s.rawData ?? s.data) as ReadonlyArray<DataPoint>; |
| 2115 | raw = seed.length === 0 ? [] : seed.slice(); |
| 2116 | runtimeRawDataByIndex[seriesIndex] = raw; |
| 2117 | runtimeRawBoundsByIndex[seriesIndex] = s.rawBounds ?? computeRawBoundsFromData(raw); |
| 2118 | } |
| 2119 | |
| 2120 | const dataPoints = points as unknown as ReadonlyArray<DataPoint>; |
| 2121 | |
| 2122 | // Optional fast-path: if the GPU buffer currently represents the full, unsampled line series, |
| 2123 | // we can append just the new points to the existing GPU buffer (no full re-upload). |
| 2124 | if ( |
| 2125 | s.type === 'line' && |
| 2126 | s.sampling === 'none' && |
no test coverage detected