@363045841yyt/klinechart-core 0.8.6 → 0.8.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config/chartSettings.d.ts +18 -2
- package/dist/config/chartSettings.d.ts.map +1 -1
- package/dist/config/chartSettings.js +8 -1
- package/dist/config/chartSettings.js.map +1 -1
- package/dist/controllers/createChartController.d.ts.map +1 -1
- package/dist/controllers/createChartController.js +56 -2
- package/dist/controllers/createChartController.js.map +1 -1
- package/dist/controllers/types.d.ts +36 -23
- package/dist/controllers/types.d.ts.map +1 -1
- package/dist/data-fetchers/baostock.d.ts +0 -3
- package/dist/data-fetchers/baostock.d.ts.map +1 -1
- package/dist/data-fetchers/baostock.js +0 -1
- package/dist/data-fetchers/baostock.js.map +1 -1
- package/dist/data-fetchers/dataBuffer.d.ts +13 -2
- package/dist/data-fetchers/dataBuffer.d.ts.map +1 -1
- package/dist/data-fetchers/dataBuffer.js +41 -7
- package/dist/data-fetchers/dataBuffer.js.map +1 -1
- package/dist/data-fetchers/dataBufferTypes.d.ts +11 -0
- package/dist/data-fetchers/dataBufferTypes.d.ts.map +1 -0
- package/dist/data-fetchers/dataBufferTypes.js +2 -0
- package/dist/data-fetchers/dataBufferTypes.js.map +1 -0
- package/dist/data-fetchers/fetcherDefinitionRegistry.d.ts +4 -3
- package/dist/data-fetchers/fetcherDefinitionRegistry.d.ts.map +1 -1
- package/dist/data-fetchers/fetcherDefinitionRegistry.js +9 -2
- package/dist/data-fetchers/fetcherDefinitionRegistry.js.map +1 -1
- package/dist/data-fetchers/gotdx/gotdx.d.ts +7 -0
- package/dist/data-fetchers/gotdx/gotdx.d.ts.map +1 -0
- package/dist/data-fetchers/gotdx/gotdx.js +7 -0
- package/dist/data-fetchers/gotdx/gotdx.js.map +1 -0
- package/dist/data-fetchers/gotdx.d.ts +0 -8
- package/dist/data-fetchers/gotdx.d.ts.map +1 -1
- package/dist/data-fetchers/gotdx.js +40 -3
- package/dist/data-fetchers/gotdx.js.map +1 -1
- package/dist/data-fetchers/hundred-mock.d.ts +0 -3
- package/dist/data-fetchers/hundred-mock.d.ts.map +1 -1
- package/dist/data-fetchers/hundred-mock.js +0 -1
- package/dist/data-fetchers/hundred-mock.js.map +1 -1
- package/dist/data-fetchers/index.d.ts +10 -8
- package/dist/data-fetchers/index.d.ts.map +1 -1
- package/dist/data-fetchers/index.js +8 -7
- package/dist/data-fetchers/index.js.map +1 -1
- package/dist/data-fetchers/router.d.ts +2 -0
- package/dist/data-fetchers/router.d.ts.map +1 -1
- package/dist/data-fetchers/router.js +8 -1
- package/dist/data-fetchers/router.js.map +1 -1
- package/dist/data-fetchers/thousand-mock.d.ts +0 -3
- package/dist/data-fetchers/thousand-mock.d.ts.map +1 -1
- package/dist/data-fetchers/thousand-mock.js +0 -1
- package/dist/data-fetchers/thousand-mock.js.map +1 -1
- package/dist/data-fetchers/timeShareBuffer.d.ts +27 -0
- package/dist/data-fetchers/timeShareBuffer.d.ts.map +1 -0
- package/dist/data-fetchers/timeShareBuffer.js +79 -0
- package/dist/data-fetchers/timeShareBuffer.js.map +1 -0
- package/dist/data-fetchers/tradingview.d.ts +0 -8
- package/dist/data-fetchers/tradingview.d.ts.map +1 -1
- package/dist/data-fetchers/tradingview.js +1 -2
- package/dist/data-fetchers/tradingview.js.map +1 -1
- package/dist/data-fetchers/types.d.ts +9 -1
- package/dist/data-fetchers/types.d.ts.map +1 -1
- package/dist/engine/chart.d.ts +32 -1
- package/dist/engine/chart.d.ts.map +1 -1
- package/dist/engine/chart.js +148 -7
- package/dist/engine/chart.js.map +1 -1
- package/dist/engine/chartTypes.d.ts +3 -0
- package/dist/engine/chartTypes.d.ts.map +1 -1
- package/dist/engine/controller/interaction.d.ts +6 -1
- package/dist/engine/controller/interaction.d.ts.map +1 -1
- package/dist/engine/controller/interaction.js +76 -28
- package/dist/engine/controller/interaction.js.map +1 -1
- package/dist/engine/data/chartDataManager.d.ts +39 -14
- package/dist/engine/data/chartDataManager.d.ts.map +1 -1
- package/dist/engine/data/chartDataManager.js +494 -202
- package/dist/engine/data/chartDataManager.js.map +1 -1
- package/dist/engine/draw/pixelAlign.d.ts +0 -27
- package/dist/engine/draw/pixelAlign.d.ts.map +1 -1
- package/dist/engine/draw/pixelAlign.js +1 -1
- package/dist/engine/draw/pixelAlign.js.map +1 -1
- package/dist/engine/indicators/calculators.d.ts +0 -104
- package/dist/engine/indicators/calculators.d.ts.map +1 -1
- package/dist/engine/indicators/calculators.js +57 -168
- package/dist/engine/indicators/calculators.js.map +1 -1
- package/dist/engine/indicators/chartIndicatorManager.d.ts.map +1 -1
- package/dist/engine/indicators/chartIndicatorManager.js +3 -2
- package/dist/engine/indicators/chartIndicatorManager.js.map +1 -1
- package/dist/engine/indicators/macdState.d.ts +0 -5
- package/dist/engine/indicators/macdState.d.ts.map +1 -1
- package/dist/engine/indicators/macdState.js +1 -1
- package/dist/engine/indicators/macdState.js.map +1 -1
- package/dist/engine/indicators/registerBuiltins.d.ts.map +1 -1
- package/dist/engine/indicators/registerBuiltins.js +1 -0
- package/dist/engine/indicators/registerBuiltins.js.map +1 -1
- package/dist/engine/indicators/rsiState.d.ts +0 -4
- package/dist/engine/indicators/rsiState.d.ts.map +1 -1
- package/dist/engine/indicators/rsiState.js +1 -1
- package/dist/engine/indicators/rsiState.js.map +1 -1
- package/dist/engine/indicators/scheduler.d.ts.map +1 -1
- package/dist/engine/indicators/scheduler.js +1 -7
- package/dist/engine/indicators/scheduler.js.map +1 -1
- package/dist/engine/layout/chartPaneLayout.d.ts +2 -0
- package/dist/engine/layout/chartPaneLayout.d.ts.map +1 -1
- package/dist/engine/layout/chartPaneLayout.js +24 -6
- package/dist/engine/layout/chartPaneLayout.js.map +1 -1
- package/dist/engine/modes/kLineMode.d.ts +37 -0
- package/dist/engine/modes/kLineMode.d.ts.map +1 -0
- package/dist/engine/modes/kLineMode.js +22 -0
- package/dist/engine/modes/kLineMode.js.map +1 -0
- package/dist/engine/modes/timeShareMode.d.ts +37 -0
- package/dist/engine/modes/timeShareMode.d.ts.map +1 -0
- package/dist/engine/modes/timeShareMode.js +59 -0
- package/dist/engine/modes/timeShareMode.js.map +1 -0
- package/dist/engine/modes/types.d.ts +47 -0
- package/dist/engine/modes/types.d.ts.map +1 -0
- package/dist/engine/modes/types.js +2 -0
- package/dist/engine/modes/types.js.map +1 -0
- package/dist/engine/paneRenderer.d.ts +4 -0
- package/dist/engine/paneRenderer.d.ts.map +1 -1
- package/dist/engine/paneRenderer.js +27 -40
- package/dist/engine/paneRenderer.js.map +1 -1
- package/dist/engine/render/chartRenderer.d.ts +4 -23
- package/dist/engine/render/chartRenderer.d.ts.map +1 -1
- package/dist/engine/render/chartRenderer.js +113 -18
- package/dist/engine/render/chartRenderer.js.map +1 -1
- package/dist/engine/renderers/Indicator/atr.d.ts +1 -18
- package/dist/engine/renderers/Indicator/atr.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/atr.js +3 -22
- package/dist/engine/renderers/Indicator/atr.js.map +1 -1
- package/dist/engine/renderers/Indicator/boll.d.ts +1 -4
- package/dist/engine/renderers/Indicator/boll.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/boll.js +3 -18
- package/dist/engine/renderers/Indicator/boll.js.map +1 -1
- package/dist/engine/renderers/Indicator/cci.d.ts +1 -22
- package/dist/engine/renderers/Indicator/cci.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/cci.js +8 -20
- package/dist/engine/renderers/Indicator/cci.js.map +1 -1
- package/dist/engine/renderers/Indicator/chaikinVol.d.ts +1 -7
- package/dist/engine/renderers/Indicator/chaikinVol.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/chaikinVol.js +3 -16
- package/dist/engine/renderers/Indicator/chaikinVol.js.map +1 -1
- package/dist/engine/renderers/Indicator/cmf.d.ts +1 -7
- package/dist/engine/renderers/Indicator/cmf.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/cmf.js +3 -15
- package/dist/engine/renderers/Indicator/cmf.js.map +1 -1
- package/dist/engine/renderers/Indicator/dema.d.ts +1 -7
- package/dist/engine/renderers/Indicator/dema.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/dema.js +3 -17
- package/dist/engine/renderers/Indicator/dema.js.map +1 -1
- package/dist/engine/renderers/Indicator/donchian.d.ts +1 -8
- package/dist/engine/renderers/Indicator/donchian.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/donchian.js +2 -2
- package/dist/engine/renderers/Indicator/donchian.js.map +1 -1
- package/dist/engine/renderers/Indicator/ene.d.ts +1 -12
- package/dist/engine/renderers/Indicator/ene.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/ene.js +3 -18
- package/dist/engine/renderers/Indicator/ene.js.map +1 -1
- package/dist/engine/renderers/Indicator/expma.d.ts +1 -4
- package/dist/engine/renderers/Indicator/expma.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/expma.js +2 -2
- package/dist/engine/renderers/Indicator/expma.js.map +1 -1
- package/dist/engine/renderers/Indicator/fastk.d.ts +1 -22
- package/dist/engine/renderers/Indicator/fastk.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/fastk.js +11 -64
- package/dist/engine/renderers/Indicator/fastk.js.map +1 -1
- package/dist/engine/renderers/Indicator/fib.d.ts +1 -6
- package/dist/engine/renderers/Indicator/fib.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/fib.js +2 -2
- package/dist/engine/renderers/Indicator/fib.js.map +1 -1
- package/dist/engine/renderers/Indicator/hma.d.ts +1 -7
- package/dist/engine/renderers/Indicator/hma.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/hma.js +3 -17
- package/dist/engine/renderers/Indicator/hma.js.map +1 -1
- package/dist/engine/renderers/Indicator/hv.d.ts +1 -7
- package/dist/engine/renderers/Indicator/hv.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/hv.js +3 -16
- package/dist/engine/renderers/Indicator/hv.js.map +1 -1
- package/dist/engine/renderers/Indicator/ichimoku.d.ts +1 -8
- package/dist/engine/renderers/Indicator/ichimoku.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/ichimoku.js +2 -2
- package/dist/engine/renderers/Indicator/ichimoku.js.map +1 -1
- package/dist/engine/renderers/Indicator/kama.d.ts +1 -7
- package/dist/engine/renderers/Indicator/kama.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/kama.js +3 -17
- package/dist/engine/renderers/Indicator/kama.js.map +1 -1
- package/dist/engine/renderers/Indicator/keltner.d.ts +1 -8
- package/dist/engine/renderers/Indicator/keltner.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/keltner.js +2 -2
- package/dist/engine/renderers/Indicator/keltner.js.map +1 -1
- package/dist/engine/renderers/Indicator/kst.d.ts +1 -22
- package/dist/engine/renderers/Indicator/kst.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/kst.js +2 -2
- package/dist/engine/renderers/Indicator/kst.js.map +1 -1
- package/dist/engine/renderers/Indicator/ma.d.ts +1 -4
- package/dist/engine/renderers/Indicator/ma.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/ma.js +1 -1
- package/dist/engine/renderers/Indicator/ma.js.map +1 -1
- package/dist/engine/renderers/Indicator/macd.d.ts +1 -49
- package/dist/engine/renderers/Indicator/macd.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/macd.js +2 -12
- package/dist/engine/renderers/Indicator/macd.js.map +1 -1
- package/dist/engine/renderers/Indicator/mainIndicatorLegend.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/mainIndicatorLegend.js +114 -1
- package/dist/engine/renderers/Indicator/mainIndicatorLegend.js.map +1 -1
- package/dist/engine/renderers/Indicator/mfi.d.ts +1 -7
- package/dist/engine/renderers/Indicator/mfi.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/mfi.js +3 -15
- package/dist/engine/renderers/Indicator/mfi.js.map +1 -1
- package/dist/engine/renderers/Indicator/mom.d.ts +1 -22
- package/dist/engine/renderers/Indicator/mom.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/mom.js +8 -23
- package/dist/engine/renderers/Indicator/mom.js.map +1 -1
- package/dist/engine/renderers/Indicator/obv.d.ts +1 -7
- package/dist/engine/renderers/Indicator/obv.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/obv.js +3 -14
- package/dist/engine/renderers/Indicator/obv.js.map +1 -1
- package/dist/engine/renderers/Indicator/parkinson.d.ts +1 -7
- package/dist/engine/renderers/Indicator/parkinson.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/parkinson.js +3 -16
- package/dist/engine/renderers/Indicator/parkinson.js.map +1 -1
- package/dist/engine/renderers/Indicator/pivot.d.ts +1 -6
- package/dist/engine/renderers/Indicator/pivot.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/pivot.js +2 -2
- package/dist/engine/renderers/Indicator/pivot.js.map +1 -1
- package/dist/engine/renderers/Indicator/pvt.d.ts +1 -7
- package/dist/engine/renderers/Indicator/pvt.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/pvt.js +3 -14
- package/dist/engine/renderers/Indicator/pvt.js.map +1 -1
- package/dist/engine/renderers/Indicator/roc.d.ts +1 -8
- package/dist/engine/renderers/Indicator/roc.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/roc.js +3 -15
- package/dist/engine/renderers/Indicator/roc.js.map +1 -1
- package/dist/engine/renderers/Indicator/rsi.d.ts +0 -32
- package/dist/engine/renderers/Indicator/rsi.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/rsi.js +3 -3
- package/dist/engine/renderers/Indicator/rsi.js.map +1 -1
- package/dist/engine/renderers/Indicator/sar.d.ts +1 -8
- package/dist/engine/renderers/Indicator/sar.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/sar.js +2 -2
- package/dist/engine/renderers/Indicator/sar.js.map +1 -1
- package/dist/engine/renderers/Indicator/scale/indicator_scale.d.ts +2 -0
- package/dist/engine/renderers/Indicator/scale/indicator_scale.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/scale/indicator_scale.js +10 -6
- package/dist/engine/renderers/Indicator/scale/indicator_scale.js.map +1 -1
- package/dist/engine/renderers/Indicator/shared/dashedLines.d.ts +4 -0
- package/dist/engine/renderers/Indicator/shared/dashedLines.d.ts.map +1 -0
- package/dist/engine/renderers/Indicator/shared/dashedLines.js +50 -0
- package/dist/engine/renderers/Indicator/shared/dashedLines.js.map +1 -0
- package/dist/engine/renderers/Indicator/shared/titleInfo.d.ts +14 -0
- package/dist/engine/renderers/Indicator/shared/titleInfo.d.ts.map +1 -0
- package/dist/engine/renderers/Indicator/shared/titleInfo.js +25 -0
- package/dist/engine/renderers/Indicator/shared/titleInfo.js.map +1 -0
- package/dist/engine/renderers/Indicator/shared/webglBand.d.ts +5 -0
- package/dist/engine/renderers/Indicator/shared/webglBand.d.ts.map +1 -0
- package/dist/engine/renderers/Indicator/shared/webglBand.js +17 -0
- package/dist/engine/renderers/Indicator/shared/webglBand.js.map +1 -0
- package/dist/engine/renderers/Indicator/stoch.d.ts +1 -22
- package/dist/engine/renderers/Indicator/stoch.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/stoch.js +5 -46
- package/dist/engine/renderers/Indicator/stoch.js.map +1 -1
- package/dist/engine/renderers/Indicator/structure.d.ts +1 -7
- package/dist/engine/renderers/Indicator/structure.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/structure.js +2 -2
- package/dist/engine/renderers/Indicator/structure.js.map +1 -1
- package/dist/engine/renderers/Indicator/supertrend.d.ts +1 -8
- package/dist/engine/renderers/Indicator/supertrend.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/supertrend.js +2 -2
- package/dist/engine/renderers/Indicator/supertrend.js.map +1 -1
- package/dist/engine/renderers/Indicator/tema.d.ts +1 -7
- package/dist/engine/renderers/Indicator/tema.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/tema.js +3 -17
- package/dist/engine/renderers/Indicator/tema.js.map +1 -1
- package/dist/engine/renderers/Indicator/trix.d.ts +1 -8
- package/dist/engine/renderers/Indicator/trix.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/trix.js +2 -2
- package/dist/engine/renderers/Indicator/trix.js.map +1 -1
- package/dist/engine/renderers/Indicator/vma.d.ts +1 -7
- package/dist/engine/renderers/Indicator/vma.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/vma.js +3 -15
- package/dist/engine/renderers/Indicator/vma.js.map +1 -1
- package/dist/engine/renderers/Indicator/volumeProfile.d.ts +1 -7
- package/dist/engine/renderers/Indicator/volumeProfile.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/volumeProfile.js +2 -2
- package/dist/engine/renderers/Indicator/volumeProfile.js.map +1 -1
- package/dist/engine/renderers/Indicator/vwap.d.ts +1 -7
- package/dist/engine/renderers/Indicator/vwap.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/vwap.js +3 -14
- package/dist/engine/renderers/Indicator/vwap.js.map +1 -1
- package/dist/engine/renderers/Indicator/wma.d.ts +1 -7
- package/dist/engine/renderers/Indicator/wma.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/wma.js +3 -17
- package/dist/engine/renderers/Indicator/wma.js.map +1 -1
- package/dist/engine/renderers/Indicator/wmsr.d.ts +1 -22
- package/dist/engine/renderers/Indicator/wmsr.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/wmsr.js +8 -23
- package/dist/engine/renderers/Indicator/wmsr.js.map +1 -1
- package/dist/engine/renderers/Indicator/zones.d.ts +1 -6
- package/dist/engine/renderers/Indicator/zones.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/zones.js +2 -2
- package/dist/engine/renderers/Indicator/zones.js.map +1 -1
- package/dist/engine/renderers/candle.d.ts +0 -16
- package/dist/engine/renderers/candle.d.ts.map +1 -1
- package/dist/engine/renderers/candle.js +1 -1
- package/dist/engine/renderers/candle.js.map +1 -1
- package/dist/engine/renderers/comparisonLine.d.ts.map +1 -1
- package/dist/engine/renderers/comparisonLine.js +2 -0
- package/dist/engine/renderers/comparisonLine.js.map +1 -1
- package/dist/engine/renderers/extremaMarkers.d.ts.map +1 -1
- package/dist/engine/renderers/extremaMarkers.js +2 -0
- package/dist/engine/renderers/extremaMarkers.js.map +1 -1
- package/dist/engine/renderers/gridLines.d.ts.map +1 -1
- package/dist/engine/renderers/gridLines.js +7 -35
- package/dist/engine/renderers/gridLines.js.map +1 -1
- package/dist/engine/renderers/lastPrice.d.ts.map +1 -1
- package/dist/engine/renderers/lastPrice.js +7 -2
- package/dist/engine/renderers/lastPrice.js.map +1 -1
- package/dist/engine/renderers/leftYAxis.d.ts +11 -0
- package/dist/engine/renderers/leftYAxis.d.ts.map +1 -0
- package/dist/engine/renderers/leftYAxis.js +79 -0
- package/dist/engine/renderers/leftYAxis.js.map +1 -0
- package/dist/engine/renderers/subVolume.d.ts +1 -13
- package/dist/engine/renderers/subVolume.d.ts.map +1 -1
- package/dist/engine/renderers/subVolume.js +1 -1
- package/dist/engine/renderers/subVolume.js.map +1 -1
- package/dist/engine/renderers/timeAxis.d.ts +0 -2
- package/dist/engine/renderers/timeAxis.d.ts.map +1 -1
- package/dist/engine/renderers/timeAxis.js +4 -1
- package/dist/engine/renderers/timeAxis.js.map +1 -1
- package/dist/engine/renderers/timeShare.d.ts +3 -0
- package/dist/engine/renderers/timeShare.d.ts.map +1 -0
- package/dist/engine/renderers/timeShare.js +260 -0
- package/dist/engine/renderers/timeShare.js.map +1 -0
- package/dist/engine/renderers/yAxis.d.ts.map +1 -1
- package/dist/engine/renderers/yAxis.js +25 -23
- package/dist/engine/renderers/yAxis.js.map +1 -1
- package/dist/engine/scale/price.d.ts +0 -7
- package/dist/engine/scale/price.d.ts.map +1 -1
- package/dist/engine/scale/price.js +3 -2
- package/dist/engine/scale/price.js.map +1 -1
- package/dist/engine/theme/fonts.d.ts +0 -2
- package/dist/engine/theme/fonts.d.ts.map +1 -1
- package/dist/engine/theme/fonts.js +1 -1
- package/dist/engine/theme/fonts.js.map +1 -1
- package/dist/engine/utils/klineConfig.d.ts.map +1 -1
- package/dist/engine/utils/klineConfig.js +1 -5
- package/dist/engine/utils/klineConfig.js.map +1 -1
- package/dist/engine/utils/tickPosition.d.ts +12 -0
- package/dist/engine/utils/tickPosition.d.ts.map +1 -1
- package/dist/engine/utils/tickPosition.js +15 -0
- package/dist/engine/utils/tickPosition.js.map +1 -1
- package/dist/engine/viewport/chartViewportManager.d.ts +0 -4
- package/dist/engine/viewport/chartViewportManager.d.ts.map +1 -1
- package/dist/engine/viewport/chartViewportManager.js +10 -13
- package/dist/engine/viewport/chartViewportManager.js.map +1 -1
- package/dist/plugin/types.d.ts +10 -0
- package/dist/plugin/types.d.ts.map +1 -1
- package/dist/plugin/types.js.map +1 -1
- package/dist/semantic/types.d.ts +1 -1
- package/dist/semantic/types.d.ts.map +1 -1
- package/dist/tokens/theme-base.d.ts +5 -0
- package/dist/tokens/theme-base.d.ts.map +1 -0
- package/dist/tokens/theme-base.js +31 -0
- package/dist/tokens/theme-base.js.map +1 -0
- package/dist/tokens/theme-china.d.ts.map +1 -1
- package/dist/tokens/theme-china.js +3 -0
- package/dist/tokens/theme-china.js.map +1 -1
- package/dist/tokens/theme-dark.d.ts.map +1 -1
- package/dist/tokens/theme-dark.js +11 -30
- package/dist/tokens/theme-dark.js.map +1 -1
- package/dist/tokens/theme-light.d.ts.map +1 -1
- package/dist/tokens/theme-light.js +11 -30
- package/dist/tokens/theme-light.js.map +1 -1
- package/dist/tokens/types.d.ts +7 -0
- package/dist/tokens/types.d.ts.map +1 -1
- package/dist/types/price.d.ts +8 -0
- package/dist/types/price.d.ts.map +1 -1
- package/dist/types/price.js +4 -0
- package/dist/types/price.js.map +1 -1
- package/dist/utils/dateFormat.d.ts +5 -42
- package/dist/utils/dateFormat.d.ts.map +1 -1
- package/dist/utils/dateFormat.js +24 -4
- package/dist/utils/dateFormat.js.map +1 -1
- package/dist/utils/kLineDraw/axis.d.ts +9 -28
- package/dist/utils/kLineDraw/axis.d.ts.map +1 -1
- package/dist/utils/kLineDraw/axis.js +33 -58
- package/dist/utils/kLineDraw/axis.js.map +1 -1
- package/dist/utils/volumePrice.d.ts +0 -40
- package/dist/utils/volumePrice.d.ts.map +1 -1
- package/dist/utils/volumePrice.js +2 -2
- package/dist/utils/volumePrice.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/src/config/chartSettings.ts +8 -1
- package/src/controllers/createChartController.ts +59 -2
- package/src/controllers/types.ts +38 -17
- package/src/data-fetchers/__tests__/dataBuffer.test.ts +39 -5
- package/src/data-fetchers/baostock.ts +1 -1
- package/src/data-fetchers/dataBuffer.ts +48 -11
- package/src/data-fetchers/dataBufferTypes.ts +11 -0
- package/src/data-fetchers/fetcherDefinitionRegistry.ts +14 -4
- package/src/data-fetchers/gotdx/gotdx.ts +6 -0
- package/src/data-fetchers/gotdx.ts +45 -7
- package/src/data-fetchers/hundred-mock.ts +1 -1
- package/src/data-fetchers/index.ts +10 -20
- package/src/data-fetchers/router.ts +12 -1
- package/src/data-fetchers/thousand-mock.ts +1 -1
- package/src/data-fetchers/timeShareBuffer.ts +92 -0
- package/src/data-fetchers/tradingview.ts +2 -2
- package/src/data-fetchers/types.ts +15 -2
- package/src/engine/__tests__/chart.dpr.test.ts +1 -0
- package/src/engine/chart.ts +167 -9
- package/src/engine/chartTypes.ts +3 -0
- package/src/engine/controller/__tests__/interaction.dpr.test.ts +2 -0
- package/src/engine/controller/interaction.ts +80 -28
- package/src/engine/data/chartDataManager.ts +560 -229
- package/src/engine/draw/pixelAlign.ts +1 -1
- package/src/engine/indicators/__tests__/_propertyAssertions.ts +2 -2
- package/src/engine/indicators/__tests__/registerBuiltins.test.ts +1 -1
- package/src/engine/indicators/calculators.ts +83 -233
- package/src/engine/indicators/chartIndicatorManager.ts +3 -2
- package/src/engine/indicators/macdState.ts +1 -1
- package/src/engine/indicators/registerBuiltins.ts +1 -0
- package/src/engine/indicators/rsiState.ts +1 -1
- package/src/engine/indicators/scheduler.ts +1 -7
- package/src/engine/layout/chartPaneLayout.ts +26 -6
- package/src/engine/modes/kLineMode.ts +57 -0
- package/src/engine/modes/timeShareMode.ts +95 -0
- package/src/engine/modes/types.ts +63 -0
- package/src/engine/paneRenderer.ts +37 -46
- package/src/engine/render/chartRenderer.ts +120 -22
- package/src/engine/renderers/Indicator/atr.ts +4 -29
- package/src/engine/renderers/Indicator/boll.ts +3 -24
- package/src/engine/renderers/Indicator/cci.ts +9 -27
- package/src/engine/renderers/Indicator/chaikinVol.ts +3 -23
- package/src/engine/renderers/Indicator/cmf.ts +3 -22
- package/src/engine/renderers/Indicator/dema.ts +5 -26
- package/src/engine/renderers/Indicator/donchian.ts +3 -3
- package/src/engine/renderers/Indicator/ene.ts +3 -24
- package/src/engine/renderers/Indicator/expma.ts +2 -2
- package/src/engine/renderers/Indicator/fastk.ts +12 -95
- package/src/engine/renderers/Indicator/fib.ts +2 -2
- package/src/engine/renderers/Indicator/hma.ts +5 -26
- package/src/engine/renderers/Indicator/hv.ts +3 -23
- package/src/engine/renderers/Indicator/ichimoku.ts +3 -3
- package/src/engine/renderers/Indicator/kama.ts +5 -26
- package/src/engine/renderers/Indicator/keltner.ts +3 -3
- package/src/engine/renderers/Indicator/kst.ts +3 -3
- package/src/engine/renderers/Indicator/ma.ts +1 -1
- package/src/engine/renderers/Indicator/macd.ts +4 -21
- package/src/engine/renderers/Indicator/mainIndicatorLegend.ts +127 -2
- package/src/engine/renderers/Indicator/mfi.ts +3 -22
- package/src/engine/renderers/Indicator/mom.ts +9 -30
- package/src/engine/renderers/Indicator/obv.ts +3 -21
- package/src/engine/renderers/Indicator/parkinson.ts +3 -23
- package/src/engine/renderers/Indicator/pivot.ts +2 -2
- package/src/engine/renderers/Indicator/pvt.ts +3 -21
- package/src/engine/renderers/Indicator/roc.ts +4 -23
- package/src/engine/renderers/Indicator/rsi.ts +4 -4
- package/src/engine/renderers/Indicator/sar.ts +3 -3
- package/src/engine/renderers/Indicator/scale/indicator_scale.ts +11 -4
- package/src/engine/renderers/Indicator/shared/dashedLines.ts +81 -0
- package/src/engine/renderers/Indicator/shared/titleInfo.ts +52 -0
- package/src/engine/renderers/Indicator/shared/webglBand.ts +23 -0
- package/src/engine/renderers/Indicator/stoch.ts +6 -71
- package/src/engine/renderers/Indicator/structure.ts +2 -2
- package/src/engine/renderers/Indicator/supertrend.ts +3 -3
- package/src/engine/renderers/Indicator/tema.ts +5 -26
- package/src/engine/renderers/Indicator/trix.ts +3 -3
- package/src/engine/renderers/Indicator/vma.ts +3 -22
- package/src/engine/renderers/Indicator/volumeProfile.ts +2 -2
- package/src/engine/renderers/Indicator/vwap.ts +3 -21
- package/src/engine/renderers/Indicator/wma.ts +5 -26
- package/src/engine/renderers/Indicator/wmsr.ts +9 -30
- package/src/engine/renderers/Indicator/zones.ts +2 -2
- package/src/engine/renderers/__tests__/yAxis.renderer.test.ts +30 -26
- package/src/engine/renderers/candle.ts +1 -1
- package/src/engine/renderers/comparisonLine.ts +1 -0
- package/src/engine/renderers/extremaMarkers.ts +1 -0
- package/src/engine/renderers/gridLines.ts +7 -36
- package/src/engine/renderers/lastPrice.ts +5 -2
- package/src/engine/renderers/leftYAxis.ts +93 -0
- package/src/engine/renderers/subVolume.ts +3 -3
- package/src/engine/renderers/timeAxis.ts +16 -13
- package/src/engine/renderers/timeShare.ts +271 -0
- package/src/engine/renderers/yAxis.ts +28 -24
- package/src/engine/scale/price.ts +2 -2
- package/src/engine/theme/fonts.ts +1 -1
- package/src/engine/utils/klineConfig.ts +1 -5
- package/src/engine/utils/tickPosition.ts +34 -0
- package/src/engine/viewport/chartViewportManager.ts +11 -15
- package/src/plugin/types.ts +11 -0
- package/src/semantic/types.ts +1 -1
- package/src/tokens/__tests__/__snapshots__/baseline.test.ts.snap +14 -0
- package/src/tokens/theme-base.ts +36 -0
- package/src/tokens/theme-china.ts +4 -0
- package/src/tokens/theme-dark.ts +12 -32
- package/src/tokens/theme-light.ts +13 -33
- package/src/tokens/types.ts +9 -0
- package/src/types/price.ts +13 -0
- package/src/utils/dateFormat.ts +27 -4
- package/src/utils/kLineDraw/axis.ts +40 -107
- package/src/utils/volumePrice.ts +2 -2
- package/src/version.ts +1 -1
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import type { KLineData } from '../../types/price'
|
|
2
|
-
import type { SymbolSpec, DataFetcher } from '../../controllers/types'
|
|
1
|
+
import type { KLineData, TimeShareData } from '../../types/price'
|
|
2
|
+
import type { SymbolSpec, DataFetcher, CustomDataSource } from '../../controllers/types'
|
|
3
3
|
import { createSignal, type Signal } from '../../reactivity/signal'
|
|
4
4
|
import { DataBuffer } from '../../data-fetchers/dataBuffer'
|
|
5
|
+
import { TimeShareBuffer } from '../../data-fetchers/timeShareBuffer'
|
|
6
|
+
import type { DataBufferLike } from '../../data-fetchers/dataBufferTypes'
|
|
7
|
+
import type { TimeShareFetcherFn } from '../../data-fetchers/types'
|
|
5
8
|
import type { ChartDom, Viewport } from '../chartTypes'
|
|
6
9
|
import type { VisibleRange, UpdateLevel } from '../layout/pane'
|
|
7
10
|
import { getVisibleRange } from '../viewport/viewport'
|
|
@@ -15,8 +18,7 @@ export interface DataDependencies {
|
|
|
15
18
|
getEffectiveDpr: () => number
|
|
16
19
|
getLogicalScrollLeft: () => number
|
|
17
20
|
getCachedScrollLeft: () => number
|
|
18
|
-
|
|
19
|
-
setPendingScrollLeft: (v: number) => void
|
|
21
|
+
setScrollLeft: (v: number) => void
|
|
20
22
|
getDom: () => ChartDom
|
|
21
23
|
getObservedSize: () => { width: number; height: number }
|
|
22
24
|
getViewport: () => Viewport | null
|
|
@@ -27,24 +29,40 @@ export interface DataDependencies {
|
|
|
27
29
|
}
|
|
28
30
|
setPendingIndicatorDataUpdate: (v: boolean) => void
|
|
29
31
|
isPointerDown: () => boolean
|
|
32
|
+
onTimeShareDataReady: (dataLength: number) => void
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const BUF_PRIMARY = 'main'
|
|
36
|
+
const BUF_COMPARISON = 'cmp'
|
|
37
|
+
const BUF_TIMESHARE = 'ts'
|
|
38
|
+
|
|
39
|
+
function bufKey(type: string, symbol: string, period?: string): string {
|
|
40
|
+
if (type === BUF_TIMESHARE) return `ts:${symbol}`
|
|
41
|
+
return `${type}:${symbol}:${period ?? 'daily'}`
|
|
30
42
|
}
|
|
31
43
|
|
|
32
44
|
export class ChartDataManager {
|
|
33
|
-
private _internalData: KLineData[] = []
|
|
34
45
|
private _dataFetcher: DataFetcher | null = null
|
|
35
|
-
private
|
|
36
|
-
|
|
46
|
+
private _timeShareFetcher: TimeShareFetcherFn | null = null
|
|
47
|
+
|
|
48
|
+
private _buffers = new Map<string, any>()
|
|
49
|
+
private _activeBufferKey: string | null = null
|
|
50
|
+
private _activeBufferUnsub: (() => void) | null = null
|
|
51
|
+
|
|
52
|
+
private _dataSignal = createSignal<ReadonlyArray<unknown>>([])
|
|
53
|
+
private _loadingSignal = createSignal<boolean>(false)
|
|
54
|
+
private _symbolsSignal = createSignal<ReadonlyArray<SymbolSpec>>([])
|
|
55
|
+
|
|
56
|
+
private _currentSpec: SymbolSpec | null = null
|
|
57
|
+
|
|
58
|
+
// Comparison-specific state (still needed for rendering pass-through)
|
|
37
59
|
private _comparisonSpecs: SymbolSpec[] = []
|
|
38
60
|
private _comparisonData: Map<string, KLineData[]> = new Map()
|
|
39
|
-
private _comparisonBuffers: Map<string, DataBuffer> = new Map()
|
|
40
|
-
private _comparisonBufferUnsubs: Map<string, () => void> = new Map()
|
|
41
61
|
private _comparisonColors: Map<string, string> = new Map()
|
|
42
62
|
private _comparisonColorsSignal = createSignal<ReadonlyMap<string, string>>(new Map())
|
|
43
|
-
private _comparisonLoadingUnsubs: Map<string, () => void> = new Map()
|
|
44
63
|
private _comparisonLoadingSignal = createSignal<boolean>(false)
|
|
45
|
-
|
|
46
|
-
private
|
|
47
|
-
private _symbolsSignal = createSignal<ReadonlyArray<SymbolSpec>>([])
|
|
64
|
+
// Track loading per-comparison buffer (keyed by buffer key)
|
|
65
|
+
private _cmpLoadingUnsubs = new Map<string, () => void>()
|
|
48
66
|
|
|
49
67
|
private _pendingFetches: Array<{
|
|
50
68
|
source: string
|
|
@@ -71,20 +89,170 @@ export class ChartDataManager {
|
|
|
71
89
|
this.deps = deps
|
|
72
90
|
}
|
|
73
91
|
|
|
92
|
+
// ── Buffer helpers ──
|
|
93
|
+
|
|
94
|
+
private activateBuffer(key: string): void {
|
|
95
|
+
if (this._activeBufferKey === key) return
|
|
96
|
+
this._activeBufferUnsub?.()
|
|
97
|
+
this._activeBufferKey = key
|
|
98
|
+
const buf = this._buffers.get(key) as DataBufferLike | undefined
|
|
99
|
+
if (buf) {
|
|
100
|
+
this._dataSignal.set([...buf.data.peek() as unknown[]])
|
|
101
|
+
this._loadingSignal.set(buf.loading.peek())
|
|
102
|
+
const unsubData = buf.data.subscribe(() => {
|
|
103
|
+
const prevDataLength = this._dataSignal.peek().length
|
|
104
|
+
this._dataSignal.set([...buf.data.peek() as unknown[]])
|
|
105
|
+
this.onBufferDataChanged(key, prevDataLength)
|
|
106
|
+
})
|
|
107
|
+
const unsubLoading = buf.loading.subscribe(() => {
|
|
108
|
+
this._loadingSignal.set(buf.loading.peek())
|
|
109
|
+
})
|
|
110
|
+
this._activeBufferUnsub = () => {
|
|
111
|
+
unsubData()
|
|
112
|
+
unsubLoading()
|
|
113
|
+
}
|
|
114
|
+
} else {
|
|
115
|
+
this._dataSignal.set([])
|
|
116
|
+
this._loadingSignal.set(false)
|
|
117
|
+
this._activeBufferUnsub = null
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
private disposeBuffer(key: string): void {
|
|
122
|
+
const buf = this._buffers.get(key)
|
|
123
|
+
if (!buf) return
|
|
124
|
+
const unsub = this._cmpLoadingUnsubs.get(key)
|
|
125
|
+
unsub?.()
|
|
126
|
+
const loadingUnsub = this._cmpLoadingUnsubs.get(`loading:${key}`)
|
|
127
|
+
loadingUnsub?.()
|
|
128
|
+
this._cmpLoadingUnsubs.delete(key)
|
|
129
|
+
this._cmpLoadingUnsubs.delete(`loading:${key}`)
|
|
130
|
+
buf.dispose()
|
|
131
|
+
this._buffers.delete(key)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
private getActiveDataBuffer(): DataBuffer | null {
|
|
135
|
+
const buf = this._activeBufferKey ? this._buffers.get(this._activeBufferKey) : null
|
|
136
|
+
return buf instanceof DataBuffer ? buf : null
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
private getActiveTimeShareBuffer(): TimeShareBuffer | null {
|
|
140
|
+
const buf = this._activeBufferKey ? this._buffers.get(this._activeBufferKey) : null
|
|
141
|
+
return buf instanceof TimeShareBuffer ? buf : null
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
private getPrimaryDataBuffer(symbol: string, period: string): DataBuffer {
|
|
145
|
+
const key = bufKey(BUF_PRIMARY, symbol, period)
|
|
146
|
+
let buf = this._buffers.get(key) as DataBuffer | undefined
|
|
147
|
+
if (!buf) {
|
|
148
|
+
buf = new DataBuffer()
|
|
149
|
+
buf.setFetcher(this._dataFetcher)
|
|
150
|
+
if (this._dataFetcher) {
|
|
151
|
+
buf.setRequestFetch(this._createBatchHandler(this._dataFetcher))
|
|
152
|
+
}
|
|
153
|
+
this._buffers.set(key, buf)
|
|
154
|
+
} else {
|
|
155
|
+
buf.setFetcher(this._dataFetcher)
|
|
156
|
+
if (this._dataFetcher) {
|
|
157
|
+
buf.setRequestFetch(this._createBatchHandler(this._dataFetcher))
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return buf
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// ── Buffer data change handler ──
|
|
164
|
+
|
|
165
|
+
private onBufferDataChanged(key: string, prevDataLength?: number): void {
|
|
166
|
+
const buf = this._buffers.get(key)
|
|
167
|
+
if (!buf) return
|
|
168
|
+
|
|
169
|
+
if (buf instanceof DataBuffer) {
|
|
170
|
+
this.onKLineBufferChanged(key, buf, prevDataLength)
|
|
171
|
+
} else if (buf instanceof TimeShareBuffer) {
|
|
172
|
+
this.onTimeShareBufferChanged(key, buf)
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
private onKLineBufferChanged(key: string, buf: DataBuffer, prevDataLength?: number): void {
|
|
177
|
+
if (!key.startsWith('main:')) return
|
|
178
|
+
|
|
179
|
+
const bufferData = buf.getRawData() as KLineData[]
|
|
180
|
+
const prependedCount = this.pendingPrependedCount
|
|
181
|
+
this.pendingPrependedCount = 0
|
|
182
|
+
|
|
183
|
+
if (prependedCount === 0 && this.deps.getCachedScrollLeft() < this.getLeftLoadBufferWidth()) {
|
|
184
|
+
this.deps.setScrollLeft(this.getLeftLoadBufferWidth())
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if ((prevDataLength ?? this._dataSignal.peek().length) === 0 && bufferData.length > 0) {
|
|
188
|
+
this.scrollToRight()
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
this.deps.resetInteraction()
|
|
192
|
+
|
|
193
|
+
if (this.lastVisibleRange.start === 0 && this.lastVisibleRange.end === 0 && bufferData.length > 0) {
|
|
194
|
+
const plotWidth = this.deps.getObservedSize().width > 0
|
|
195
|
+
? this.deps.getObservedSize().width
|
|
196
|
+
: Math.max(1, Math.round(this.deps.getDom().container?.clientWidth ?? 800))
|
|
197
|
+
const dpr = this.deps.getEffectiveDpr()
|
|
198
|
+
const opt = this.deps.getOption()
|
|
199
|
+
const { start, end } = getVisibleRange(
|
|
200
|
+
this.deps.getLogicalScrollLeft(),
|
|
201
|
+
plotWidth,
|
|
202
|
+
opt.kWidth,
|
|
203
|
+
opt.kGap,
|
|
204
|
+
bufferData.length,
|
|
205
|
+
dpr,
|
|
206
|
+
)
|
|
207
|
+
this.lastRawVisibleRange = { start, end }
|
|
208
|
+
this.lastVisibleRange = { start: Math.max(0, start), end }
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const scheduler = this.deps.getIndicatorScheduler()
|
|
212
|
+
const indicatorsReady = scheduler.update(bufferData, this.lastVisibleRange)
|
|
213
|
+
if (indicatorsReady) {
|
|
214
|
+
this.pendingIndicatorDataUpdate = false
|
|
215
|
+
this.deps.scheduleDraw()
|
|
216
|
+
} else {
|
|
217
|
+
this.pendingIndicatorDataUpdate = true
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
this.showIncrementalLoadHint(prependedCount)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
private onTimeShareBufferChanged(_key: string, _buf: TimeShareBuffer): void {
|
|
224
|
+
const data = this._dataSignal.peek() as TimeShareData[]
|
|
225
|
+
this.lastVisibleRange = { start: 0, end: data.length }
|
|
226
|
+
this.lastRawVisibleRange = { start: 0, end: data.length }
|
|
227
|
+
this.deps.resetInteraction()
|
|
228
|
+
this.deps.onTimeShareDataReady(data.length)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// ── Internal helpers ──
|
|
232
|
+
|
|
74
233
|
private getScrollContentHost(): HTMLDivElement | null {
|
|
75
234
|
return this.deps.getDom().scrollContent ?? this.deps.getDom().container ?? null
|
|
76
235
|
}
|
|
77
236
|
|
|
78
237
|
getLeftLoadBufferWidth(): number {
|
|
79
|
-
|
|
238
|
+
const buf = this.getActiveDataBuffer()
|
|
239
|
+
const dataLength = buf ? buf.getRawData().length : 0
|
|
240
|
+
if (dataLength === 0) return 0
|
|
80
241
|
const plotWidth = this.deps.getViewport()?.plotWidth
|
|
81
242
|
?? (this.deps.getObservedSize().width > 0 ? this.deps.getObservedSize().width : undefined)
|
|
82
243
|
?? Math.round(this.deps.getDom().container?.clientWidth ?? 0)
|
|
83
244
|
return Math.max(0, plotWidth)
|
|
84
245
|
}
|
|
85
246
|
|
|
247
|
+
private getActiveKLineLength(): number {
|
|
248
|
+
const buf = this.getActiveDataBuffer()
|
|
249
|
+
return buf ? buf.getRawData().length : 0
|
|
250
|
+
}
|
|
251
|
+
|
|
86
252
|
private computeRawVisibleRange(): VisibleRange | null {
|
|
87
|
-
|
|
253
|
+
const buf = this.getActiveDataBuffer()
|
|
254
|
+
const dataLength = buf ? buf.getRawData().length : 0
|
|
255
|
+
if (dataLength === 0) return null
|
|
88
256
|
const vp = this.deps.getViewport()
|
|
89
257
|
if (!vp) return null
|
|
90
258
|
const opt = this.deps.getOption()
|
|
@@ -93,7 +261,7 @@ export class ChartDataManager {
|
|
|
93
261
|
vp.plotWidth,
|
|
94
262
|
opt.kWidth,
|
|
95
263
|
opt.kGap,
|
|
96
|
-
|
|
264
|
+
dataLength,
|
|
97
265
|
vp.dpr,
|
|
98
266
|
)
|
|
99
267
|
}
|
|
@@ -102,8 +270,7 @@ export class ChartDataManager {
|
|
|
102
270
|
return 24
|
|
103
271
|
}
|
|
104
272
|
|
|
105
|
-
|
|
106
|
-
private static readonly TRAILING_DRAWING_SLOTS = 24
|
|
273
|
+
|
|
107
274
|
|
|
108
275
|
private clearIncrementalLoadHintTimer(): void {
|
|
109
276
|
if (this.incrementalLoadHintTimer !== null) {
|
|
@@ -130,7 +297,6 @@ export class ChartDataManager {
|
|
|
130
297
|
const hint = ownerDoc.createElement('div')
|
|
131
298
|
hint.className = 'klc-incremental-load-hint'
|
|
132
299
|
hint.style.position = 'absolute'
|
|
133
|
-
hint.style.left = '0'
|
|
134
300
|
hint.style.top = '0'
|
|
135
301
|
hint.style.height = '0px'
|
|
136
302
|
hint.style.width = '0px'
|
|
@@ -154,7 +320,8 @@ export class ChartDataManager {
|
|
|
154
320
|
const dpr = this.deps.getEffectiveDpr()
|
|
155
321
|
const opt = this.deps.getOption()
|
|
156
322
|
const { unitPx, startXPx } = getPhysicalKLineConfig(opt.kWidth, opt.kGap, dpr)
|
|
157
|
-
|
|
323
|
+
hint.style.left = `${this.getLeftLoadBufferWidth()}px`
|
|
324
|
+
const width = (startXPx + count * unitPx) / dpr
|
|
158
325
|
hint.style.width = `${Math.max(0, width)}px`
|
|
159
326
|
hint.style.height = `${Math.max(
|
|
160
327
|
0,
|
|
@@ -169,8 +336,16 @@ export class ChartDataManager {
|
|
|
169
336
|
}, 900)
|
|
170
337
|
}
|
|
171
338
|
|
|
339
|
+
// ── Public accessors ──
|
|
340
|
+
|
|
341
|
+
/** Unified data signal — always reflects the active buffer's data */
|
|
172
342
|
get data(): Signal<ReadonlyArray<KLineData>> {
|
|
173
|
-
return this._dataSignal
|
|
343
|
+
return this._dataSignal as Signal<ReadonlyArray<KLineData>>
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/** Loading signal — mirrors the active buffer's loading state */
|
|
347
|
+
get loading(): Signal<boolean> {
|
|
348
|
+
return this._loadingSignal
|
|
174
349
|
}
|
|
175
350
|
|
|
176
351
|
get symbols(): Signal<ReadonlyArray<SymbolSpec>> {
|
|
@@ -178,11 +353,36 @@ export class ChartDataManager {
|
|
|
178
353
|
}
|
|
179
354
|
|
|
180
355
|
get currentPeriod(): string {
|
|
181
|
-
return this.
|
|
356
|
+
return this._currentSpec?.period ?? 'daily'
|
|
182
357
|
}
|
|
183
358
|
|
|
359
|
+
/** Internal KLine data for indicator scheduler (empty in timeshare mode) */
|
|
184
360
|
getInternalData(): KLineData[] {
|
|
185
|
-
|
|
361
|
+
const buf = this.getActiveDataBuffer()
|
|
362
|
+
return buf ? buf.getRawData() : []
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
getRenderData(): unknown[] {
|
|
366
|
+
return [...this._dataSignal.peek()]
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
getTimeShareData(): TimeShareData[] {
|
|
370
|
+
const buf = this.getActiveTimeShareBuffer()
|
|
371
|
+
return buf ? buf.getRawData() : []
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
getTimeShareSignal(): Signal<ReadonlyArray<TimeShareData>> {
|
|
375
|
+
const buf = this.getActiveTimeShareBuffer()
|
|
376
|
+
return (buf?.data ?? createSignal<ReadonlyArray<TimeShareData>>([])) as Signal<ReadonlyArray<TimeShareData>>
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
getTimeShareLoadingSignal(): Signal<boolean> {
|
|
380
|
+
const buf = this.getActiveTimeShareBuffer()
|
|
381
|
+
return (buf?.loading ?? createSignal<boolean>(false)) as Signal<boolean>
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
setTimeShareFetcher(fetcher: TimeShareFetcherFn | null): void {
|
|
385
|
+
this._timeShareFetcher = fetcher
|
|
186
386
|
}
|
|
187
387
|
|
|
188
388
|
getComparisonData(): Map<string, KLineData[]> {
|
|
@@ -194,7 +394,16 @@ export class ChartDataManager {
|
|
|
194
394
|
}
|
|
195
395
|
|
|
196
396
|
get dataBuffer(): DataBuffer {
|
|
197
|
-
|
|
397
|
+
const buf = this.getActiveDataBuffer()
|
|
398
|
+
if (buf) return buf
|
|
399
|
+
// Fallback: create a primary buffer if none exists yet
|
|
400
|
+
const key = bufKey(BUF_PRIMARY, '', 'daily')
|
|
401
|
+
let fallback = this._buffers.get(key) as DataBuffer | undefined
|
|
402
|
+
if (!fallback) {
|
|
403
|
+
fallback = new DataBuffer()
|
|
404
|
+
this._buffers.set(key, fallback)
|
|
405
|
+
}
|
|
406
|
+
return fallback
|
|
198
407
|
}
|
|
199
408
|
|
|
200
409
|
get comparisonColors(): Signal<ReadonlyMap<string, string>> {
|
|
@@ -210,85 +419,65 @@ export class ChartDataManager {
|
|
|
210
419
|
}
|
|
211
420
|
|
|
212
421
|
private recomputeComparisonLoading(): void {
|
|
213
|
-
const anyLoading = Array.from(this.
|
|
422
|
+
const anyLoading = Array.from(this._buffers.entries()).some(
|
|
423
|
+
([k, b]) => k.startsWith(BUF_COMPARISON) && b instanceof DataBuffer && b.loading.peek(),
|
|
424
|
+
)
|
|
214
425
|
this._comparisonLoadingSignal.set(anyLoading)
|
|
215
426
|
}
|
|
216
427
|
|
|
217
|
-
|
|
218
|
-
this._internalData = data ?? []
|
|
219
|
-
this._dataSignal.set([...this._internalData])
|
|
220
|
-
|
|
221
|
-
const container = this.deps.getDom().container
|
|
222
|
-
if (container) {
|
|
223
|
-
const minScrollLeft = this.getLeftLoadBufferWidth()
|
|
224
|
-
if (this.deps.getCachedScrollLeft() < minScrollLeft) {
|
|
225
|
-
this.deps.setCachedScrollLeft(minScrollLeft)
|
|
226
|
-
this.deps.setPendingScrollLeft(minScrollLeft)
|
|
227
|
-
}
|
|
228
|
-
const contentWidth = this.getContentWidth()
|
|
229
|
-
const maxScrollLeft = Math.max(0, contentWidth - container.clientWidth)
|
|
230
|
-
if (this.deps.getCachedScrollLeft() > maxScrollLeft) {
|
|
231
|
-
this.deps.setCachedScrollLeft(maxScrollLeft)
|
|
232
|
-
this.deps.setPendingScrollLeft(maxScrollLeft)
|
|
233
|
-
}
|
|
234
|
-
}
|
|
428
|
+
// ── Data updates (KLine) ──
|
|
235
429
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
: Math.max(1, Math.round(this.deps.getDom().container?.clientWidth ?? 800))
|
|
242
|
-
const dpr = this.deps.getEffectiveDpr()
|
|
243
|
-
const opt = this.deps.getOption()
|
|
244
|
-
const { start, end } = getVisibleRange(
|
|
245
|
-
this.deps.getLogicalScrollLeft(),
|
|
246
|
-
plotWidth,
|
|
247
|
-
opt.kWidth,
|
|
248
|
-
opt.kGap,
|
|
249
|
-
this._internalData.length,
|
|
250
|
-
dpr,
|
|
251
|
-
)
|
|
252
|
-
this.lastRawVisibleRange = { start, end }
|
|
253
|
-
this.lastVisibleRange = { start: Math.max(0, start), end }
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
const scheduler = this.deps.getIndicatorScheduler()
|
|
257
|
-
const indicatorsReady = scheduler.update(this._internalData, this.lastVisibleRange)
|
|
258
|
-
if (indicatorsReady) {
|
|
259
|
-
this.pendingIndicatorDataUpdate = false
|
|
260
|
-
this.deps.scheduleDraw()
|
|
261
|
-
} else {
|
|
262
|
-
this.pendingIndicatorDataUpdate = true
|
|
430
|
+
updateData(data: KLineData[]): void {
|
|
431
|
+
if (this.currentPeriod === 'timeshare') return
|
|
432
|
+
const buf = this.getActiveDataBuffer()
|
|
433
|
+
if (buf) {
|
|
434
|
+
buf.setInlineData(data)
|
|
263
435
|
}
|
|
264
436
|
}
|
|
265
437
|
|
|
266
438
|
setData(data: KLineData[]): void {
|
|
267
|
-
this.
|
|
439
|
+
const buf = this.getActiveDataBuffer()
|
|
440
|
+
if (buf) {
|
|
441
|
+
buf.setInlineData(data)
|
|
442
|
+
} else {
|
|
443
|
+
this._dataSignal.set([...data])
|
|
444
|
+
}
|
|
268
445
|
}
|
|
269
446
|
|
|
270
447
|
appendData(newData: KLineData[]): void {
|
|
271
|
-
const
|
|
272
|
-
|
|
448
|
+
const buf = this.getActiveDataBuffer()
|
|
449
|
+
if (buf) {
|
|
450
|
+
const merged = [...buf.getRawData(), ...newData]
|
|
451
|
+
buf.setInlineData(merged)
|
|
452
|
+
} else {
|
|
453
|
+
this._dataSignal.set([...this._dataSignal.peek(), ...newData])
|
|
454
|
+
}
|
|
273
455
|
}
|
|
274
456
|
|
|
275
457
|
getData(): KLineData[] {
|
|
276
|
-
|
|
458
|
+
const buf = this.getActiveDataBuffer()
|
|
459
|
+
return buf ? buf.getRawData() : []
|
|
277
460
|
}
|
|
278
461
|
|
|
462
|
+
// ── Fetcher ──
|
|
463
|
+
|
|
279
464
|
setDataFetcher(fetcher: DataFetcher | null): void {
|
|
280
465
|
this._dataFetcher = fetcher
|
|
281
466
|
if (!fetcher) {
|
|
282
|
-
this.
|
|
283
|
-
|
|
284
|
-
|
|
467
|
+
for (const [key, buf] of this._buffers) {
|
|
468
|
+
if (buf instanceof DataBuffer) {
|
|
469
|
+
const dataBuf = buf as DataBuffer
|
|
470
|
+
dataBuf.setRequestFetch(null)
|
|
471
|
+
}
|
|
285
472
|
}
|
|
286
473
|
return
|
|
287
474
|
}
|
|
288
475
|
const handler = this._createBatchHandler(fetcher)
|
|
289
|
-
this.
|
|
290
|
-
|
|
291
|
-
|
|
476
|
+
for (const [key, buf] of this._buffers) {
|
|
477
|
+
if (buf instanceof DataBuffer) {
|
|
478
|
+
const dataBuf = buf as DataBuffer
|
|
479
|
+
dataBuf.setRequestFetch(handler)
|
|
480
|
+
}
|
|
292
481
|
}
|
|
293
482
|
}
|
|
294
483
|
|
|
@@ -339,8 +528,11 @@ export class ChartDataManager {
|
|
|
339
528
|
}
|
|
340
529
|
|
|
341
530
|
checkVisibleRangeGap(): void {
|
|
342
|
-
|
|
343
|
-
|
|
531
|
+
const buf = this.getActiveDataBuffer()
|
|
532
|
+
if (!buf) return
|
|
533
|
+
const data = buf.getRawData()
|
|
534
|
+
if (data.length === 0) return
|
|
535
|
+
const window = buf.loadedWindow
|
|
344
536
|
if (!window) return
|
|
345
537
|
const range = this.computeRawVisibleRange() ?? this.lastRawVisibleRange
|
|
346
538
|
|
|
@@ -349,73 +541,83 @@ export class ChartDataManager {
|
|
|
349
541
|
|
|
350
542
|
if (range.start < 0 && this._dataFetcher) {
|
|
351
543
|
const earlierThanEarliest = window.earliestTs - 365 * MS_PER_DAY
|
|
352
|
-
|
|
353
|
-
firstVisibleTs =
|
|
354
|
-
} else if (range.start <
|
|
355
|
-
firstVisibleTs =
|
|
544
|
+
buf.ensureRange(earlierThanEarliest, window.earliestTs)
|
|
545
|
+
firstVisibleTs = data[0]?.timestamp
|
|
546
|
+
} else if (range.start < data.length) {
|
|
547
|
+
firstVisibleTs = data[Math.max(0, range.start)]?.timestamp
|
|
356
548
|
if (firstVisibleTs !== undefined && firstVisibleTs < window.earliestTs) {
|
|
357
|
-
|
|
549
|
+
buf.ensureRange(firstVisibleTs, window.earliestTs)
|
|
358
550
|
}
|
|
359
551
|
}
|
|
360
552
|
|
|
361
553
|
if (firstVisibleTs === undefined) return
|
|
362
554
|
|
|
363
|
-
for (const
|
|
364
|
-
|
|
555
|
+
for (const [key, b] of this._buffers) {
|
|
556
|
+
if (key.startsWith(BUF_COMPARISON) && b instanceof DataBuffer) {
|
|
557
|
+
b.ensureRange(firstVisibleTs, window.earliestTs)
|
|
558
|
+
}
|
|
365
559
|
}
|
|
366
560
|
}
|
|
367
561
|
|
|
562
|
+
// ── Comparison management ──
|
|
563
|
+
|
|
368
564
|
private syncComparisonBuffers(specs: ReadonlyArray<SymbolSpec>): void {
|
|
369
565
|
this._comparisonSpecs = [...specs]
|
|
370
566
|
const nextKeys = new Set(specs.map((spec) => spec.symbol))
|
|
371
567
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
this.
|
|
378
|
-
this._comparisonData.delete(
|
|
568
|
+
// Remove buffers for removed comparisons
|
|
569
|
+
for (const [key, buf] of this._buffers) {
|
|
570
|
+
if (!key.startsWith(BUF_COMPARISON)) continue
|
|
571
|
+
const symbol = key.split(':')[1]!
|
|
572
|
+
if (nextKeys.has(symbol)) continue
|
|
573
|
+
this.disposeBuffer(key)
|
|
574
|
+
this._comparisonData.delete(symbol)
|
|
379
575
|
}
|
|
380
576
|
|
|
381
577
|
if (!this._dataFetcher) return
|
|
382
578
|
|
|
579
|
+
const primaryBuf = this.getActiveDataBuffer()
|
|
580
|
+
|
|
383
581
|
for (const spec of specs) {
|
|
384
|
-
const key = spec.symbol
|
|
385
|
-
|
|
386
|
-
|
|
582
|
+
const key = bufKey(BUF_COMPARISON, spec.symbol, spec.period)
|
|
583
|
+
const symbol = spec.symbol
|
|
584
|
+
let buf = this._buffers.get(key) as DataBuffer | undefined
|
|
585
|
+
if (!buf) {
|
|
387
586
|
const newBuffer = new DataBuffer()
|
|
388
587
|
newBuffer.setFetcher(this._dataFetcher)
|
|
389
588
|
if (this._dataFetcher) {
|
|
390
589
|
newBuffer.setRequestFetch(this._createBatchHandler(this._dataFetcher))
|
|
391
590
|
}
|
|
392
|
-
this.
|
|
591
|
+
this._buffers.set(key, newBuffer)
|
|
592
|
+
|
|
393
593
|
const unsubscribe = newBuffer.data.subscribe(() => {
|
|
394
|
-
this._comparisonData.set(
|
|
594
|
+
this._comparisonData.set(symbol, [...newBuffer.getRawData()])
|
|
395
595
|
this.deps.scheduleDraw()
|
|
396
596
|
})
|
|
397
|
-
this.
|
|
597
|
+
this._cmpLoadingUnsubs.set(key, unsubscribe)
|
|
598
|
+
|
|
398
599
|
const unsubLoading = newBuffer.loading.subscribe(() => this.recomputeComparisonLoading())
|
|
399
|
-
|
|
400
|
-
|
|
600
|
+
// Store loading unsubscribe with a special key
|
|
601
|
+
this._cmpLoadingUnsubs.set(`loading:${key}`, unsubLoading)
|
|
602
|
+
|
|
603
|
+
buf = newBuffer
|
|
401
604
|
} else {
|
|
402
|
-
|
|
605
|
+
buf.setFetcher(this._dataFetcher)
|
|
403
606
|
if (this._dataFetcher) {
|
|
404
|
-
|
|
607
|
+
buf.setRequestFetch(this._createBatchHandler(this._dataFetcher))
|
|
405
608
|
}
|
|
406
609
|
}
|
|
407
|
-
const mainEarliest =
|
|
408
|
-
|
|
610
|
+
const mainEarliest = primaryBuf?.loadedWindow?.earliestTs
|
|
611
|
+
buf.setSymbol(spec, mainEarliest)
|
|
409
612
|
}
|
|
410
613
|
}
|
|
411
614
|
|
|
412
615
|
private clearComparisonBuffers(): void {
|
|
413
|
-
for (const
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
this._comparisonBuffers.clear()
|
|
616
|
+
for (const [key, buf] of this._buffers) {
|
|
617
|
+
if (key.startsWith(BUF_COMPARISON)) {
|
|
618
|
+
this.disposeBuffer(key)
|
|
619
|
+
}
|
|
620
|
+
}
|
|
419
621
|
this._comparisonData.clear()
|
|
420
622
|
this._comparisonColors.clear()
|
|
421
623
|
this._comparisonColorsSignal.set(new Map())
|
|
@@ -424,12 +626,18 @@ export class ChartDataManager {
|
|
|
424
626
|
}
|
|
425
627
|
|
|
426
628
|
addComparisonSymbol(spec: SymbolSpec): void {
|
|
427
|
-
const
|
|
428
|
-
|
|
629
|
+
const symbol = spec.symbol
|
|
630
|
+
const key = bufKey(BUF_COMPARISON, symbol, spec.period)
|
|
631
|
+
|
|
632
|
+
// Check if already exists
|
|
633
|
+
for (const k of this._buffers.keys()) {
|
|
634
|
+
if (k.startsWith(BUF_COMPARISON) && k.split(':')[1] === symbol) return
|
|
635
|
+
}
|
|
636
|
+
|
|
429
637
|
this._comparisonSpecs.push(spec)
|
|
430
638
|
|
|
431
639
|
const color = COMPARISON_PALETTE[this._comparisonColors.size % COMPARISON_PALETTE.length] ?? DEFAULT_COMPARISON_COLOR
|
|
432
|
-
this._comparisonColors.set(
|
|
640
|
+
this._comparisonColors.set(symbol, color)
|
|
433
641
|
this._comparisonColorsSignal.set(new Map(this._comparisonColors))
|
|
434
642
|
|
|
435
643
|
if (!this._dataFetcher) return
|
|
@@ -439,157 +647,267 @@ export class ChartDataManager {
|
|
|
439
647
|
if (this._dataFetcher) {
|
|
440
648
|
newBuffer.setRequestFetch(this._createBatchHandler(this._dataFetcher))
|
|
441
649
|
}
|
|
442
|
-
this.
|
|
650
|
+
this._buffers.set(key, newBuffer)
|
|
443
651
|
const unsubscribe = newBuffer.data.subscribe(() => {
|
|
444
|
-
this._comparisonData.set(
|
|
652
|
+
this._comparisonData.set(symbol, [...newBuffer.getRawData()])
|
|
445
653
|
this.deps.scheduleDraw()
|
|
446
654
|
})
|
|
447
|
-
this.
|
|
655
|
+
this._cmpLoadingUnsubs.set(key, unsubscribe)
|
|
448
656
|
const unsubLoading = newBuffer.loading.subscribe(() => this.recomputeComparisonLoading())
|
|
449
|
-
this.
|
|
450
|
-
const
|
|
657
|
+
this._cmpLoadingUnsubs.set(`loading:${key}`, unsubLoading)
|
|
658
|
+
const primaryBuf = this.getActiveDataBuffer()
|
|
659
|
+
const mainEarliest = primaryBuf?.loadedWindow?.earliestTs
|
|
451
660
|
newBuffer.setSymbol(spec, mainEarliest)
|
|
452
661
|
this._symbolsSignal.set([this._symbolsSignal.peek()[0]!, ...this._comparisonSpecs])
|
|
453
662
|
}
|
|
454
663
|
|
|
664
|
+
setComparisonData(symbol: string, data: KLineData[]): void {
|
|
665
|
+
const period = this.currentPeriod
|
|
666
|
+
const key = bufKey(BUF_COMPARISON, symbol, period)
|
|
667
|
+
|
|
668
|
+
const existing = this._buffers.get(key) as DataBuffer | undefined
|
|
669
|
+
if (!existing) {
|
|
670
|
+
const buffer = new DataBuffer()
|
|
671
|
+
this._buffers.set(key, buffer)
|
|
672
|
+
|
|
673
|
+
const unsub = buffer.data.subscribe(() => {
|
|
674
|
+
this._comparisonData.set(symbol, [...buffer.getRawData()])
|
|
675
|
+
this.deps.scheduleDraw()
|
|
676
|
+
})
|
|
677
|
+
this._cmpLoadingUnsubs.set(key, unsub)
|
|
678
|
+
|
|
679
|
+
const unsubLoading = buffer.loading.subscribe(() => this.recomputeComparisonLoading())
|
|
680
|
+
this._cmpLoadingUnsubs.set(`loading:${key}`, unsubLoading)
|
|
681
|
+
|
|
682
|
+
const color =
|
|
683
|
+
COMPARISON_PALETTE[this._comparisonColors.size % COMPARISON_PALETTE.length] ??
|
|
684
|
+
DEFAULT_COMPARISON_COLOR
|
|
685
|
+
this._comparisonColors.set(symbol, color)
|
|
686
|
+
this._comparisonColorsSignal.set(new Map(this._comparisonColors))
|
|
687
|
+
|
|
688
|
+
const spec: SymbolSpec = { symbol, period }
|
|
689
|
+
this._comparisonSpecs.push(spec)
|
|
690
|
+
const mainSpec = this._symbolsSignal.peek()[0]
|
|
691
|
+
this._symbolsSignal.set(mainSpec ? [mainSpec, ...this._comparisonSpecs] : [...this._comparisonSpecs])
|
|
692
|
+
|
|
693
|
+
buffer.setInlineData(data)
|
|
694
|
+
return
|
|
695
|
+
}
|
|
696
|
+
existing.setInlineData(data)
|
|
697
|
+
}
|
|
698
|
+
|
|
455
699
|
removeComparisonSymbol(symbol: string): void {
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
this.
|
|
700
|
+
let found = false
|
|
701
|
+
for (const [key, buf] of this._buffers) {
|
|
702
|
+
if (key.startsWith(BUF_COMPARISON) && key.split(':')[1] === symbol) {
|
|
703
|
+
this.disposeBuffer(key)
|
|
704
|
+
found = true
|
|
705
|
+
break
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
if (!found) return
|
|
709
|
+
|
|
710
|
+
this._comparisonData.delete(symbol)
|
|
711
|
+
this._comparisonColors.delete(symbol)
|
|
467
712
|
this._comparisonColorsSignal.set(new Map(this._comparisonColors))
|
|
468
713
|
this._comparisonSpecs = this._comparisonSpecs.filter((s) => s.symbol !== symbol)
|
|
469
714
|
this._symbolsSignal.set([this._symbolsSignal.peek()[0]!, ...this._comparisonSpecs])
|
|
470
715
|
this.recomputeComparisonLoading()
|
|
716
|
+
this.deps.scheduleDraw()
|
|
471
717
|
}
|
|
472
718
|
|
|
719
|
+
// ── Symbol / Period ──
|
|
720
|
+
|
|
721
|
+
setCurrentSymbol(symbol: string): void {
|
|
722
|
+
const current = this._currentSpec ?? { symbol }
|
|
723
|
+
this._currentSpec = { ...current, symbol }
|
|
724
|
+
const specs = this._symbolsSignal.peek()
|
|
725
|
+
if (specs.length > 0) {
|
|
726
|
+
const updated = [{ ...specs[0], symbol }, ...specs.slice(1)] as SymbolSpec[]
|
|
727
|
+
this._symbolsSignal.set(updated)
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
setTimeShareQueryDate(date: number): void {
|
|
732
|
+
const buf = this.getActiveTimeShareBuffer()
|
|
733
|
+
if (buf) {
|
|
734
|
+
buf.setQueryDate(date)
|
|
735
|
+
} else {
|
|
736
|
+
// Store for later when buffer is created
|
|
737
|
+
const tsBuf = new TimeShareBuffer()
|
|
738
|
+
tsBuf.setFetcher(this._timeShareFetcher)
|
|
739
|
+
tsBuf.setQueryDate(date)
|
|
740
|
+
const spec = this._currentSpec
|
|
741
|
+
if (spec) {
|
|
742
|
+
const key = bufKey(BUF_TIMESHARE, spec.symbol)
|
|
743
|
+
this._buffers.set(key, tsBuf)
|
|
744
|
+
this.activateBuffer(key)
|
|
745
|
+
tsBuf.load(spec)
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
setCurrentPeriod(period: string): void {
|
|
751
|
+
const current = this._currentSpec
|
|
752
|
+
if (!current) {
|
|
753
|
+
this._currentSpec = { symbol: '', period }
|
|
754
|
+
return
|
|
755
|
+
}
|
|
756
|
+
const next = { ...current, period }
|
|
757
|
+
this.setSymbols([next, ...this._comparisonSpecs])
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
applyCustomData(source: CustomDataSource): void {
|
|
761
|
+
if (source.symbol) this.setCurrentSymbol(source.symbol)
|
|
762
|
+
if (source.period) this.setCurrentPeriod(source.period)
|
|
763
|
+
|
|
764
|
+
const specs = this._symbolsSignal.peek()
|
|
765
|
+
if (specs.length === 0 && source.symbol) {
|
|
766
|
+
const mainSpec: SymbolSpec = {
|
|
767
|
+
symbol: source.symbol,
|
|
768
|
+
period: source.period ?? 'daily',
|
|
769
|
+
}
|
|
770
|
+
this._symbolsSignal.set([mainSpec])
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
const plainData = source.data.map((d) => ({ ...d }))
|
|
774
|
+
this.setData(plainData)
|
|
775
|
+
if (source.comparisons) {
|
|
776
|
+
for (const key of this._comparisonData.keys()) {
|
|
777
|
+
if (!source.comparisons[key]) this.removeComparisonSymbol(key)
|
|
778
|
+
}
|
|
779
|
+
for (const [symbol, data] of Object.entries(source.comparisons)) {
|
|
780
|
+
this.setComparisonData(symbol, data.map((d) => ({ ...d })))
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
// ── Main symbol switching ──
|
|
786
|
+
|
|
473
787
|
setSymbols(specs: ReadonlyArray<SymbolSpec>): void {
|
|
474
788
|
this._symbolsSignal.set(specs)
|
|
789
|
+
|
|
475
790
|
if (specs.length === 0) {
|
|
791
|
+
this._currentSpec = null
|
|
792
|
+
this.disposeAllBuffers()
|
|
793
|
+
this._dataSignal.set([])
|
|
794
|
+
this.lastVisibleRange = { start: 0, end: 0 }
|
|
795
|
+
this.lastRawVisibleRange = { start: 0, end: 0 }
|
|
796
|
+
return
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
const primary = specs[0]!
|
|
800
|
+
this._currentSpec = primary
|
|
801
|
+
|
|
802
|
+
if (primary.period === 'timeshare') {
|
|
803
|
+
// Switch to timeshare mode
|
|
476
804
|
this.clearComparisonBuffers()
|
|
805
|
+
// Dispose primary KLine buffer
|
|
806
|
+
for (const [key, buf] of this._buffers) {
|
|
807
|
+
if (key.startsWith(BUF_PRIMARY)) {
|
|
808
|
+
this.disposeBuffer(key)
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
this._dataSignal.set([])
|
|
812
|
+
this.lastVisibleRange = { start: 0, end: 0 }
|
|
813
|
+
this.lastRawVisibleRange = { start: 0, end: 0 }
|
|
814
|
+
|
|
815
|
+
// Get or create timeshare buffer
|
|
816
|
+
const tsKey = bufKey(BUF_TIMESHARE, primary.symbol)
|
|
817
|
+
let tsBuf = this._buffers.get(tsKey) as TimeShareBuffer | undefined
|
|
818
|
+
if (!tsBuf) {
|
|
819
|
+
tsBuf = new TimeShareBuffer()
|
|
820
|
+
tsBuf.setFetcher(this._timeShareFetcher)
|
|
821
|
+
this._buffers.set(tsKey, tsBuf)
|
|
822
|
+
}
|
|
823
|
+
this.activateBuffer(tsKey)
|
|
824
|
+
tsBuf.load(primary)
|
|
477
825
|
return
|
|
478
826
|
}
|
|
827
|
+
|
|
828
|
+
// KLine mode
|
|
829
|
+
// Dispose timeshare buffer
|
|
830
|
+
for (const [key, buf] of this._buffers) {
|
|
831
|
+
if (key.startsWith(BUF_TIMESHARE)) {
|
|
832
|
+
this.disposeBuffer(key)
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
this.loadKLineSymbols(specs)
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
// ── KLine loading ──
|
|
840
|
+
|
|
841
|
+
private loadKLineSymbols(specs: ReadonlyArray<SymbolSpec>): void {
|
|
479
842
|
const spec = specs[0]!
|
|
480
843
|
this.syncComparisonBuffers(specs.slice(1))
|
|
481
844
|
if (!this._dataFetcher) return
|
|
482
845
|
|
|
483
|
-
this.
|
|
846
|
+
const buf = this.getPrimaryDataBuffer(spec.symbol, spec.period!)
|
|
847
|
+
this.activateBuffer(bufKey(BUF_PRIMARY, spec.symbol, spec.period!))
|
|
484
848
|
|
|
485
|
-
|
|
849
|
+
buf.onPrepend = (count: number) => {
|
|
486
850
|
this.pendingPrependedCount = count
|
|
487
851
|
const dpr = this.deps.getEffectiveDpr()
|
|
488
852
|
const opt = this.deps.getOption()
|
|
489
853
|
const { unitPx } = getPhysicalKLineConfig(opt.kWidth, opt.kGap, dpr)
|
|
490
854
|
const compensation = (count * unitPx) / dpr
|
|
491
|
-
const
|
|
492
|
-
|
|
493
|
-
container.scrollLeft += compensation
|
|
494
|
-
this.deps.setCachedScrollLeft(container.scrollLeft)
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
if (!this._dataBufferUnsub) {
|
|
499
|
-
this._dataBufferUnsub = this._dataBuffer.data.subscribe(() => {
|
|
500
|
-
const prevLength = this._internalData.length
|
|
501
|
-
const bufferData = this._dataBuffer.data.peek()
|
|
502
|
-
this._internalData = [...bufferData]
|
|
503
|
-
this._dataSignal.set([...this._internalData])
|
|
504
|
-
const prependedCount = this.pendingPrependedCount
|
|
505
|
-
this.pendingPrependedCount = 0
|
|
506
|
-
|
|
507
|
-
if (this.deps.getCachedScrollLeft() < this.getLeftLoadBufferWidth()) {
|
|
508
|
-
const desiredScrollLeft = this.getLeftLoadBufferWidth()
|
|
509
|
-
this.deps.setCachedScrollLeft(desiredScrollLeft)
|
|
510
|
-
this.deps.setPendingScrollLeft(desiredScrollLeft)
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
if (prevLength === 0 && this._internalData.length > 0) {
|
|
514
|
-
const dpr = this.deps.getEffectiveDpr()
|
|
515
|
-
const opt = this.deps.getOption()
|
|
516
|
-
const { unitPx, startXPx } = getPhysicalKLineConfig(opt.kWidth, opt.kGap, dpr)
|
|
517
|
-
const lastKLineEndPx = (startXPx + this._internalData.length * unitPx) / dpr
|
|
518
|
-
const container = this.deps.getDom().container
|
|
519
|
-
if (container) {
|
|
520
|
-
const target = this.getLeftLoadBufferWidth() + Math.max(0, lastKLineEndPx - container.clientWidth)
|
|
521
|
-
const contentWidth = this.getContentWidth()
|
|
522
|
-
const maxScroll = Math.max(0, contentWidth - container.clientWidth)
|
|
523
|
-
const scrollLeft = Math.round(Math.min(target, maxScroll) * dpr) / dpr
|
|
524
|
-
this.deps.setCachedScrollLeft(scrollLeft)
|
|
525
|
-
this.deps.setPendingScrollLeft(scrollLeft)
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
this.deps.resetInteraction()
|
|
530
|
-
|
|
531
|
-
if (this.lastVisibleRange.start === 0 && this.lastVisibleRange.end === 0 && this._internalData.length > 0) {
|
|
532
|
-
const plotWidth = this.deps.getObservedSize().width > 0
|
|
533
|
-
? this.deps.getObservedSize().width
|
|
534
|
-
: Math.max(1, Math.round(this.deps.getDom().container?.clientWidth ?? 800))
|
|
535
|
-
const dpr = this.deps.getEffectiveDpr()
|
|
536
|
-
const opt = this.deps.getOption()
|
|
537
|
-
const { start, end } = getVisibleRange(
|
|
538
|
-
this.deps.getLogicalScrollLeft(),
|
|
539
|
-
plotWidth,
|
|
540
|
-
opt.kWidth,
|
|
541
|
-
opt.kGap,
|
|
542
|
-
this._internalData.length,
|
|
543
|
-
dpr,
|
|
544
|
-
)
|
|
545
|
-
this.lastRawVisibleRange = { start, end }
|
|
546
|
-
this.lastVisibleRange = { start: Math.max(0, start), end }
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
const scheduler = this.deps.getIndicatorScheduler()
|
|
550
|
-
const indicatorsReady = scheduler.update(this._internalData, this.lastVisibleRange)
|
|
551
|
-
if (indicatorsReady) {
|
|
552
|
-
this.pendingIndicatorDataUpdate = false
|
|
553
|
-
this.deps.scheduleDraw()
|
|
554
|
-
} else {
|
|
555
|
-
this.pendingIndicatorDataUpdate = true
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
this.showIncrementalLoadHint(prependedCount)
|
|
559
|
-
})
|
|
855
|
+
const nextScrollLeft = this.deps.getCachedScrollLeft() + compensation
|
|
856
|
+
this.deps.setScrollLeft(nextScrollLeft)
|
|
560
857
|
}
|
|
561
858
|
|
|
562
|
-
|
|
859
|
+
buf.setSymbol(spec)
|
|
563
860
|
}
|
|
564
861
|
|
|
862
|
+
// ── Content width ──
|
|
863
|
+
|
|
565
864
|
getContentWidth(): number {
|
|
566
|
-
|
|
865
|
+
if (this.currentPeriod === 'timeshare') {
|
|
866
|
+
const tsData = this.getTimeShareData()
|
|
867
|
+
if (tsData.length === 0) return 0
|
|
868
|
+
const viewWidth = this.deps.getViewport()?.plotWidth ?? 0
|
|
869
|
+
return this.getLeftLoadBufferWidth() + Math.max(viewWidth, 1)
|
|
870
|
+
}
|
|
871
|
+
const buf = this.getActiveDataBuffer()
|
|
872
|
+
const dataLength = buf ? buf.getRawData().length : 0
|
|
567
873
|
if (dataLength === 0) return 0
|
|
568
874
|
const opt = this.deps.getOption()
|
|
569
875
|
const viewWidth = this.deps.getViewport()?.plotWidth ?? 0
|
|
570
876
|
const dpr = this.deps.getEffectiveDpr()
|
|
571
877
|
const { startXPx, unitPx } = getPhysicalKLineConfig(opt.kWidth, opt.kGap, dpr)
|
|
572
|
-
const dataPlotWidth = (startXPx +
|
|
878
|
+
const dataPlotWidth = (startXPx + dataLength * unitPx) / dpr
|
|
573
879
|
return this.getLeftLoadBufferWidth() + Math.max(dataPlotWidth, viewWidth)
|
|
574
880
|
}
|
|
575
881
|
|
|
576
882
|
scrollToRight(): void {
|
|
577
|
-
const
|
|
578
|
-
|
|
883
|
+
const buf = this.getActiveDataBuffer()
|
|
884
|
+
const dataLength = buf ? buf.getRawData().length : 0
|
|
885
|
+
if (dataLength === 0) return
|
|
579
886
|
const dpr = this.deps.getEffectiveDpr()
|
|
580
887
|
const opt = this.deps.getOption()
|
|
581
888
|
const { unitPx, startXPx } = getPhysicalKLineConfig(opt.kWidth, opt.kGap, dpr)
|
|
582
|
-
const lastKLineEndPx = (startXPx +
|
|
583
|
-
const
|
|
584
|
-
const
|
|
585
|
-
|
|
586
|
-
|
|
889
|
+
const lastKLineEndPx = (startXPx + dataLength * unitPx) / dpr
|
|
890
|
+
const viewport = this.deps.getViewport()
|
|
891
|
+
const clientWidth = viewport?.viewWidth
|
|
892
|
+
?? (this.deps.getObservedSize().width > 0 ? this.deps.getObservedSize().width : undefined)
|
|
893
|
+
?? Math.round(this.deps.getDom().container?.clientWidth ?? 0)
|
|
894
|
+
if (clientWidth <= 0) return
|
|
895
|
+
const target = this.getLeftLoadBufferWidth() + Math.max(0, lastKLineEndPx - clientWidth)
|
|
896
|
+
const contentWidth = this.getContentWidth()
|
|
897
|
+
const maxScroll = Math.max(0, contentWidth - clientWidth)
|
|
898
|
+
const scrollLeft = Math.round(Math.min(target, maxScroll) * dpr) / dpr
|
|
899
|
+
this.deps.setScrollLeft(scrollLeft)
|
|
900
|
+
this.deps.scheduleDraw()
|
|
587
901
|
}
|
|
588
902
|
|
|
903
|
+
// ── Comparison price range ──
|
|
904
|
+
|
|
589
905
|
getComparisonEquivalentPriceRange(range: VisibleRange): { min: number; max: number } | null {
|
|
590
906
|
if (this._comparisonSpecs.length === 0 || this._comparisonData.size === 0) return null
|
|
907
|
+
const buf = this.getActiveDataBuffer()
|
|
908
|
+
const internalData = buf ? buf.getRawData() : []
|
|
591
909
|
const baseIndex = Math.max(0, range.start)
|
|
592
|
-
const baseItem =
|
|
910
|
+
const baseItem = internalData[baseIndex]
|
|
593
911
|
if (!baseItem || !Number.isFinite(baseItem.close) || baseItem.close <= 0) return null
|
|
594
912
|
const mainBase = baseItem.close
|
|
595
913
|
const baseDate = baseItem.date ?? ''
|
|
@@ -612,8 +930,8 @@ export class ChartDataManager {
|
|
|
612
930
|
else byDate.set(String(item.timestamp), item)
|
|
613
931
|
}
|
|
614
932
|
|
|
615
|
-
for (let i = Math.max(0, range.start); i < range.end && i <
|
|
616
|
-
const mainItem =
|
|
933
|
+
for (let i = Math.max(0, range.start); i < range.end && i < internalData.length; i++) {
|
|
934
|
+
const mainItem = internalData[i]
|
|
617
935
|
if (!mainItem) continue
|
|
618
936
|
const key = mainItem.date ?? String(mainItem.timestamp)
|
|
619
937
|
const item = byDate.get(key)
|
|
@@ -631,18 +949,27 @@ export class ChartDataManager {
|
|
|
631
949
|
return { min, max }
|
|
632
950
|
}
|
|
633
951
|
|
|
952
|
+
// ── Index helpers ──
|
|
953
|
+
|
|
634
954
|
getLogicalSlotCount(): number {
|
|
635
|
-
|
|
955
|
+
const buf = this.getActiveDataBuffer()
|
|
956
|
+
const dataLength = buf ? buf.getRawData().length : 0
|
|
957
|
+
return dataLength + this.getTrailingSlotCount()
|
|
636
958
|
}
|
|
637
959
|
|
|
638
960
|
getTimestampAtLogicalIndex(index: number): number | null {
|
|
639
|
-
|
|
640
|
-
|
|
961
|
+
const buf = this.getActiveDataBuffer()
|
|
962
|
+
const data = buf ? buf.getRawData() : []
|
|
963
|
+
if (!Number.isInteger(index) || index < 0 || index >= data.length) return null
|
|
964
|
+
return data[index]?.timestamp ?? null
|
|
641
965
|
}
|
|
642
966
|
|
|
643
967
|
getLogicalIndexAtX(mouseX: number): number | null {
|
|
644
968
|
const vp = this.deps.getViewport()
|
|
645
|
-
if (!vp
|
|
969
|
+
if (!vp) return null
|
|
970
|
+
const buf = this.getActiveDataBuffer()
|
|
971
|
+
const data = buf ? buf.getRawData() : []
|
|
972
|
+
if (data.length === 0) return null
|
|
646
973
|
const dpr = this.deps.getEffectiveDpr()
|
|
647
974
|
const opt = this.deps.getOption()
|
|
648
975
|
const { startXPx, unitPx } = getPhysicalKLineConfig(opt.kWidth, opt.kGap, dpr)
|
|
@@ -654,21 +981,25 @@ export class ChartDataManager {
|
|
|
654
981
|
|
|
655
982
|
getDataIndexAtX(mouseX: number): number | null {
|
|
656
983
|
const index = this.getLogicalIndexAtX(mouseX)
|
|
657
|
-
|
|
984
|
+
const buf = this.getActiveDataBuffer()
|
|
985
|
+
const dataLength = buf ? buf.getRawData().length : 0
|
|
986
|
+
if (index === null || index >= dataLength) return null
|
|
658
987
|
return index
|
|
659
988
|
}
|
|
660
989
|
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
this.
|
|
664
|
-
this._dataBufferUnsub = null
|
|
990
|
+
private disposeAllBuffers(): void {
|
|
991
|
+
for (const key of this._buffers.keys()) {
|
|
992
|
+
this.disposeBuffer(key)
|
|
665
993
|
}
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
destroy(): void {
|
|
997
|
+
this._activeBufferUnsub?.()
|
|
998
|
+
this.disposeAllBuffers()
|
|
666
999
|
this.clearIncrementalLoadHintTimer()
|
|
667
1000
|
this.incrementalLoadHintEl?.remove()
|
|
668
1001
|
this.incrementalLoadHintEl = null
|
|
669
1002
|
this.pendingPrependedCount = 0
|
|
670
|
-
this._dataBuffer.dispose()
|
|
671
|
-
this.clearComparisonBuffers()
|
|
672
1003
|
}
|
|
673
1004
|
}
|
|
674
1005
|
|
|
@@ -692,4 +1023,4 @@ function batchFormatDate(ts: number): string {
|
|
|
692
1023
|
const m = String(d.getMonth() + 1).padStart(2, '0')
|
|
693
1024
|
const day = String(d.getDate()).padStart(2, '0')
|
|
694
1025
|
return `${y}-${m}-${day}`
|
|
695
|
-
}
|
|
1026
|
+
}
|