@363045841yyt/klinechart-core 0.9.0-alpha.0 → 0.9.0-alpha.2
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/controllers/createChartController.d.ts.map +1 -1
- package/dist/controllers/createChartController.js +31 -13
- package/dist/controllers/createChartController.js.map +1 -1
- package/dist/controllers/index.d.ts +1 -0
- package/dist/controllers/index.d.ts.map +1 -1
- package/dist/controllers/index.js.map +1 -1
- package/dist/controllers/types.d.ts +12 -0
- package/dist/controllers/types.d.ts.map +1 -1
- package/dist/engine/chart.d.ts +29 -11
- package/dist/engine/chart.d.ts.map +1 -1
- package/dist/engine/chart.js +147 -25
- package/dist/engine/chart.js.map +1 -1
- package/dist/engine/controller/interaction.d.ts +29 -4
- package/dist/engine/controller/interaction.d.ts.map +1 -1
- package/dist/engine/controller/interaction.js +78 -31
- package/dist/engine/controller/interaction.js.map +1 -1
- package/dist/engine/data/incrementalLoadHint.d.ts.map +1 -1
- package/dist/engine/data/incrementalLoadHint.js +5 -1
- package/dist/engine/data/incrementalLoadHint.js.map +1 -1
- package/dist/engine/drawing/DrawingState.d.ts +19 -34
- package/dist/engine/drawing/DrawingState.d.ts.map +1 -1
- package/dist/engine/drawing/DrawingState.js +110 -92
- package/dist/engine/drawing/DrawingState.js.map +1 -1
- package/dist/engine/drawing/index.d.ts +4 -1
- package/dist/engine/drawing/index.d.ts.map +1 -1
- package/dist/engine/drawing/index.js +9 -4
- package/dist/engine/drawing/index.js.map +1 -1
- package/dist/engine/drawing/interaction.d.ts +9 -29
- package/dist/engine/drawing/interaction.d.ts.map +1 -1
- package/dist/engine/drawing/interaction.js +23 -40
- package/dist/engine/drawing/interaction.js.map +1 -1
- package/dist/engine/indicators/chartIndicatorManager.d.ts.map +1 -1
- package/dist/engine/indicators/chartIndicatorManager.js +4 -12
- package/dist/engine/indicators/chartIndicatorManager.js.map +1 -1
- package/dist/engine/layout/chartPaneLayout.d.ts +0 -2
- package/dist/engine/layout/chartPaneLayout.d.ts.map +1 -1
- package/dist/engine/layout/chartPaneLayout.js +5 -9
- package/dist/engine/layout/chartPaneLayout.js.map +1 -1
- package/dist/engine/layout/pane.d.ts +0 -39
- package/dist/engine/layout/pane.d.ts.map +1 -1
- package/dist/engine/layout/pane.js +0 -9
- package/dist/engine/layout/pane.js.map +1 -1
- package/dist/engine/paneRenderer.d.ts +1 -10
- package/dist/engine/paneRenderer.d.ts.map +1 -1
- package/dist/engine/paneRenderer.js +2 -19
- package/dist/engine/paneRenderer.js.map +1 -1
- package/dist/engine/render/chartRenderer.d.ts +49 -8
- package/dist/engine/render/chartRenderer.d.ts.map +1 -1
- package/dist/engine/render/chartRenderer.js +143 -72
- package/dist/engine/render/chartRenderer.js.map +1 -1
- package/dist/engine/renderers/Indicator/atr.js +3 -13
- package/dist/engine/renderers/Indicator/atr.js.map +1 -1
- package/dist/engine/renderers/Indicator/boll.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/boll.js +12 -24
- package/dist/engine/renderers/Indicator/boll.js.map +1 -1
- package/dist/engine/renderers/Indicator/cci.js +6 -13
- package/dist/engine/renderers/Indicator/cci.js.map +1 -1
- package/dist/engine/renderers/Indicator/chaikinVol.js +3 -11
- package/dist/engine/renderers/Indicator/chaikinVol.js.map +1 -1
- package/dist/engine/renderers/Indicator/cmf.js +3 -11
- package/dist/engine/renderers/Indicator/cmf.js.map +1 -1
- package/dist/engine/renderers/Indicator/dema.js +3 -11
- package/dist/engine/renderers/Indicator/dema.js.map +1 -1
- package/dist/engine/renderers/Indicator/donchian.js +3 -11
- package/dist/engine/renderers/Indicator/donchian.js.map +1 -1
- package/dist/engine/renderers/Indicator/ene.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/ene.js +12 -24
- package/dist/engine/renderers/Indicator/ene.js.map +1 -1
- package/dist/engine/renderers/Indicator/expma.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/expma.js +5 -11
- package/dist/engine/renderers/Indicator/expma.js.map +1 -1
- package/dist/engine/renderers/Indicator/fastk.js +6 -13
- package/dist/engine/renderers/Indicator/fastk.js.map +1 -1
- package/dist/engine/renderers/Indicator/fib.js +3 -11
- package/dist/engine/renderers/Indicator/fib.js.map +1 -1
- package/dist/engine/renderers/Indicator/hma.js +3 -11
- package/dist/engine/renderers/Indicator/hma.js.map +1 -1
- package/dist/engine/renderers/Indicator/hv.js +3 -11
- package/dist/engine/renderers/Indicator/hv.js.map +1 -1
- package/dist/engine/renderers/Indicator/ichimoku.js +24 -18
- package/dist/engine/renderers/Indicator/ichimoku.js.map +1 -1
- package/dist/engine/renderers/Indicator/kama.js +3 -11
- package/dist/engine/renderers/Indicator/kama.js.map +1 -1
- package/dist/engine/renderers/Indicator/keltner.js +3 -11
- package/dist/engine/renderers/Indicator/keltner.js.map +1 -1
- package/dist/engine/renderers/Indicator/kst.js +9 -17
- package/dist/engine/renderers/Indicator/kst.js.map +1 -1
- package/dist/engine/renderers/Indicator/ma.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/ma.js +10 -21
- package/dist/engine/renderers/Indicator/ma.js.map +1 -1
- package/dist/engine/renderers/Indicator/macd.js +14 -44
- package/dist/engine/renderers/Indicator/macd.js.map +1 -1
- package/dist/engine/renderers/Indicator/mfi.js +3 -11
- package/dist/engine/renderers/Indicator/mfi.js.map +1 -1
- package/dist/engine/renderers/Indicator/mom.js +6 -13
- package/dist/engine/renderers/Indicator/mom.js.map +1 -1
- package/dist/engine/renderers/Indicator/obv.js +3 -11
- package/dist/engine/renderers/Indicator/obv.js.map +1 -1
- package/dist/engine/renderers/Indicator/parkinson.js +3 -11
- package/dist/engine/renderers/Indicator/parkinson.js.map +1 -1
- package/dist/engine/renderers/Indicator/pvt.js +3 -11
- package/dist/engine/renderers/Indicator/pvt.js.map +1 -1
- package/dist/engine/renderers/Indicator/roc.js +3 -11
- package/dist/engine/renderers/Indicator/roc.js.map +1 -1
- package/dist/engine/renderers/Indicator/rsi.js +12 -20
- package/dist/engine/renderers/Indicator/rsi.js.map +1 -1
- package/dist/engine/renderers/Indicator/shared/webglBand.d.ts +0 -2
- package/dist/engine/renderers/Indicator/shared/webglBand.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/shared/webglBand.js +0 -6
- package/dist/engine/renderers/Indicator/shared/webglBand.js.map +1 -1
- package/dist/engine/renderers/Indicator/stoch.js +9 -17
- package/dist/engine/renderers/Indicator/stoch.js.map +1 -1
- package/dist/engine/renderers/Indicator/tema.js +3 -11
- package/dist/engine/renderers/Indicator/tema.js.map +1 -1
- package/dist/engine/renderers/Indicator/trix.js +3 -11
- package/dist/engine/renderers/Indicator/trix.js.map +1 -1
- package/dist/engine/renderers/Indicator/vma.js +3 -11
- package/dist/engine/renderers/Indicator/vma.js.map +1 -1
- package/dist/engine/renderers/Indicator/vwap.js +3 -11
- package/dist/engine/renderers/Indicator/vwap.js.map +1 -1
- package/dist/engine/renderers/Indicator/wma.js +3 -11
- package/dist/engine/renderers/Indicator/wma.js.map +1 -1
- package/dist/engine/renderers/Indicator/wmsr.js +6 -13
- package/dist/engine/renderers/Indicator/wmsr.js.map +1 -1
- package/dist/engine/renderers/candle.d.ts.map +1 -1
- package/dist/engine/renderers/candle.js +21 -28
- package/dist/engine/renderers/candle.js.map +1 -1
- package/dist/engine/renderers/candleViaRenderer.d.ts +19 -0
- package/dist/engine/renderers/candleViaRenderer.d.ts.map +1 -0
- package/dist/engine/renderers/candleViaRenderer.js +15 -0
- package/dist/engine/renderers/candleViaRenderer.js.map +1 -0
- package/dist/engine/renderers/linesViaRenderer.d.ts +55 -0
- package/dist/engine/renderers/linesViaRenderer.d.ts.map +1 -0
- package/dist/engine/renderers/linesViaRenderer.js +169 -0
- package/dist/engine/renderers/linesViaRenderer.js.map +1 -0
- package/dist/engine/renderers/rectsViaRenderer.d.ts +18 -0
- package/dist/engine/renderers/rectsViaRenderer.d.ts.map +1 -0
- package/dist/engine/renderers/rectsViaRenderer.js +63 -0
- package/dist/engine/renderers/rectsViaRenderer.js.map +1 -0
- package/dist/engine/renderers/subVolume.js +7 -26
- package/dist/engine/renderers/subVolume.js.map +1 -1
- package/dist/engine/renderers/timeAxis.js +1 -1
- package/dist/engine/renderers/timeAxis.js.map +1 -1
- package/dist/engine/state/chartStateKernel.d.ts +11 -2
- package/dist/engine/state/chartStateKernel.d.ts.map +1 -1
- package/dist/engine/state/chartStateKernel.js +28 -12
- package/dist/engine/state/chartStateKernel.js.map +1 -1
- package/dist/engine/state/index.d.ts +1 -1
- package/dist/engine/state/index.d.ts.map +1 -1
- package/dist/engine/state/index.js +1 -1
- package/dist/engine/state/index.js.map +1 -1
- package/dist/engine/state/interactionState.d.ts +15 -7
- package/dist/engine/state/interactionState.d.ts.map +1 -1
- package/dist/engine/state/interactionState.js +55 -60
- package/dist/engine/state/interactionState.js.map +1 -1
- package/dist/engine/state/rendererState.d.ts +14 -0
- package/dist/engine/state/rendererState.d.ts.map +1 -0
- package/dist/engine/state/rendererState.js +25 -0
- package/dist/engine/state/rendererState.js.map +1 -0
- package/dist/engine/state/themeState.d.ts +11 -4
- package/dist/engine/state/themeState.d.ts.map +1 -1
- package/dist/engine/state/themeState.js +13 -5
- package/dist/engine/state/themeState.js.map +1 -1
- package/dist/engine/state/viewportState.d.ts.map +1 -1
- package/dist/engine/state/viewportState.js +7 -3
- package/dist/engine/state/viewportState.js.map +1 -1
- package/dist/engine/subPaneManager.d.ts.map +1 -1
- package/dist/engine/subPaneManager.js +2 -10
- package/dist/engine/subPaneManager.js.map +1 -1
- package/dist/foundation/config/chartSettings.d.ts +16 -4
- package/dist/foundation/config/chartSettings.d.ts.map +1 -1
- package/dist/foundation/config/chartSettings.js +21 -6
- package/dist/foundation/config/chartSettings.js.map +1 -1
- package/dist/foundation/plugin/index.d.ts +0 -1
- package/dist/foundation/plugin/index.d.ts.map +1 -1
- package/dist/foundation/plugin/rendererPluginManager.d.ts +1 -22
- package/dist/foundation/plugin/rendererPluginManager.d.ts.map +1 -1
- package/dist/foundation/plugin/rendererPluginManager.js +0 -84
- package/dist/foundation/plugin/rendererPluginManager.js.map +1 -1
- package/dist/foundation/plugin/types.d.ts +11 -17
- package/dist/foundation/plugin/types.d.ts.map +1 -1
- package/dist/foundation/plugin/types.js.map +1 -1
- package/dist/foundation/reactivity/frameTransaction.d.ts +71 -0
- package/dist/foundation/reactivity/frameTransaction.d.ts.map +1 -0
- package/dist/foundation/reactivity/frameTransaction.js +170 -0
- package/dist/foundation/reactivity/frameTransaction.js.map +1 -0
- package/dist/foundation/reactivity/index.d.ts +4 -2
- package/dist/foundation/reactivity/index.d.ts.map +1 -1
- package/dist/foundation/reactivity/index.js +2 -1
- package/dist/foundation/reactivity/index.js.map +1 -1
- package/dist/foundation/reactivity/signal.d.ts +20 -0
- package/dist/foundation/reactivity/signal.d.ts.map +1 -1
- package/dist/foundation/reactivity/signal.js +27 -0
- package/dist/foundation/reactivity/signal.js.map +1 -1
- package/dist/foundation/tokens/theme-dark.d.ts.map +1 -1
- package/dist/foundation/tokens/theme-dark.js +2 -1
- package/dist/foundation/tokens/theme-dark.js.map +1 -1
- package/dist/foundation/tokens/theme-light.d.ts.map +1 -1
- package/dist/foundation/tokens/theme-light.js +2 -1
- package/dist/foundation/tokens/theme-light.js.map +1 -1
- package/dist/rendering/render/Renderer.d.ts +29 -14
- package/dist/rendering/render/Renderer.d.ts.map +1 -1
- package/dist/rendering/render/Renderer.js +3 -10
- package/dist/rendering/render/Renderer.js.map +1 -1
- package/dist/rendering/render/SurfaceBackend.d.ts +5 -7
- package/dist/rendering/render/SurfaceBackend.d.ts.map +1 -1
- package/dist/rendering/render/SurfaceBackend.js +5 -7
- package/dist/rendering/render/SurfaceBackend.js.map +1 -1
- package/dist/rendering/render/createCanvas2DRenderer.d.ts +3 -0
- package/dist/rendering/render/createCanvas2DRenderer.d.ts.map +1 -0
- package/dist/rendering/render/createCanvas2DRenderer.js +74 -0
- package/dist/rendering/render/createCanvas2DRenderer.js.map +1 -0
- package/dist/rendering/render/createDefaultRendererHost.d.ts +4 -0
- package/dist/rendering/render/createDefaultRendererHost.d.ts.map +1 -0
- package/dist/rendering/render/createDefaultRendererHost.js +54 -0
- package/dist/rendering/render/createDefaultRendererHost.js.map +1 -0
- package/dist/rendering/render/createWebGLRenderer.d.ts.map +1 -1
- package/dist/rendering/render/createWebGLRenderer.js +42 -80
- package/dist/rendering/render/createWebGLRenderer.js.map +1 -1
- package/dist/rendering/render/createWebGPURenderer.d.ts +11 -0
- package/dist/rendering/render/createWebGPURenderer.d.ts.map +1 -0
- package/dist/rendering/render/createWebGPURenderer.js +619 -0
- package/dist/rendering/render/createWebGPURenderer.js.map +1 -0
- package/dist/rendering/render/createWebGPUSurfaceBackend.d.ts +15 -0
- package/dist/rendering/render/createWebGPUSurfaceBackend.d.ts.map +1 -0
- package/dist/rendering/render/createWebGPUSurfaceBackend.js +92 -0
- package/dist/rendering/render/createWebGPUSurfaceBackend.js.map +1 -0
- package/dist/rendering/render/frameMetrics.d.ts +19 -0
- package/dist/rendering/render/frameMetrics.d.ts.map +1 -0
- package/dist/rendering/render/frameMetrics.js +43 -0
- package/dist/rendering/render/frameMetrics.js.map +1 -0
- package/dist/rendering/render/index.d.ts +10 -0
- package/dist/rendering/render/index.d.ts.map +1 -1
- package/dist/rendering/render/index.js +6 -0
- package/dist/rendering/render/index.js.map +1 -1
- package/dist/rendering/render/rendererHost.d.ts +34 -0
- package/dist/rendering/render/rendererHost.d.ts.map +1 -0
- package/dist/rendering/render/rendererHost.js +144 -0
- package/dist/rendering/render/rendererHost.js.map +1 -0
- package/dist/rendering/render/webgpuResourceTable.d.ts +25 -0
- package/dist/rendering/render/webgpuResourceTable.d.ts.map +1 -0
- package/dist/rendering/render/webgpuResourceTable.js +54 -0
- package/dist/rendering/render/webgpuResourceTable.js.map +1 -0
- package/dist/rendering/scene/createLayerFromPlugin.d.ts.map +1 -1
- package/dist/rendering/scene/createLayerFromPlugin.js +10 -2
- package/dist/rendering/scene/createLayerFromPlugin.js.map +1 -1
- package/dist/rendering/scene/layerRegistry.d.ts +3 -5
- package/dist/rendering/scene/layerRegistry.d.ts.map +1 -1
- package/dist/rendering/scene/layerRegistry.js +1 -1
- package/dist/rendering/scene/layerRegistry.js.map +1 -1
- package/dist/rendering/scene/retainedScene.d.ts +60 -0
- package/dist/rendering/scene/retainedScene.d.ts.map +1 -0
- package/dist/rendering/scene/retainedScene.js +42 -0
- package/dist/rendering/scene/retainedScene.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -1
- package/src/__tests__/signal.test.ts +47 -1
- package/src/controllers/__tests__/createChartController.theme.test.ts +102 -0
- package/src/controllers/createChartController.ts +36 -12
- package/src/controllers/index.ts +5 -0
- package/src/controllers/types.ts +14 -0
- package/src/engine/__tests__/chart.dpr.test.ts +64 -0
- package/src/engine/__tests__/paneRenderer.resize.test.ts +0 -7
- package/src/engine/__tests__/renderSinglePath.test.ts +121 -0
- package/src/engine/chart.ts +172 -25
- package/src/engine/controller/__tests__/interaction.dpr.test.ts +45 -41
- package/src/engine/controller/interaction.ts +81 -30
- package/src/engine/data/__tests__/chartDataManager.incrementalLoad.test.ts +1 -0
- package/src/engine/data/incrementalLoadHint.ts +6 -1
- package/src/engine/drawing/DrawingState.ts +107 -89
- package/src/engine/drawing/__tests__/drawingState.workCopy.test.ts +95 -36
- package/src/engine/drawing/__tests__/drawingStore.projection.test.ts +22 -0
- package/src/engine/drawing/index.ts +12 -4
- package/src/engine/drawing/interaction.ts +25 -40
- package/src/engine/indicators/chartIndicatorManager.ts +6 -16
- package/src/engine/layout/chartPaneLayout.ts +6 -11
- package/src/engine/layout/pane.ts +0 -44
- package/src/engine/paneRenderer.ts +3 -34
- package/src/engine/render/chartRenderer.ts +181 -81
- package/src/engine/renderers/Indicator/atr.ts +5 -17
- package/src/engine/renderers/Indicator/boll.ts +15 -26
- package/src/engine/renderers/Indicator/cci.ts +7 -17
- package/src/engine/renderers/Indicator/chaikinVol.ts +3 -15
- package/src/engine/renderers/Indicator/cmf.ts +3 -15
- package/src/engine/renderers/Indicator/dema.ts +3 -15
- package/src/engine/renderers/Indicator/donchian.ts +3 -12
- package/src/engine/renderers/Indicator/ene.ts +15 -25
- package/src/engine/renderers/Indicator/expma.ts +4 -13
- package/src/engine/renderers/Indicator/fastk.ts +7 -17
- package/src/engine/renderers/Indicator/fib.ts +3 -12
- package/src/engine/renderers/Indicator/hma.ts +3 -15
- package/src/engine/renderers/Indicator/hv.ts +3 -15
- package/src/engine/renderers/Indicator/ichimoku.ts +21 -24
- package/src/engine/renderers/Indicator/kama.ts +3 -15
- package/src/engine/renderers/Indicator/keltner.ts +3 -12
- package/src/engine/renderers/Indicator/kst.ts +9 -20
- package/src/engine/renderers/Indicator/ma.ts +9 -21
- package/src/engine/renderers/Indicator/macd.ts +27 -102
- package/src/engine/renderers/Indicator/mfi.ts +3 -15
- package/src/engine/renderers/Indicator/mom.ts +7 -17
- package/src/engine/renderers/Indicator/obv.ts +3 -15
- package/src/engine/renderers/Indicator/parkinson.ts +3 -15
- package/src/engine/renderers/Indicator/pvt.ts +3 -15
- package/src/engine/renderers/Indicator/roc.ts +3 -15
- package/src/engine/renderers/Indicator/rsi.ts +12 -23
- package/src/engine/renderers/Indicator/shared/webglBand.ts +0 -13
- package/src/engine/renderers/Indicator/stoch.ts +9 -20
- package/src/engine/renderers/Indicator/tema.ts +3 -15
- package/src/engine/renderers/Indicator/trix.ts +3 -12
- package/src/engine/renderers/Indicator/vma.ts +3 -15
- package/src/engine/renderers/Indicator/vwap.ts +3 -15
- package/src/engine/renderers/Indicator/wma.ts +3 -15
- package/src/engine/renderers/Indicator/wmsr.ts +7 -17
- package/src/engine/renderers/__tests__/candle.sceneRenderer.test.ts +208 -0
- package/src/engine/renderers/__tests__/candleViaRenderer.test.ts +100 -0
- package/src/engine/renderers/__tests__/linesViaRenderer.test.ts +263 -0
- package/src/engine/renderers/__tests__/rectsViaRenderer.test.ts +87 -0
- package/src/engine/renderers/candle.ts +26 -69
- package/src/engine/renderers/candleViaRenderer.ts +38 -0
- package/src/engine/renderers/linesViaRenderer.ts +226 -0
- package/src/engine/renderers/rectsViaRenderer.ts +83 -0
- package/src/engine/renderers/subVolume.ts +9 -61
- package/src/engine/renderers/timeAxis.ts +1 -1
- package/src/engine/state/__tests__/effectiveTheme.test.ts +49 -0
- package/src/engine/state/__tests__/rendererState.test.ts +36 -0
- package/src/engine/state/__tests__/settingsState.test.ts +1 -1
- package/src/engine/state/chartStateKernel.ts +38 -17
- package/src/engine/state/index.ts +6 -1
- package/src/engine/state/interactionState.ts +73 -102
- package/src/engine/state/rendererState.ts +32 -0
- package/src/engine/state/themeState.ts +15 -8
- package/src/engine/state/viewportState.ts +6 -3
- package/src/engine/subPaneManager.ts +2 -16
- package/src/foundation/config/__tests__/chartSettings.test.ts +25 -0
- package/src/foundation/config/chartSettings.ts +24 -7
- package/src/foundation/plugin/index.ts +0 -1
- package/src/foundation/plugin/rendererPluginManager.ts +0 -99
- package/src/foundation/plugin/types.ts +11 -18
- package/src/foundation/reactivity/__tests__/frameTransaction.test.ts +306 -0
- package/src/foundation/reactivity/frameTransaction.ts +239 -0
- package/src/foundation/reactivity/index.ts +8 -0
- package/src/foundation/reactivity/signal.ts +39 -0
- package/src/foundation/tokens/__tests__/__snapshots__/baseline.test.ts.snap +2 -2
- package/src/foundation/tokens/theme-dark.ts +2 -1
- package/src/foundation/tokens/theme-light.ts +2 -1
- package/src/rendering/render/Renderer.ts +27 -14
- package/src/rendering/render/SurfaceBackend.ts +5 -7
- package/src/rendering/render/__tests__/canvas2DRenderer.test.ts +34 -0
- package/src/rendering/render/__tests__/contract.test.ts +2 -2
- package/src/rendering/render/__tests__/frameMetrics.test.ts +24 -0
- package/src/rendering/render/__tests__/rendererHost.test.ts +157 -0
- package/src/rendering/render/__tests__/webglRenderer.fallback.test.ts +14 -74
- package/src/rendering/render/__tests__/webglRenderer.test.ts +64 -6
- package/src/rendering/render/__tests__/webgpuRenderer.test.ts +370 -0
- package/src/rendering/render/__tests__/webgpuResourceTable.test.ts +62 -0
- package/src/rendering/render/__tests__/webgpuSurfaceBackend.test.ts +120 -0
- package/src/rendering/render/createCanvas2DRenderer.ts +83 -0
- package/src/rendering/render/createDefaultRendererHost.ts +74 -0
- package/src/rendering/render/createWebGLRenderer.ts +41 -87
- package/src/rendering/render/createWebGPURenderer.ts +677 -0
- package/src/rendering/render/createWebGPUSurfaceBackend.ts +106 -0
- package/src/rendering/render/frameMetrics.ts +54 -0
- package/src/rendering/render/index.ts +30 -0
- package/src/rendering/render/rendererHost.ts +210 -0
- package/src/rendering/render/webgpuResourceTable.ts +87 -0
- package/src/rendering/scene/__tests__/layerFromPlugin.test.ts +29 -2
- package/src/rendering/scene/__tests__/retainedScene.test.ts +59 -0
- package/src/rendering/scene/createLayerFromPlugin.ts +9 -2
- package/src/rendering/scene/layerRegistry.ts +4 -6
- package/src/rendering/scene/retainedScene.ts +101 -0
- package/src/version.ts +1 -1
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import type { RenderContext } from '../../foundation/plugin/index'
|
|
2
|
+
import type { Renderer } from '../../rendering/render/Renderer'
|
|
3
|
+
|
|
4
|
+
export type LinePoint = { x: number; y: number }
|
|
5
|
+
|
|
6
|
+
export type ColoredLineStrip = {
|
|
7
|
+
points: LinePoint[]
|
|
8
|
+
color: string
|
|
9
|
+
width?: number
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
type LineGpuCache = {
|
|
13
|
+
pipeline: ReturnType<Renderer['createPipeline']>
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const lineCacheByRenderer = new WeakMap<Renderer, LineGpuCache>()
|
|
17
|
+
|
|
18
|
+
function ensureLineCache(renderer: Renderer): LineGpuCache {
|
|
19
|
+
let cache = lineCacheByRenderer.get(renderer)
|
|
20
|
+
if (!cache) {
|
|
21
|
+
cache = { pipeline: renderer.createPipeline({ type: 'line' }) }
|
|
22
|
+
lineCacheByRenderer.set(renderer, cache)
|
|
23
|
+
}
|
|
24
|
+
return cache
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* 经 Renderer.drawLines 一次提交多条折线(strips 批量)。
|
|
29
|
+
* 禁止 per-strip 循环 drawLines:LineWebGLSurface MSAA 每次 clear 会盖掉前一条。
|
|
30
|
+
* 不负责 composite。pipeline 按 renderer 缓存。
|
|
31
|
+
*/
|
|
32
|
+
export function drawLinesViaRenderer(
|
|
33
|
+
renderer: Renderer,
|
|
34
|
+
lines: ReadonlyArray<ColoredLineStrip>,
|
|
35
|
+
scrollLeft: number,
|
|
36
|
+
): boolean {
|
|
37
|
+
if (!renderer.surface.isAvailable()) return false
|
|
38
|
+
const drawable = lines.filter((l) => l.points.length >= 2)
|
|
39
|
+
if (drawable.length === 0) return true
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
const cache = ensureLineCache(renderer)
|
|
43
|
+
return renderer.drawLines({
|
|
44
|
+
pipeline: cache.pipeline,
|
|
45
|
+
strips: drawable.map((l) => ({
|
|
46
|
+
points: l.points,
|
|
47
|
+
color: l.color,
|
|
48
|
+
width: l.width ?? 1,
|
|
49
|
+
})),
|
|
50
|
+
uniforms: { scrollLeft },
|
|
51
|
+
})
|
|
52
|
+
} catch {
|
|
53
|
+
return false
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** WebGPU 走可见 DOM canvas,禁止 drawImage 回 2D(M2 hybrid) */
|
|
58
|
+
export function shouldCompositeSceneRenderer(renderer: Renderer): boolean {
|
|
59
|
+
return renderer.caps.name !== 'webgpu'
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 将 sceneRenderer 输出合成到主 canvas。
|
|
64
|
+
* WebGL:即时 composite(MSAA resolve 会盖掉 shared 上前序内容,须按层立即合成)。
|
|
65
|
+
* WebGPU:no-op,由 plot 区可见 GPU canvas 直接显示。
|
|
66
|
+
*/
|
|
67
|
+
export function compositeSceneRenderer(context: {
|
|
68
|
+
ctx: CanvasRenderingContext2D
|
|
69
|
+
pane: { top: number; height: number }
|
|
70
|
+
viewport?: { plotWidth: number }
|
|
71
|
+
paneWidth: number
|
|
72
|
+
dpr: number
|
|
73
|
+
sceneRenderer?: Renderer
|
|
74
|
+
}): void {
|
|
75
|
+
const r = context.sceneRenderer
|
|
76
|
+
if (!r || !shouldCompositeSceneRenderer(r)) return
|
|
77
|
+
r.surface.compositeTo(
|
|
78
|
+
context.ctx,
|
|
79
|
+
{
|
|
80
|
+
x: 0,
|
|
81
|
+
y: context.pane.top,
|
|
82
|
+
width: context.viewport?.plotWidth ?? context.paneWidth,
|
|
83
|
+
height: context.pane.height,
|
|
84
|
+
dpr: context.dpr,
|
|
85
|
+
},
|
|
86
|
+
{ imageSmoothingEnabled: false },
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* 折线 GPU:仅 sceneRenderer;失败返回 false(调用方 2D)。
|
|
92
|
+
* 指标 draw 内:if (tryDrawLinesGpu(context, lines, scrollLeft)) return
|
|
93
|
+
*/
|
|
94
|
+
export function tryDrawLinesGpu(
|
|
95
|
+
context: RenderContext,
|
|
96
|
+
lines: ReadonlyArray<ColoredLineStrip>,
|
|
97
|
+
scrollLeft: number,
|
|
98
|
+
): boolean {
|
|
99
|
+
const drawable = lines.filter((l) => l.points.length >= 2)
|
|
100
|
+
if (drawable.length === 0) return false
|
|
101
|
+
|
|
102
|
+
if (!context.sceneRenderer) return false
|
|
103
|
+
if (drawLinesViaRenderer(context.sceneRenderer, drawable, scrollLeft)) {
|
|
104
|
+
compositeSceneRenderer(context)
|
|
105
|
+
return true
|
|
106
|
+
}
|
|
107
|
+
return false
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
type FillGpuCache = {
|
|
111
|
+
pipeline: ReturnType<Renderer['createPipeline']>
|
|
112
|
+
vertices: ReturnType<Renderer['createBuffer']> | null
|
|
113
|
+
capacity: number
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const fillCacheByRenderer = new WeakMap<Renderer, FillGpuCache>()
|
|
117
|
+
|
|
118
|
+
function ensureFillCache(renderer: Renderer): FillGpuCache {
|
|
119
|
+
let cache = fillCacheByRenderer.get(renderer)
|
|
120
|
+
if (!cache) {
|
|
121
|
+
cache = {
|
|
122
|
+
pipeline: renderer.createPipeline({ type: 'fill' }),
|
|
123
|
+
vertices: null,
|
|
124
|
+
capacity: 0,
|
|
125
|
+
}
|
|
126
|
+
fillCacheByRenderer.set(renderer, cache)
|
|
127
|
+
}
|
|
128
|
+
return cache
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* 经 Renderer fill pipeline 画上下轨填充带(BOLL/ENE)。
|
|
133
|
+
* 顶点布局与 createWebGLRenderer fill 一致:每点 upper.x,y + lower.x,y。
|
|
134
|
+
* vertex buffer 按 renderer 缓存扩容,不每帧 destroy。
|
|
135
|
+
*/
|
|
136
|
+
export function drawFilledBandViaRenderer(
|
|
137
|
+
renderer: Renderer,
|
|
138
|
+
upperPoints: ReadonlyArray<LinePoint>,
|
|
139
|
+
lowerPoints: ReadonlyArray<LinePoint>,
|
|
140
|
+
color: string,
|
|
141
|
+
scrollLeft: number,
|
|
142
|
+
): boolean {
|
|
143
|
+
if (!renderer.surface.isAvailable()) return false
|
|
144
|
+
const n = Math.min(upperPoints.length, lowerPoints.length)
|
|
145
|
+
if (n < 2) return false
|
|
146
|
+
|
|
147
|
+
try {
|
|
148
|
+
const cache = ensureFillCache(renderer)
|
|
149
|
+
// vertexCount = n*2(上轨 n + 下轨 n 交错为 n 组 4 floats)
|
|
150
|
+
const floats = new Float32Array(n * 4)
|
|
151
|
+
for (let i = 0; i < n; i++) {
|
|
152
|
+
const o = i * 4
|
|
153
|
+
floats[o] = upperPoints[i]!.x
|
|
154
|
+
floats[o + 1] = upperPoints[i]!.y
|
|
155
|
+
floats[o + 2] = lowerPoints[i]!.x
|
|
156
|
+
floats[o + 3] = lowerPoints[i]!.y
|
|
157
|
+
}
|
|
158
|
+
if (!cache.vertices || cache.capacity < floats.byteLength) {
|
|
159
|
+
if (cache.vertices) renderer.destroyBuffer(cache.vertices)
|
|
160
|
+
cache.vertices = renderer.createBuffer('vertex', floats.byteLength)
|
|
161
|
+
cache.capacity = floats.byteLength
|
|
162
|
+
}
|
|
163
|
+
renderer.writeBuffer(cache.vertices, floats)
|
|
164
|
+
return renderer.drawLines({
|
|
165
|
+
pipeline: cache.pipeline,
|
|
166
|
+
vertices: cache.vertices,
|
|
167
|
+
vertexCount: n * 2,
|
|
168
|
+
uniforms: { color, scrollLeft },
|
|
169
|
+
})
|
|
170
|
+
} catch {
|
|
171
|
+
return false
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** 将全局 alpha 烘焙进 rgba 颜色串(WebGPU 无 compositeTo 时用) */
|
|
176
|
+
function bakeAlphaIntoColor(color: string, alpha: number): string {
|
|
177
|
+
if (!(alpha < 1)) return color
|
|
178
|
+
const a = Math.max(0, Math.min(1, alpha))
|
|
179
|
+
const rgba = color.match(/^rgba?\(([^)]+)\)$/i)
|
|
180
|
+
if (rgba) {
|
|
181
|
+
const parts = rgba[1]!.split(',').map((p) => p.trim())
|
|
182
|
+
if (parts.length >= 3) {
|
|
183
|
+
const baseA = parts.length >= 4 ? Number(parts[3]) : 1
|
|
184
|
+
const nextA = (Number.isFinite(baseA) ? baseA : 1) * a
|
|
185
|
+
return `rgba(${parts[0]}, ${parts[1]}, ${parts[2]}, ${nextA})`
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return color
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* 填充带 GPU:仅 sceneRenderer fill;失败返回 false。
|
|
193
|
+
* @param alpha composite 时的全局透明度(半透明 bandFill)
|
|
194
|
+
* @remarks WebGL 走 compositeTo(alpha);WebGPU hybrid 把 alpha 烘焙进 fill color
|
|
195
|
+
*/
|
|
196
|
+
export function tryDrawFilledBandGpu(
|
|
197
|
+
context: RenderContext,
|
|
198
|
+
upperPoints: ReadonlyArray<LinePoint>,
|
|
199
|
+
lowerPoints: ReadonlyArray<LinePoint>,
|
|
200
|
+
color: string,
|
|
201
|
+
scrollLeft: number,
|
|
202
|
+
alpha = 1,
|
|
203
|
+
): boolean {
|
|
204
|
+
if (Math.min(upperPoints.length, lowerPoints.length) < 2) return false
|
|
205
|
+
|
|
206
|
+
if (!context.sceneRenderer) return false
|
|
207
|
+
const r = context.sceneRenderer
|
|
208
|
+
const fillColor = shouldCompositeSceneRenderer(r) ? color : bakeAlphaIntoColor(color, alpha)
|
|
209
|
+
if (drawFilledBandViaRenderer(r, upperPoints, lowerPoints, fillColor, scrollLeft)) {
|
|
210
|
+
if (shouldCompositeSceneRenderer(r)) {
|
|
211
|
+
r.surface.compositeTo(
|
|
212
|
+
context.ctx,
|
|
213
|
+
{
|
|
214
|
+
x: 0,
|
|
215
|
+
y: context.pane.top,
|
|
216
|
+
width: context.viewport?.plotWidth ?? context.paneWidth,
|
|
217
|
+
height: context.pane.height,
|
|
218
|
+
dpr: context.dpr,
|
|
219
|
+
},
|
|
220
|
+
{ imageSmoothingEnabled: false, alpha },
|
|
221
|
+
)
|
|
222
|
+
}
|
|
223
|
+
return true
|
|
224
|
+
}
|
|
225
|
+
return false
|
|
226
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { RenderContext } from '../../foundation/plugin/index'
|
|
2
|
+
import type { BufferHandle, PipelineHandle, Renderer } from '../../rendering/render/Renderer'
|
|
3
|
+
import { compositeSceneRenderer } from './linesViaRenderer'
|
|
4
|
+
|
|
5
|
+
export type RectBatch = {
|
|
6
|
+
buf: Float32Array
|
|
7
|
+
count: number
|
|
8
|
+
color: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
type RectGpuCache = {
|
|
12
|
+
pipeline: PipelineHandle
|
|
13
|
+
unit: BufferHandle
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const rectCacheByRenderer = new WeakMap<Renderer, RectGpuCache>()
|
|
17
|
+
|
|
18
|
+
function ensureRectCache(renderer: Renderer): RectGpuCache {
|
|
19
|
+
let cache = rectCacheByRenderer.get(renderer)
|
|
20
|
+
if (!cache) {
|
|
21
|
+
cache = {
|
|
22
|
+
pipeline: renderer.createPipeline({ type: 'candle' }),
|
|
23
|
+
unit: renderer.createBuffer('vertex', 64),
|
|
24
|
+
}
|
|
25
|
+
rectCacheByRenderer.set(renderer, cache)
|
|
26
|
+
}
|
|
27
|
+
return cache
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* 经 Renderer.drawInstances 画多组矩形(volume / MACD bar / candle 共用)。
|
|
32
|
+
* 任一非空 batch 失败 → false。不负责 composite。
|
|
33
|
+
* instance buffer 每 batch 独立创建,避免同 frame 内不同绘制目标互相覆盖。
|
|
34
|
+
*/
|
|
35
|
+
export function drawRectBatchesViaRenderer(
|
|
36
|
+
renderer: Renderer,
|
|
37
|
+
batches: ReadonlyArray<RectBatch>,
|
|
38
|
+
scrollLeft: number,
|
|
39
|
+
): boolean {
|
|
40
|
+
if (!renderer.surface.isAvailable()) return false
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
const cache = ensureRectCache(renderer)
|
|
44
|
+
for (const batch of batches) {
|
|
45
|
+
if (batch.count <= 0) continue
|
|
46
|
+
const byteLength = batch.count * 4 * 4
|
|
47
|
+
const instances = renderer.createBuffer('instance', byteLength)
|
|
48
|
+
renderer.writeBuffer(instances, batch.buf.subarray(0, batch.count * 4))
|
|
49
|
+
const ok = renderer.drawInstances({
|
|
50
|
+
pipeline: cache.pipeline,
|
|
51
|
+
vertices: cache.unit,
|
|
52
|
+
instances,
|
|
53
|
+
instanceCount: batch.count,
|
|
54
|
+
vertexCount: 6,
|
|
55
|
+
uniforms: { color: batch.color, scrollLeft },
|
|
56
|
+
})
|
|
57
|
+
renderer.destroyBuffer(instances)
|
|
58
|
+
if (!ok) return false
|
|
59
|
+
}
|
|
60
|
+
return true
|
|
61
|
+
} catch {
|
|
62
|
+
return false
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* 矩形 GPU:仅 sceneRenderer;失败返回 false。
|
|
68
|
+
*/
|
|
69
|
+
export function tryDrawRectsGpu(
|
|
70
|
+
context: RenderContext,
|
|
71
|
+
batches: ReadonlyArray<RectBatch>,
|
|
72
|
+
scrollLeft: number,
|
|
73
|
+
): boolean {
|
|
74
|
+
const active = batches.filter((b) => b.count > 0)
|
|
75
|
+
if (active.length === 0) return true
|
|
76
|
+
|
|
77
|
+
if (!context.sceneRenderer) return false
|
|
78
|
+
if (drawRectBatchesViaRenderer(context.sceneRenderer, active, scrollLeft)) {
|
|
79
|
+
compositeSceneRenderer(context)
|
|
80
|
+
return true
|
|
81
|
+
}
|
|
82
|
+
return false
|
|
83
|
+
}
|
|
@@ -13,6 +13,7 @@ import { resolveStateKey } from '../indicators/indicatorMetadata'
|
|
|
13
13
|
import type { IndicatorScheduler } from '../indicators/scheduler'
|
|
14
14
|
|
|
15
15
|
import { createVolumeScaleRendererPlugin } from './Indicator/scale/volume_scale'
|
|
16
|
+
import { tryDrawRectsGpu } from './rectsViaRenderer'
|
|
16
17
|
|
|
17
18
|
interface VolumeRendererOptions {
|
|
18
19
|
/** 目标 pane ID(默认 'sub') */
|
|
@@ -164,19 +165,16 @@ function createVolumeRendererPlugin(options: VolumeRendererOptions = {}): Render
|
|
|
164
165
|
buf[off + 3] = finalH
|
|
165
166
|
}
|
|
166
167
|
|
|
167
|
-
const
|
|
168
|
+
const usedGpu = tryDrawRectsGpu(
|
|
168
169
|
context,
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
upVolume,
|
|
176
|
-
downVolume,
|
|
177
|
-
neutralVolume,
|
|
170
|
+
[
|
|
171
|
+
{ buf: upBuf, count: upCount, color: upVolume },
|
|
172
|
+
{ buf: downBuf, count: downCount, color: downVolume },
|
|
173
|
+
{ buf: neutralBuf, count: neutralCount, color: neutralVolume },
|
|
174
|
+
],
|
|
175
|
+
context.scrollLeft,
|
|
178
176
|
)
|
|
179
|
-
if (!
|
|
177
|
+
if (!usedGpu) {
|
|
180
178
|
drawVolumeWithCanvas2D(
|
|
181
179
|
ctx,
|
|
182
180
|
context.scrollLeft,
|
|
@@ -190,54 +188,11 @@ function createVolumeRendererPlugin(options: VolumeRendererOptions = {}): Render
|
|
|
190
188
|
downVolume,
|
|
191
189
|
neutralVolume,
|
|
192
190
|
)
|
|
193
|
-
} else {
|
|
194
|
-
compositeVolumeWebGL(ctx, context)
|
|
195
191
|
}
|
|
196
192
|
},
|
|
197
193
|
}
|
|
198
194
|
}
|
|
199
195
|
|
|
200
|
-
function drawVolumeWithWebGL(
|
|
201
|
-
context: RenderContext,
|
|
202
|
-
upBuf: Float32Array,
|
|
203
|
-
upCount: number,
|
|
204
|
-
downBuf: Float32Array,
|
|
205
|
-
downCount: number,
|
|
206
|
-
neutralBuf: Float32Array,
|
|
207
|
-
neutralCount: number,
|
|
208
|
-
upColor: string,
|
|
209
|
-
downColor: string,
|
|
210
|
-
neutralColor: string,
|
|
211
|
-
): boolean {
|
|
212
|
-
if (context.settings?.enableWebGLRendering === false) return false
|
|
213
|
-
const surface = context.candleWebGLSurface
|
|
214
|
-
if (!surface || !surface.isAvailable()) return false
|
|
215
|
-
|
|
216
|
-
surface.clear()
|
|
217
|
-
|
|
218
|
-
const ok1 =
|
|
219
|
-
upCount === 0 ||
|
|
220
|
-
surface.drawRectBuffer(upBuf.subarray(0, upCount * 4), upCount, upColor, context.scrollLeft)
|
|
221
|
-
const ok2 =
|
|
222
|
-
downCount === 0 ||
|
|
223
|
-
surface.drawRectBuffer(
|
|
224
|
-
downBuf.subarray(0, downCount * 4),
|
|
225
|
-
downCount,
|
|
226
|
-
downColor,
|
|
227
|
-
context.scrollLeft,
|
|
228
|
-
)
|
|
229
|
-
const ok3 =
|
|
230
|
-
neutralCount === 0 ||
|
|
231
|
-
surface.drawRectBuffer(
|
|
232
|
-
neutralBuf.subarray(0, neutralCount * 4),
|
|
233
|
-
neutralCount,
|
|
234
|
-
neutralColor,
|
|
235
|
-
context.scrollLeft,
|
|
236
|
-
)
|
|
237
|
-
|
|
238
|
-
return ok1 && ok2 && ok3
|
|
239
|
-
}
|
|
240
|
-
|
|
241
196
|
function drawVolumeWithCanvas2D(
|
|
242
197
|
ctx: CanvasRenderingContext2D,
|
|
243
198
|
scrollLeft: number,
|
|
@@ -275,13 +230,6 @@ function drawVolumeWithCanvas2D(
|
|
|
275
230
|
ctx.restore()
|
|
276
231
|
}
|
|
277
232
|
|
|
278
|
-
function compositeVolumeWebGL(ctx: CanvasRenderingContext2D, context: RenderContext): void {
|
|
279
|
-
const surface = context.candleWebGLSurface
|
|
280
|
-
if (!surface) return
|
|
281
|
-
|
|
282
|
-
surface.compositeTo(ctx)
|
|
283
|
-
}
|
|
284
|
-
|
|
285
233
|
/**
|
|
286
234
|
* 判断成交量柱子颜色
|
|
287
235
|
*/
|
|
@@ -26,7 +26,7 @@ export function createTimeAxisRendererPlugin(options: {
|
|
|
26
26
|
debugName: '时间轴',
|
|
27
27
|
paneId: TIME_AXIS_PANE_ID,
|
|
28
28
|
priority: RENDERER_PRIORITY.SYSTEM_XAXIS,
|
|
29
|
-
isSystem: true, //
|
|
29
|
+
isSystem: true, // 系统渲染器:由 Scene Layer 调度
|
|
30
30
|
|
|
31
31
|
draw(context: RenderContext) {
|
|
32
32
|
const { ctx, data, range, scrollLeft, kWidth, kGap, dpr, paneWidth } = context
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import { ChartStateKernel } from '../chartStateKernel'
|
|
4
|
+
|
|
5
|
+
function createKernel() {
|
|
6
|
+
return new ChartStateKernel({
|
|
7
|
+
initialOptions: {
|
|
8
|
+
minKWidth: 2,
|
|
9
|
+
maxKWidth: 50,
|
|
10
|
+
zoomLevelCount: 20,
|
|
11
|
+
bottomAxisHeight: 24,
|
|
12
|
+
rightAxisWidth: 60,
|
|
13
|
+
leftAxisWidth: 0,
|
|
14
|
+
yPaddingPx: 8,
|
|
15
|
+
panes: [{ id: 'main', ratio: 1 }],
|
|
16
|
+
},
|
|
17
|
+
initialZoomLevel: 1,
|
|
18
|
+
scheduleDraw: () => {},
|
|
19
|
+
})
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
describe('effectiveTheme', () => {
|
|
23
|
+
it('follows settings.theme when not auto', () => {
|
|
24
|
+
const k = createKernel()
|
|
25
|
+
k.settings.actions.patch({ theme: 'light' })
|
|
26
|
+
expect(k.effectiveTheme$.peek()).toBe('light')
|
|
27
|
+
k.settings.actions.patch({ theme: 'dark' })
|
|
28
|
+
expect(k.effectiveTheme$.peek()).toBe('dark')
|
|
29
|
+
k.dispose()
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('follows systemTheme when settings.theme is auto', () => {
|
|
33
|
+
const k = createKernel()
|
|
34
|
+
k.settings.actions.patch({ theme: 'auto' })
|
|
35
|
+
k.systemTheme.actions.setSystemTheme('dark')
|
|
36
|
+
expect(k.effectiveTheme$.peek()).toBe('dark')
|
|
37
|
+
k.systemTheme.actions.setSystemTheme('light')
|
|
38
|
+
expect(k.effectiveTheme$.peek()).toBe('light')
|
|
39
|
+
k.dispose()
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('setTheme action patches settings preference', () => {
|
|
43
|
+
const k = createKernel()
|
|
44
|
+
k.actions.setTheme('light')
|
|
45
|
+
expect(k.settings.readonly.settings.peek().theme).toBe('light')
|
|
46
|
+
expect(k.signals.theme()).toBe('light')
|
|
47
|
+
k.dispose()
|
|
48
|
+
})
|
|
49
|
+
})
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import { createRendererState } from '../rendererState'
|
|
4
|
+
|
|
5
|
+
describe('rendererState', () => {
|
|
6
|
+
it('publishes immutable backend runtime snapshots through an Action', () => {
|
|
7
|
+
const state = createRendererState({ effective: 'webgl', status: 'ready', error: null })
|
|
8
|
+
const listener = vi.fn()
|
|
9
|
+
state.readonly.runtime.subscribe(listener)
|
|
10
|
+
|
|
11
|
+
state.actions.setRuntime({
|
|
12
|
+
effective: 'canvas',
|
|
13
|
+
status: 'degraded',
|
|
14
|
+
error: 'WebGPU adapter unavailable',
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
expect(state.readonly.runtime.peek()).toEqual({
|
|
18
|
+
effective: 'canvas',
|
|
19
|
+
status: 'degraded',
|
|
20
|
+
error: 'WebGPU adapter unavailable',
|
|
21
|
+
})
|
|
22
|
+
expect(Object.isFrozen(state.readonly.runtime.peek())).toBe(true)
|
|
23
|
+
expect(listener).toHaveBeenCalledOnce()
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
it('does not notify for an identical runtime', () => {
|
|
27
|
+
const runtime = { effective: 'webgpu', status: 'ready', error: null } as const
|
|
28
|
+
const state = createRendererState(runtime)
|
|
29
|
+
const listener = vi.fn()
|
|
30
|
+
state.readonly.runtime.subscribe(listener)
|
|
31
|
+
|
|
32
|
+
state.actions.setRuntime({ ...runtime })
|
|
33
|
+
|
|
34
|
+
expect(listener).not.toHaveBeenCalled()
|
|
35
|
+
})
|
|
36
|
+
})
|
|
@@ -15,7 +15,7 @@ describe('settingsState', () => {
|
|
|
15
15
|
const s = createSettingsState()
|
|
16
16
|
s.actions.replace({ showGridLines: false })
|
|
17
17
|
expect(s.readonly.settings.peek().showGridLines).toBe(false)
|
|
18
|
-
expect(s.readonly.settings.peek().
|
|
18
|
+
expect(s.readonly.settings.peek().rendererBackend).toBe('webgl')
|
|
19
19
|
})
|
|
20
20
|
|
|
21
21
|
it('patch merges onto current then re-resolves', () => {
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
type ViewportDomDeps,
|
|
8
8
|
} from './viewportState'
|
|
9
9
|
import { createPaneState, type PaneStateModule } from './paneState'
|
|
10
|
-
import {
|
|
10
|
+
import { createSystemThemeState, type SystemThemeStateModule } from './themeState'
|
|
11
11
|
import { createSettingsState, type SettingsStateModule } from './settingsState'
|
|
12
12
|
import { createModeState, type ModeStateModule } from './modeState'
|
|
13
13
|
import { createDrawingState, type DrawingStateModule } from './drawingState'
|
|
@@ -22,6 +22,7 @@ import { createComparisonState, type ComparisonStateModule } from './comparisonS
|
|
|
22
22
|
import { createIndicatorState, type IndicatorStateModule } from './indicatorState'
|
|
23
23
|
import { createSubPaneState, type SubPaneStateModule } from './subPaneState'
|
|
24
24
|
import { createMarkerState, type MarkerStateModule } from './markerState'
|
|
25
|
+
import { createRendererState, type RendererStateModule } from './rendererState'
|
|
25
26
|
import { batch, computed, type ReadonlySignal } from '../../foundation/reactivity/signal'
|
|
26
27
|
import type { DrawingObject } from '../../foundation/plugin/index'
|
|
27
28
|
import type { PaneSpec } from '../chartTypes'
|
|
@@ -29,6 +30,8 @@ import type { DrawingToolId } from '../drawing/toolConfig'
|
|
|
29
30
|
import type { SymbolSpec, SymbolInfo } from '../../controllers/types'
|
|
30
31
|
import type { MarkerEntity, CustomMarkerEntity } from '../marker/registry'
|
|
31
32
|
import type { DragMode } from './interactionState'
|
|
33
|
+
import type { ChartSettings } from '../../foundation/config/chartSettings'
|
|
34
|
+
import type { RendererBackendRuntime } from '../../rendering/render/rendererHost'
|
|
32
35
|
|
|
33
36
|
export interface ChartStateKernelDeps {
|
|
34
37
|
initialOptions: {
|
|
@@ -48,6 +51,8 @@ export interface ChartStateKernelDeps {
|
|
|
48
51
|
[key: string]: unknown
|
|
49
52
|
}
|
|
50
53
|
initialZoomLevel: number
|
|
54
|
+
initialSettings?: Partial<ChartSettings>
|
|
55
|
+
initialRendererRuntime?: RendererBackendRuntime
|
|
51
56
|
scheduleDraw: (level?: unknown) => void
|
|
52
57
|
}
|
|
53
58
|
|
|
@@ -57,7 +62,8 @@ export class ChartStateKernel extends StateKernel {
|
|
|
57
62
|
readonly data: DataStateModule
|
|
58
63
|
readonly viewport: ViewportStateModule
|
|
59
64
|
readonly pane: PaneStateModule
|
|
60
|
-
|
|
65
|
+
/** 系统主题注入(非用户偏好);用户偏好在 settings.theme */
|
|
66
|
+
readonly systemTheme: SystemThemeStateModule
|
|
61
67
|
readonly settings: SettingsStateModule
|
|
62
68
|
readonly mode: ModeStateModule
|
|
63
69
|
readonly drawing: DrawingStateModule
|
|
@@ -67,9 +73,12 @@ export class ChartStateKernel extends StateKernel {
|
|
|
67
73
|
readonly indicator: IndicatorStateModule
|
|
68
74
|
readonly subPane: SubPaneStateModule
|
|
69
75
|
readonly marker: MarkerStateModule
|
|
76
|
+
readonly renderer: RendererStateModule
|
|
70
77
|
|
|
71
78
|
readonly zoomLevel$: ReadonlySignal<number>
|
|
72
79
|
readonly dataLength$: ReadonlySignal<number>
|
|
80
|
+
/** 生效主题 light|dark(settings.theme + systemTheme 推导) */
|
|
81
|
+
readonly effectiveTheme$: ReadonlySignal<'light' | 'dark'>
|
|
73
82
|
readonly optionsForViewport$: ReadonlySignal<{
|
|
74
83
|
bottomAxisHeight: number
|
|
75
84
|
kWidth: number
|
|
@@ -136,11 +145,19 @@ export class ChartStateKernel extends StateKernel {
|
|
|
136
145
|
this.pane.actions.commitLayout(initialRatios, initialPanes)
|
|
137
146
|
}
|
|
138
147
|
|
|
139
|
-
// ──
|
|
140
|
-
this.
|
|
148
|
+
// ── Settings state(用户偏好 SSOT,含 theme light|dark|auto)──
|
|
149
|
+
this.settings = createSettingsState(deps.initialSettings)
|
|
150
|
+
this.renderer = createRendererState(
|
|
151
|
+
deps.initialRendererRuntime ?? { effective: 'webgl', status: 'ready', error: null },
|
|
152
|
+
)
|
|
141
153
|
|
|
142
|
-
// ──
|
|
143
|
-
this.
|
|
154
|
+
// ── 系统主题(auto 时参与 effectiveTheme 推导)──
|
|
155
|
+
this.systemTheme = createSystemThemeState()
|
|
156
|
+
this.effectiveTheme$ = computed(() => {
|
|
157
|
+
const pref = this.settings.readonly.settings().theme
|
|
158
|
+
if (pref === 'auto') return this.systemTheme.readonly.systemTheme()
|
|
159
|
+
return pref === 'dark' ? 'dark' : 'light'
|
|
160
|
+
})
|
|
144
161
|
|
|
145
162
|
// ── Mode state(kline / timeshare id;ModeHandler 仍在 Chart)──
|
|
146
163
|
this.mode = createModeState()
|
|
@@ -181,10 +198,11 @@ export class ChartStateKernel extends StateKernel {
|
|
|
181
198
|
// Pane
|
|
182
199
|
paneRatios: this.pane.readonly.paneRatios,
|
|
183
200
|
paneSpecs: this.pane.readonly.paneSpecs,
|
|
184
|
-
// Theme
|
|
185
|
-
theme: this.
|
|
201
|
+
// Theme(生效主题;偏好在 settings.theme)
|
|
202
|
+
theme: this.effectiveTheme$,
|
|
186
203
|
// Settings
|
|
187
204
|
settings: this.settings.readonly.settings,
|
|
205
|
+
rendererRuntime: this.renderer.readonly.runtime,
|
|
188
206
|
// Mode
|
|
189
207
|
chartMode: this.mode.readonly.chartMode,
|
|
190
208
|
// Pane scale types
|
|
@@ -228,22 +246,24 @@ export class ChartStateKernel extends StateKernel {
|
|
|
228
246
|
setPaneSpecs: (specs: PaneSpec[]) => this.pane.actions.setPaneSpecs(specs),
|
|
229
247
|
commitPaneLayout: (ratios: Record<string, number>, specs: PaneSpec[]) =>
|
|
230
248
|
this.pane.actions.commitLayout(ratios, specs),
|
|
231
|
-
setTheme: (theme: 'light' | 'dark') => this.
|
|
249
|
+
setTheme: (theme: 'light' | 'dark') => this.settings.actions.patch({ theme }),
|
|
250
|
+
setSystemTheme: (theme: 'light' | 'dark') => this.systemTheme.actions.setSystemTheme(theme),
|
|
251
|
+
setRendererRuntime: (runtime: RendererBackendRuntime) =>
|
|
252
|
+
this.renderer.actions.setRuntime(runtime),
|
|
232
253
|
setDrawingTool: (tool: DrawingToolId) => this.drawing.actions.setDrawingTool(tool),
|
|
233
254
|
setDrawings: (drawings: ReadonlyArray<DrawingObject>) =>
|
|
234
255
|
this.drawing.actions.setDrawings(drawings),
|
|
235
256
|
clearDrawings: () => this.drawing.actions.clearDrawings(),
|
|
236
|
-
updateCrosshair: (
|
|
237
|
-
|
|
257
|
+
updateCrosshair: (
|
|
258
|
+
pos: { x: number; y: number } | null,
|
|
259
|
+
price: number | null,
|
|
260
|
+
index?: number | null,
|
|
261
|
+
) => this.interaction.actions.updateCrosshair(pos, price, index),
|
|
262
|
+
setCrosshairIndex: (index: number | null) => this.interaction.actions.setCrosshairIndex(index),
|
|
238
263
|
updateHover: (index: number | null, paneId: string | null) =>
|
|
239
264
|
this.interaction.actions.updateHover(index, paneId),
|
|
240
265
|
setHoveredIndex: (index: number | null) => this.interaction.actions.setHoveredIndex(index),
|
|
241
266
|
setActivePaneId: (paneId: string | null) => this.interaction.actions.setActivePaneId(paneId),
|
|
242
|
-
updateFramePositions: (
|
|
243
|
-
positions: number[] | null,
|
|
244
|
-
centers: number[] | null,
|
|
245
|
-
kWidthPx: number | null,
|
|
246
|
-
) => this.interaction.actions.updateFramePositions(positions, centers, kWidthPx),
|
|
247
267
|
startDrag: (mode: DragMode) => this.interaction.actions.startDrag(mode),
|
|
248
268
|
endDrag: () => this.interaction.actions.endDrag(),
|
|
249
269
|
setDragMode: (mode: DragMode) => this.interaction.actions.setDragMode(mode),
|
|
@@ -377,8 +397,8 @@ export class ChartStateKernel extends StateKernel {
|
|
|
377
397
|
this.data.dispose()
|
|
378
398
|
this.viewport.dispose()
|
|
379
399
|
this.pane.dispose()
|
|
380
|
-
this.theme.dispose()
|
|
381
400
|
this.settings.dispose()
|
|
401
|
+
this.systemTheme.dispose()
|
|
382
402
|
this.mode.dispose()
|
|
383
403
|
this.drawing.dispose()
|
|
384
404
|
this.interaction.dispose()
|
|
@@ -387,6 +407,7 @@ export class ChartStateKernel extends StateKernel {
|
|
|
387
407
|
this.indicator.dispose()
|
|
388
408
|
this.subPane.dispose()
|
|
389
409
|
this.marker.dispose()
|
|
410
|
+
this.renderer.dispose()
|
|
390
411
|
}
|
|
391
412
|
}
|
|
392
413
|
|
|
@@ -23,7 +23,12 @@ export { createDataState, type DataStateModule } from './dataState'
|
|
|
23
23
|
export { createZoomState, type ZoomStateModule, type ZoomDeps } from './zoomState'
|
|
24
24
|
export { createOptionsState, type OptionsStateModule } from './optionsState'
|
|
25
25
|
export { createPaneState, type PaneStateModule } from './paneState'
|
|
26
|
-
export {
|
|
26
|
+
export {
|
|
27
|
+
createSystemThemeState,
|
|
28
|
+
createThemeState,
|
|
29
|
+
type SystemThemeStateModule,
|
|
30
|
+
type ThemeStateModule,
|
|
31
|
+
} from './themeState'
|
|
27
32
|
export { createSettingsState, type SettingsStateModule } from './settingsState'
|
|
28
33
|
export { createModeState, type ModeStateModule, type ChartModeId } from './modeState'
|
|
29
34
|
export { createDrawingState, type DrawingStateModule } from './drawingState'
|