@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.
Files changed (372) hide show
  1. package/dist/controllers/createChartController.d.ts.map +1 -1
  2. package/dist/controllers/createChartController.js +31 -13
  3. package/dist/controllers/createChartController.js.map +1 -1
  4. package/dist/controllers/index.d.ts +1 -0
  5. package/dist/controllers/index.d.ts.map +1 -1
  6. package/dist/controllers/index.js.map +1 -1
  7. package/dist/controllers/types.d.ts +12 -0
  8. package/dist/controllers/types.d.ts.map +1 -1
  9. package/dist/engine/chart.d.ts +29 -11
  10. package/dist/engine/chart.d.ts.map +1 -1
  11. package/dist/engine/chart.js +147 -25
  12. package/dist/engine/chart.js.map +1 -1
  13. package/dist/engine/controller/interaction.d.ts +29 -4
  14. package/dist/engine/controller/interaction.d.ts.map +1 -1
  15. package/dist/engine/controller/interaction.js +78 -31
  16. package/dist/engine/controller/interaction.js.map +1 -1
  17. package/dist/engine/data/incrementalLoadHint.d.ts.map +1 -1
  18. package/dist/engine/data/incrementalLoadHint.js +5 -1
  19. package/dist/engine/data/incrementalLoadHint.js.map +1 -1
  20. package/dist/engine/drawing/DrawingState.d.ts +19 -34
  21. package/dist/engine/drawing/DrawingState.d.ts.map +1 -1
  22. package/dist/engine/drawing/DrawingState.js +110 -92
  23. package/dist/engine/drawing/DrawingState.js.map +1 -1
  24. package/dist/engine/drawing/index.d.ts +4 -1
  25. package/dist/engine/drawing/index.d.ts.map +1 -1
  26. package/dist/engine/drawing/index.js +9 -4
  27. package/dist/engine/drawing/index.js.map +1 -1
  28. package/dist/engine/drawing/interaction.d.ts +9 -29
  29. package/dist/engine/drawing/interaction.d.ts.map +1 -1
  30. package/dist/engine/drawing/interaction.js +23 -40
  31. package/dist/engine/drawing/interaction.js.map +1 -1
  32. package/dist/engine/indicators/chartIndicatorManager.d.ts.map +1 -1
  33. package/dist/engine/indicators/chartIndicatorManager.js +4 -12
  34. package/dist/engine/indicators/chartIndicatorManager.js.map +1 -1
  35. package/dist/engine/layout/chartPaneLayout.d.ts +0 -2
  36. package/dist/engine/layout/chartPaneLayout.d.ts.map +1 -1
  37. package/dist/engine/layout/chartPaneLayout.js +5 -9
  38. package/dist/engine/layout/chartPaneLayout.js.map +1 -1
  39. package/dist/engine/layout/pane.d.ts +0 -39
  40. package/dist/engine/layout/pane.d.ts.map +1 -1
  41. package/dist/engine/layout/pane.js +0 -9
  42. package/dist/engine/layout/pane.js.map +1 -1
  43. package/dist/engine/paneRenderer.d.ts +1 -10
  44. package/dist/engine/paneRenderer.d.ts.map +1 -1
  45. package/dist/engine/paneRenderer.js +2 -19
  46. package/dist/engine/paneRenderer.js.map +1 -1
  47. package/dist/engine/render/chartRenderer.d.ts +49 -8
  48. package/dist/engine/render/chartRenderer.d.ts.map +1 -1
  49. package/dist/engine/render/chartRenderer.js +143 -72
  50. package/dist/engine/render/chartRenderer.js.map +1 -1
  51. package/dist/engine/renderers/Indicator/atr.js +3 -13
  52. package/dist/engine/renderers/Indicator/atr.js.map +1 -1
  53. package/dist/engine/renderers/Indicator/boll.d.ts.map +1 -1
  54. package/dist/engine/renderers/Indicator/boll.js +12 -24
  55. package/dist/engine/renderers/Indicator/boll.js.map +1 -1
  56. package/dist/engine/renderers/Indicator/cci.js +6 -13
  57. package/dist/engine/renderers/Indicator/cci.js.map +1 -1
  58. package/dist/engine/renderers/Indicator/chaikinVol.js +3 -11
  59. package/dist/engine/renderers/Indicator/chaikinVol.js.map +1 -1
  60. package/dist/engine/renderers/Indicator/cmf.js +3 -11
  61. package/dist/engine/renderers/Indicator/cmf.js.map +1 -1
  62. package/dist/engine/renderers/Indicator/dema.js +3 -11
  63. package/dist/engine/renderers/Indicator/dema.js.map +1 -1
  64. package/dist/engine/renderers/Indicator/donchian.js +3 -11
  65. package/dist/engine/renderers/Indicator/donchian.js.map +1 -1
  66. package/dist/engine/renderers/Indicator/ene.d.ts.map +1 -1
  67. package/dist/engine/renderers/Indicator/ene.js +12 -24
  68. package/dist/engine/renderers/Indicator/ene.js.map +1 -1
  69. package/dist/engine/renderers/Indicator/expma.d.ts.map +1 -1
  70. package/dist/engine/renderers/Indicator/expma.js +5 -11
  71. package/dist/engine/renderers/Indicator/expma.js.map +1 -1
  72. package/dist/engine/renderers/Indicator/fastk.js +6 -13
  73. package/dist/engine/renderers/Indicator/fastk.js.map +1 -1
  74. package/dist/engine/renderers/Indicator/fib.js +3 -11
  75. package/dist/engine/renderers/Indicator/fib.js.map +1 -1
  76. package/dist/engine/renderers/Indicator/hma.js +3 -11
  77. package/dist/engine/renderers/Indicator/hma.js.map +1 -1
  78. package/dist/engine/renderers/Indicator/hv.js +3 -11
  79. package/dist/engine/renderers/Indicator/hv.js.map +1 -1
  80. package/dist/engine/renderers/Indicator/ichimoku.js +24 -18
  81. package/dist/engine/renderers/Indicator/ichimoku.js.map +1 -1
  82. package/dist/engine/renderers/Indicator/kama.js +3 -11
  83. package/dist/engine/renderers/Indicator/kama.js.map +1 -1
  84. package/dist/engine/renderers/Indicator/keltner.js +3 -11
  85. package/dist/engine/renderers/Indicator/keltner.js.map +1 -1
  86. package/dist/engine/renderers/Indicator/kst.js +9 -17
  87. package/dist/engine/renderers/Indicator/kst.js.map +1 -1
  88. package/dist/engine/renderers/Indicator/ma.d.ts.map +1 -1
  89. package/dist/engine/renderers/Indicator/ma.js +10 -21
  90. package/dist/engine/renderers/Indicator/ma.js.map +1 -1
  91. package/dist/engine/renderers/Indicator/macd.js +14 -44
  92. package/dist/engine/renderers/Indicator/macd.js.map +1 -1
  93. package/dist/engine/renderers/Indicator/mfi.js +3 -11
  94. package/dist/engine/renderers/Indicator/mfi.js.map +1 -1
  95. package/dist/engine/renderers/Indicator/mom.js +6 -13
  96. package/dist/engine/renderers/Indicator/mom.js.map +1 -1
  97. package/dist/engine/renderers/Indicator/obv.js +3 -11
  98. package/dist/engine/renderers/Indicator/obv.js.map +1 -1
  99. package/dist/engine/renderers/Indicator/parkinson.js +3 -11
  100. package/dist/engine/renderers/Indicator/parkinson.js.map +1 -1
  101. package/dist/engine/renderers/Indicator/pvt.js +3 -11
  102. package/dist/engine/renderers/Indicator/pvt.js.map +1 -1
  103. package/dist/engine/renderers/Indicator/roc.js +3 -11
  104. package/dist/engine/renderers/Indicator/roc.js.map +1 -1
  105. package/dist/engine/renderers/Indicator/rsi.js +12 -20
  106. package/dist/engine/renderers/Indicator/rsi.js.map +1 -1
  107. package/dist/engine/renderers/Indicator/shared/webglBand.d.ts +0 -2
  108. package/dist/engine/renderers/Indicator/shared/webglBand.d.ts.map +1 -1
  109. package/dist/engine/renderers/Indicator/shared/webglBand.js +0 -6
  110. package/dist/engine/renderers/Indicator/shared/webglBand.js.map +1 -1
  111. package/dist/engine/renderers/Indicator/stoch.js +9 -17
  112. package/dist/engine/renderers/Indicator/stoch.js.map +1 -1
  113. package/dist/engine/renderers/Indicator/tema.js +3 -11
  114. package/dist/engine/renderers/Indicator/tema.js.map +1 -1
  115. package/dist/engine/renderers/Indicator/trix.js +3 -11
  116. package/dist/engine/renderers/Indicator/trix.js.map +1 -1
  117. package/dist/engine/renderers/Indicator/vma.js +3 -11
  118. package/dist/engine/renderers/Indicator/vma.js.map +1 -1
  119. package/dist/engine/renderers/Indicator/vwap.js +3 -11
  120. package/dist/engine/renderers/Indicator/vwap.js.map +1 -1
  121. package/dist/engine/renderers/Indicator/wma.js +3 -11
  122. package/dist/engine/renderers/Indicator/wma.js.map +1 -1
  123. package/dist/engine/renderers/Indicator/wmsr.js +6 -13
  124. package/dist/engine/renderers/Indicator/wmsr.js.map +1 -1
  125. package/dist/engine/renderers/candle.d.ts.map +1 -1
  126. package/dist/engine/renderers/candle.js +21 -28
  127. package/dist/engine/renderers/candle.js.map +1 -1
  128. package/dist/engine/renderers/candleViaRenderer.d.ts +19 -0
  129. package/dist/engine/renderers/candleViaRenderer.d.ts.map +1 -0
  130. package/dist/engine/renderers/candleViaRenderer.js +15 -0
  131. package/dist/engine/renderers/candleViaRenderer.js.map +1 -0
  132. package/dist/engine/renderers/linesViaRenderer.d.ts +55 -0
  133. package/dist/engine/renderers/linesViaRenderer.d.ts.map +1 -0
  134. package/dist/engine/renderers/linesViaRenderer.js +169 -0
  135. package/dist/engine/renderers/linesViaRenderer.js.map +1 -0
  136. package/dist/engine/renderers/rectsViaRenderer.d.ts +18 -0
  137. package/dist/engine/renderers/rectsViaRenderer.d.ts.map +1 -0
  138. package/dist/engine/renderers/rectsViaRenderer.js +63 -0
  139. package/dist/engine/renderers/rectsViaRenderer.js.map +1 -0
  140. package/dist/engine/renderers/subVolume.js +7 -26
  141. package/dist/engine/renderers/subVolume.js.map +1 -1
  142. package/dist/engine/renderers/timeAxis.js +1 -1
  143. package/dist/engine/renderers/timeAxis.js.map +1 -1
  144. package/dist/engine/state/chartStateKernel.d.ts +11 -2
  145. package/dist/engine/state/chartStateKernel.d.ts.map +1 -1
  146. package/dist/engine/state/chartStateKernel.js +28 -12
  147. package/dist/engine/state/chartStateKernel.js.map +1 -1
  148. package/dist/engine/state/index.d.ts +1 -1
  149. package/dist/engine/state/index.d.ts.map +1 -1
  150. package/dist/engine/state/index.js +1 -1
  151. package/dist/engine/state/index.js.map +1 -1
  152. package/dist/engine/state/interactionState.d.ts +15 -7
  153. package/dist/engine/state/interactionState.d.ts.map +1 -1
  154. package/dist/engine/state/interactionState.js +55 -60
  155. package/dist/engine/state/interactionState.js.map +1 -1
  156. package/dist/engine/state/rendererState.d.ts +14 -0
  157. package/dist/engine/state/rendererState.d.ts.map +1 -0
  158. package/dist/engine/state/rendererState.js +25 -0
  159. package/dist/engine/state/rendererState.js.map +1 -0
  160. package/dist/engine/state/themeState.d.ts +11 -4
  161. package/dist/engine/state/themeState.d.ts.map +1 -1
  162. package/dist/engine/state/themeState.js +13 -5
  163. package/dist/engine/state/themeState.js.map +1 -1
  164. package/dist/engine/state/viewportState.d.ts.map +1 -1
  165. package/dist/engine/state/viewportState.js +7 -3
  166. package/dist/engine/state/viewportState.js.map +1 -1
  167. package/dist/engine/subPaneManager.d.ts.map +1 -1
  168. package/dist/engine/subPaneManager.js +2 -10
  169. package/dist/engine/subPaneManager.js.map +1 -1
  170. package/dist/foundation/config/chartSettings.d.ts +16 -4
  171. package/dist/foundation/config/chartSettings.d.ts.map +1 -1
  172. package/dist/foundation/config/chartSettings.js +21 -6
  173. package/dist/foundation/config/chartSettings.js.map +1 -1
  174. package/dist/foundation/plugin/index.d.ts +0 -1
  175. package/dist/foundation/plugin/index.d.ts.map +1 -1
  176. package/dist/foundation/plugin/rendererPluginManager.d.ts +1 -22
  177. package/dist/foundation/plugin/rendererPluginManager.d.ts.map +1 -1
  178. package/dist/foundation/plugin/rendererPluginManager.js +0 -84
  179. package/dist/foundation/plugin/rendererPluginManager.js.map +1 -1
  180. package/dist/foundation/plugin/types.d.ts +11 -17
  181. package/dist/foundation/plugin/types.d.ts.map +1 -1
  182. package/dist/foundation/plugin/types.js.map +1 -1
  183. package/dist/foundation/reactivity/frameTransaction.d.ts +71 -0
  184. package/dist/foundation/reactivity/frameTransaction.d.ts.map +1 -0
  185. package/dist/foundation/reactivity/frameTransaction.js +170 -0
  186. package/dist/foundation/reactivity/frameTransaction.js.map +1 -0
  187. package/dist/foundation/reactivity/index.d.ts +4 -2
  188. package/dist/foundation/reactivity/index.d.ts.map +1 -1
  189. package/dist/foundation/reactivity/index.js +2 -1
  190. package/dist/foundation/reactivity/index.js.map +1 -1
  191. package/dist/foundation/reactivity/signal.d.ts +20 -0
  192. package/dist/foundation/reactivity/signal.d.ts.map +1 -1
  193. package/dist/foundation/reactivity/signal.js +27 -0
  194. package/dist/foundation/reactivity/signal.js.map +1 -1
  195. package/dist/foundation/tokens/theme-dark.d.ts.map +1 -1
  196. package/dist/foundation/tokens/theme-dark.js +2 -1
  197. package/dist/foundation/tokens/theme-dark.js.map +1 -1
  198. package/dist/foundation/tokens/theme-light.d.ts.map +1 -1
  199. package/dist/foundation/tokens/theme-light.js +2 -1
  200. package/dist/foundation/tokens/theme-light.js.map +1 -1
  201. package/dist/rendering/render/Renderer.d.ts +29 -14
  202. package/dist/rendering/render/Renderer.d.ts.map +1 -1
  203. package/dist/rendering/render/Renderer.js +3 -10
  204. package/dist/rendering/render/Renderer.js.map +1 -1
  205. package/dist/rendering/render/SurfaceBackend.d.ts +5 -7
  206. package/dist/rendering/render/SurfaceBackend.d.ts.map +1 -1
  207. package/dist/rendering/render/SurfaceBackend.js +5 -7
  208. package/dist/rendering/render/SurfaceBackend.js.map +1 -1
  209. package/dist/rendering/render/createCanvas2DRenderer.d.ts +3 -0
  210. package/dist/rendering/render/createCanvas2DRenderer.d.ts.map +1 -0
  211. package/dist/rendering/render/createCanvas2DRenderer.js +74 -0
  212. package/dist/rendering/render/createCanvas2DRenderer.js.map +1 -0
  213. package/dist/rendering/render/createDefaultRendererHost.d.ts +4 -0
  214. package/dist/rendering/render/createDefaultRendererHost.d.ts.map +1 -0
  215. package/dist/rendering/render/createDefaultRendererHost.js +54 -0
  216. package/dist/rendering/render/createDefaultRendererHost.js.map +1 -0
  217. package/dist/rendering/render/createWebGLRenderer.d.ts.map +1 -1
  218. package/dist/rendering/render/createWebGLRenderer.js +42 -80
  219. package/dist/rendering/render/createWebGLRenderer.js.map +1 -1
  220. package/dist/rendering/render/createWebGPURenderer.d.ts +11 -0
  221. package/dist/rendering/render/createWebGPURenderer.d.ts.map +1 -0
  222. package/dist/rendering/render/createWebGPURenderer.js +619 -0
  223. package/dist/rendering/render/createWebGPURenderer.js.map +1 -0
  224. package/dist/rendering/render/createWebGPUSurfaceBackend.d.ts +15 -0
  225. package/dist/rendering/render/createWebGPUSurfaceBackend.d.ts.map +1 -0
  226. package/dist/rendering/render/createWebGPUSurfaceBackend.js +92 -0
  227. package/dist/rendering/render/createWebGPUSurfaceBackend.js.map +1 -0
  228. package/dist/rendering/render/frameMetrics.d.ts +19 -0
  229. package/dist/rendering/render/frameMetrics.d.ts.map +1 -0
  230. package/dist/rendering/render/frameMetrics.js +43 -0
  231. package/dist/rendering/render/frameMetrics.js.map +1 -0
  232. package/dist/rendering/render/index.d.ts +10 -0
  233. package/dist/rendering/render/index.d.ts.map +1 -1
  234. package/dist/rendering/render/index.js +6 -0
  235. package/dist/rendering/render/index.js.map +1 -1
  236. package/dist/rendering/render/rendererHost.d.ts +34 -0
  237. package/dist/rendering/render/rendererHost.d.ts.map +1 -0
  238. package/dist/rendering/render/rendererHost.js +144 -0
  239. package/dist/rendering/render/rendererHost.js.map +1 -0
  240. package/dist/rendering/render/webgpuResourceTable.d.ts +25 -0
  241. package/dist/rendering/render/webgpuResourceTable.d.ts.map +1 -0
  242. package/dist/rendering/render/webgpuResourceTable.js +54 -0
  243. package/dist/rendering/render/webgpuResourceTable.js.map +1 -0
  244. package/dist/rendering/scene/createLayerFromPlugin.d.ts.map +1 -1
  245. package/dist/rendering/scene/createLayerFromPlugin.js +10 -2
  246. package/dist/rendering/scene/createLayerFromPlugin.js.map +1 -1
  247. package/dist/rendering/scene/layerRegistry.d.ts +3 -5
  248. package/dist/rendering/scene/layerRegistry.d.ts.map +1 -1
  249. package/dist/rendering/scene/layerRegistry.js +1 -1
  250. package/dist/rendering/scene/layerRegistry.js.map +1 -1
  251. package/dist/rendering/scene/retainedScene.d.ts +60 -0
  252. package/dist/rendering/scene/retainedScene.d.ts.map +1 -0
  253. package/dist/rendering/scene/retainedScene.js +42 -0
  254. package/dist/rendering/scene/retainedScene.js.map +1 -0
  255. package/dist/version.d.ts +1 -1
  256. package/dist/version.js +1 -1
  257. package/package.json +2 -1
  258. package/src/__tests__/signal.test.ts +47 -1
  259. package/src/controllers/__tests__/createChartController.theme.test.ts +102 -0
  260. package/src/controllers/createChartController.ts +36 -12
  261. package/src/controllers/index.ts +5 -0
  262. package/src/controllers/types.ts +14 -0
  263. package/src/engine/__tests__/chart.dpr.test.ts +64 -0
  264. package/src/engine/__tests__/paneRenderer.resize.test.ts +0 -7
  265. package/src/engine/__tests__/renderSinglePath.test.ts +121 -0
  266. package/src/engine/chart.ts +172 -25
  267. package/src/engine/controller/__tests__/interaction.dpr.test.ts +45 -41
  268. package/src/engine/controller/interaction.ts +81 -30
  269. package/src/engine/data/__tests__/chartDataManager.incrementalLoad.test.ts +1 -0
  270. package/src/engine/data/incrementalLoadHint.ts +6 -1
  271. package/src/engine/drawing/DrawingState.ts +107 -89
  272. package/src/engine/drawing/__tests__/drawingState.workCopy.test.ts +95 -36
  273. package/src/engine/drawing/__tests__/drawingStore.projection.test.ts +22 -0
  274. package/src/engine/drawing/index.ts +12 -4
  275. package/src/engine/drawing/interaction.ts +25 -40
  276. package/src/engine/indicators/chartIndicatorManager.ts +6 -16
  277. package/src/engine/layout/chartPaneLayout.ts +6 -11
  278. package/src/engine/layout/pane.ts +0 -44
  279. package/src/engine/paneRenderer.ts +3 -34
  280. package/src/engine/render/chartRenderer.ts +181 -81
  281. package/src/engine/renderers/Indicator/atr.ts +5 -17
  282. package/src/engine/renderers/Indicator/boll.ts +15 -26
  283. package/src/engine/renderers/Indicator/cci.ts +7 -17
  284. package/src/engine/renderers/Indicator/chaikinVol.ts +3 -15
  285. package/src/engine/renderers/Indicator/cmf.ts +3 -15
  286. package/src/engine/renderers/Indicator/dema.ts +3 -15
  287. package/src/engine/renderers/Indicator/donchian.ts +3 -12
  288. package/src/engine/renderers/Indicator/ene.ts +15 -25
  289. package/src/engine/renderers/Indicator/expma.ts +4 -13
  290. package/src/engine/renderers/Indicator/fastk.ts +7 -17
  291. package/src/engine/renderers/Indicator/fib.ts +3 -12
  292. package/src/engine/renderers/Indicator/hma.ts +3 -15
  293. package/src/engine/renderers/Indicator/hv.ts +3 -15
  294. package/src/engine/renderers/Indicator/ichimoku.ts +21 -24
  295. package/src/engine/renderers/Indicator/kama.ts +3 -15
  296. package/src/engine/renderers/Indicator/keltner.ts +3 -12
  297. package/src/engine/renderers/Indicator/kst.ts +9 -20
  298. package/src/engine/renderers/Indicator/ma.ts +9 -21
  299. package/src/engine/renderers/Indicator/macd.ts +27 -102
  300. package/src/engine/renderers/Indicator/mfi.ts +3 -15
  301. package/src/engine/renderers/Indicator/mom.ts +7 -17
  302. package/src/engine/renderers/Indicator/obv.ts +3 -15
  303. package/src/engine/renderers/Indicator/parkinson.ts +3 -15
  304. package/src/engine/renderers/Indicator/pvt.ts +3 -15
  305. package/src/engine/renderers/Indicator/roc.ts +3 -15
  306. package/src/engine/renderers/Indicator/rsi.ts +12 -23
  307. package/src/engine/renderers/Indicator/shared/webglBand.ts +0 -13
  308. package/src/engine/renderers/Indicator/stoch.ts +9 -20
  309. package/src/engine/renderers/Indicator/tema.ts +3 -15
  310. package/src/engine/renderers/Indicator/trix.ts +3 -12
  311. package/src/engine/renderers/Indicator/vma.ts +3 -15
  312. package/src/engine/renderers/Indicator/vwap.ts +3 -15
  313. package/src/engine/renderers/Indicator/wma.ts +3 -15
  314. package/src/engine/renderers/Indicator/wmsr.ts +7 -17
  315. package/src/engine/renderers/__tests__/candle.sceneRenderer.test.ts +208 -0
  316. package/src/engine/renderers/__tests__/candleViaRenderer.test.ts +100 -0
  317. package/src/engine/renderers/__tests__/linesViaRenderer.test.ts +263 -0
  318. package/src/engine/renderers/__tests__/rectsViaRenderer.test.ts +87 -0
  319. package/src/engine/renderers/candle.ts +26 -69
  320. package/src/engine/renderers/candleViaRenderer.ts +38 -0
  321. package/src/engine/renderers/linesViaRenderer.ts +226 -0
  322. package/src/engine/renderers/rectsViaRenderer.ts +83 -0
  323. package/src/engine/renderers/subVolume.ts +9 -61
  324. package/src/engine/renderers/timeAxis.ts +1 -1
  325. package/src/engine/state/__tests__/effectiveTheme.test.ts +49 -0
  326. package/src/engine/state/__tests__/rendererState.test.ts +36 -0
  327. package/src/engine/state/__tests__/settingsState.test.ts +1 -1
  328. package/src/engine/state/chartStateKernel.ts +38 -17
  329. package/src/engine/state/index.ts +6 -1
  330. package/src/engine/state/interactionState.ts +73 -102
  331. package/src/engine/state/rendererState.ts +32 -0
  332. package/src/engine/state/themeState.ts +15 -8
  333. package/src/engine/state/viewportState.ts +6 -3
  334. package/src/engine/subPaneManager.ts +2 -16
  335. package/src/foundation/config/__tests__/chartSettings.test.ts +25 -0
  336. package/src/foundation/config/chartSettings.ts +24 -7
  337. package/src/foundation/plugin/index.ts +0 -1
  338. package/src/foundation/plugin/rendererPluginManager.ts +0 -99
  339. package/src/foundation/plugin/types.ts +11 -18
  340. package/src/foundation/reactivity/__tests__/frameTransaction.test.ts +306 -0
  341. package/src/foundation/reactivity/frameTransaction.ts +239 -0
  342. package/src/foundation/reactivity/index.ts +8 -0
  343. package/src/foundation/reactivity/signal.ts +39 -0
  344. package/src/foundation/tokens/__tests__/__snapshots__/baseline.test.ts.snap +2 -2
  345. package/src/foundation/tokens/theme-dark.ts +2 -1
  346. package/src/foundation/tokens/theme-light.ts +2 -1
  347. package/src/rendering/render/Renderer.ts +27 -14
  348. package/src/rendering/render/SurfaceBackend.ts +5 -7
  349. package/src/rendering/render/__tests__/canvas2DRenderer.test.ts +34 -0
  350. package/src/rendering/render/__tests__/contract.test.ts +2 -2
  351. package/src/rendering/render/__tests__/frameMetrics.test.ts +24 -0
  352. package/src/rendering/render/__tests__/rendererHost.test.ts +157 -0
  353. package/src/rendering/render/__tests__/webglRenderer.fallback.test.ts +14 -74
  354. package/src/rendering/render/__tests__/webglRenderer.test.ts +64 -6
  355. package/src/rendering/render/__tests__/webgpuRenderer.test.ts +370 -0
  356. package/src/rendering/render/__tests__/webgpuResourceTable.test.ts +62 -0
  357. package/src/rendering/render/__tests__/webgpuSurfaceBackend.test.ts +120 -0
  358. package/src/rendering/render/createCanvas2DRenderer.ts +83 -0
  359. package/src/rendering/render/createDefaultRendererHost.ts +74 -0
  360. package/src/rendering/render/createWebGLRenderer.ts +41 -87
  361. package/src/rendering/render/createWebGPURenderer.ts +677 -0
  362. package/src/rendering/render/createWebGPUSurfaceBackend.ts +106 -0
  363. package/src/rendering/render/frameMetrics.ts +54 -0
  364. package/src/rendering/render/index.ts +30 -0
  365. package/src/rendering/render/rendererHost.ts +210 -0
  366. package/src/rendering/render/webgpuResourceTable.ts +87 -0
  367. package/src/rendering/scene/__tests__/layerFromPlugin.test.ts +29 -2
  368. package/src/rendering/scene/__tests__/retainedScene.test.ts +59 -0
  369. package/src/rendering/scene/createLayerFromPlugin.ts +9 -2
  370. package/src/rendering/scene/layerRegistry.ts +4 -6
  371. package/src/rendering/scene/retainedScene.ts +101 -0
  372. 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 usedWebGL = drawVolumeWithWebGL(
168
+ const usedGpu = tryDrawRectsGpu(
168
169
  context,
169
- upBuf,
170
- upCount,
171
- downBuf,
172
- downCount,
173
- neutralBuf,
174
- neutralCount,
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 (!usedWebGL) {
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, // 系统渲染器,只能通过 renderPlugin 单独渲染
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().enableWebGLRendering).toBeDefined()
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 { createThemeState, type ThemeStateModule } from './themeState'
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
- readonly theme: ThemeStateModule
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
- // ── Theme state ──
140
- this.theme = createThemeState()
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
- // ── Settings state(用户偏好 SSOT;rightAxisType 副作用走 Chart.updateSettings)──
143
- this.settings = createSettingsState()
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.theme.readonly.theme,
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.theme.actions.setTheme(theme),
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: (pos: { x: number; y: number } | null, price: number | null) =>
237
- this.interaction.actions.updateCrosshair(pos, price),
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 { createThemeState, type ThemeStateModule } from './themeState'
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'