@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
@@ -1,6 +1,4 @@
1
1
  import type { PaneRendererDom } from './chartTypes'
2
- import { CandleWebGLSurface, LineWebGLSurface } from './renderers/webgl/candleSurface'
3
- import type { SharedWebGLSurface, WebGLRegion } from './renderers/webgl/sharedWebGLSurface'
4
2
 
5
3
  export type { PaneRendererDom }
6
4
 
@@ -18,39 +16,24 @@ export type PaneRendererOptions = {
18
16
  priceLabelWidth?: number
19
17
  }
20
18
 
21
- export type PaneRendererWebGLHandles = {
22
- candleSurface: CandleWebGLSurface | null
23
- lineSurface: LineWebGLSurface | null
24
- }
25
-
26
19
  /* PaneRenderer:负责单个 Pane 的 Canvas 管理与运行时状态持有
27
20
  创建并管理 mainCanvas / overlayCanvas / yAxisCanvas
28
21
  持有 Pane 实例(布局、Y 轴、价格范围)
29
22
  响应 Chart 的 resize / layout 信号
30
- 渲染逻辑由 RendererPluginManager 统一调度 */
23
+ GPU 绘制经 ChartRenderer.sceneRenderer(SharedWebGLSurface),本类不再持有 per-pane surface */
31
24
  export class PaneRenderer {
32
25
  private dom: PaneRendererDom
33
26
  private pane: import('./layout/pane').Pane
34
27
  private opt: PaneRendererOptions
35
28
  private contexts: PaneRendererContexts | null = null
36
- private webgl: PaneRendererWebGLHandles
37
-
38
- constructor(
39
- dom: PaneRendererDom,
40
- pane: import('./layout/pane').Pane,
41
- opt: PaneRendererOptions,
42
- sharedWebGLSurface: SharedWebGLSurface,
43
- ) {
29
+
30
+ constructor(dom: PaneRendererDom, pane: import('./layout/pane').Pane, opt: PaneRendererOptions) {
44
31
  this.dom = dom
45
32
  this.pane = pane
46
33
  this.opt = {
47
34
  ...opt,
48
35
  priceLabelWidth: opt.priceLabelWidth || 60,
49
36
  }
50
- this.webgl = {
51
- candleSurface: new CandleWebGLSurface(sharedWebGLSurface),
52
- lineSurface: new LineWebGLSurface(sharedWebGLSurface),
53
- }
54
37
  }
55
38
 
56
39
  /** 获取关联的 Pane 实例 */
@@ -97,15 +80,6 @@ export class PaneRenderer {
97
80
  }
98
81
  }
99
82
 
100
- getWebGL(): PaneRendererWebGLHandles {
101
- return this.webgl
102
- }
103
-
104
- setWebGLRegion(region: WebGLRegion): void {
105
- this.webgl.candleSurface?.setRegion(region)
106
- this.webgl.lineSurface?.setRegion(region)
107
- }
108
-
109
83
  /**
110
84
  * 调整 Canvas 尺寸
111
85
  * @param width pane 宽度(逻辑像素)
@@ -147,15 +121,10 @@ export class PaneRenderer {
147
121
  dpr,
148
122
  )
149
123
  }
150
-
151
- this.webgl.candleSurface?.resize(width, height, dpr)
152
- this.webgl.lineSurface?.resize(width, height, dpr)
153
124
  }
154
125
 
155
126
  /** 销毁 PaneRenderer 实例 */
156
127
  destroy() {
157
128
  this.contexts = null
158
- this.webgl.candleSurface?.destroy()
159
- this.webgl.lineSurface?.destroy()
160
129
  }
161
130
  }
@@ -10,7 +10,6 @@ import type {
10
10
  YAxisTick,
11
11
  } from '../../foundation/plugin/index'
12
12
  import { RendererPluginManager, wrapPaneInfo } from '../../foundation/plugin/index'
13
- import { createWebGLRenderer, createWebGLSurfaceBackend } from '../../rendering/render/index'
14
13
  import type { Renderer } from '../../rendering/render/Renderer'
15
14
  import { createLayerFromPlugin } from '../../rendering/scene/createLayerFromPlugin'
16
15
  import { createScene } from '../../rendering/scene/createScene'
@@ -39,7 +38,6 @@ import {
39
38
  import type { ChartModeHandler } from '../modes/types'
40
39
  import { PaneRenderer } from '../paneRenderer'
41
40
  import { createTimeAxisRendererPlugin } from '../renderers/timeAxis'
42
- import { SharedWebGLSurface } from '../renderers/webgl/sharedWebGLSurface'
43
41
  import { getPhysicalKLineConfig } from '../utils/klineConfig'
44
42
  import { calculateTickCount } from '../utils/tickCount'
45
43
  import { ChartViewportManager } from '../viewport/chartViewportManager'
@@ -56,34 +54,75 @@ import { createLastPriceLineLayer } from './layers/lastPriceLineLayer'
56
54
  import { createLeftYAxisLayer } from './layers/leftYAxisLayer'
57
55
  import { createMainIndicatorLegendLayer } from './layers/mainIndicatorLegendLayer'
58
56
  import { createYAxisLayer } from './layers/yAxisLayer'
59
- import { batch, type ReadonlySignal } from '../../foundation/reactivity/signal'
57
+ import { createFrameTransaction } from '../../foundation/reactivity/frameTransaction'
58
+ import type { ReadonlySignal } from '../../foundation/reactivity/signal'
60
59
 
61
60
  type ResolvedChartOptions = Omit<ChartOptions, 'kWidth' | 'kGap'> & {
62
61
  kWidth: number
63
62
  kGap: number
64
63
  }
65
64
 
65
+ /**
66
+ * 一帧绘制几何与数据(prepare 产出,render 只读)。
67
+ * 大数组字段做结构共享,禁止深拷贝。
68
+ */
66
69
  type FrameContext = {
70
+ /** 视口(scrollLeft、plotWidth、dpr 等) */
67
71
  vp: Viewport
72
+ /** 可见 K 线起止索引 */
68
73
  range: VisibleRange
74
+ /** 每根 K 线在大图上的 x 坐标 */
69
75
  kLinePositions: KLinePositions
76
+ /** 每根 K 线中心的 x 坐标(由物理像素回算逻辑值) */
70
77
  kLineCenters: number[]
78
+ /** 每根 K 线实体的 x 和宽度 */
71
79
  kBarRects: Array<{ x: number; width: number }>
80
+ /** K 线柱物理像素宽度 */
72
81
  kWidthPx: number
82
+ /** Overlay 帧复用上一帧的几何缓存 */
73
83
  useCachedFrame: boolean
84
+ /** 原始 K 线数据 */
74
85
  data: KLineData[]
75
- mainIndicatorRange: { min: number; max: number } | null
76
- hasCrosshair: boolean
86
+ /** 当前缩放级别索引 */
77
87
  zoomLevel: number
88
+ /** 缩放级别总数 */
78
89
  zoomLevelCount: number
79
90
  }
80
91
 
92
+ /** 帧事务输入:仅重绘级别;多次 schedule 浅合并后由 mergeUpdateLevel 升格 */
93
+ type FrameDrawInput = {
94
+ level: UpdateLevel
95
+ }
96
+
97
+ /**
98
+ * 帧事务快照:单代际绘制契约。
99
+ * generation 由 FrameTransaction 写入;frame 为 null 表示无可画数据。
100
+ */
101
+ type FrameDrawSnapshot = {
102
+ generation: number
103
+ level: UpdateLevel
104
+ frame: FrameContext | null
105
+ }
106
+
107
+ /** Main 与 Overlay 合并为 All,其余取更全或后者 */
108
+ function mergeUpdateLevel(current: UpdateLevel, next: UpdateLevel): UpdateLevel {
109
+ if (current === UpdateLevel.All || next === UpdateLevel.All) return UpdateLevel.All
110
+ if (current === next) return current
111
+ if (
112
+ (current === UpdateLevel.Main && next === UpdateLevel.Overlay) ||
113
+ (current === UpdateLevel.Overlay && next === UpdateLevel.Main)
114
+ ) {
115
+ return UpdateLevel.All
116
+ }
117
+ return next
118
+ }
119
+
81
120
  export interface RendererDependencies {
82
121
  getDom: () => ChartDom
83
122
  getOption: () => ResolvedChartOptions
84
123
  getPaneRenderers: () => PaneRenderer[]
85
124
  getInteraction: () => InteractionController
86
- getSharedWebGLSurface: () => SharedWebGLSurface
125
+ getSceneRenderer: () => Renderer
87
126
  getPluginHost: () => PluginHostImpl
88
127
  getRendererPluginManager: () => RendererPluginManager
89
128
  getTheme: () => 'light' | 'dark'
@@ -97,13 +136,29 @@ export interface RendererDependencies {
97
136
  customMarkers$: MarkerManagerDeps['customMarkers$']
98
137
  drawings$: DrawingStoreDeps['drawings$']
99
138
  selectedDrawingId$: DrawingStoreDeps['selectedDrawingId$']
139
+ getOverlay?: DrawingStoreDeps['getOverlay']
100
140
  }
101
141
 
102
142
  export class ChartRenderer {
143
+ /** 依赖注入容器,ChartRenderer 不直接持有状态,从 deps 接口读取,也便于测试 mock */
103
144
  private deps: RendererDependencies
104
145
 
146
+ /**
147
+ * 帧事务:scheduleDraw 只写输入并合并 rAF;flush 内 prepare → seal → paint。
148
+ * 绘制阶段不再反向写 kernel 几何(seal 在 render 回调最前、与 paint 同代)。
149
+ */
150
+ private readonly frameTx: ReturnType<
151
+ typeof createFrameTransaction<FrameDrawInput, FrameDrawSnapshot>
152
+ >
153
+
154
+ /**
155
+ * 与 frameTx pending 同步的重绘级别镜像。
156
+ * FrameTransaction 对 level 是浅覆盖,Main/Overlay 升格在此完成。
157
+ */
158
+ private pendingLevel: UpdateLevel = UpdateLevel.All
159
+
160
+ /** 已排队的 rAF 句柄;null 表示当前没有挂起的帧调度 */
105
161
  private raf: number | null = null
106
- private pendingUpdateLevel: UpdateLevel = UpdateLevel.All
107
162
 
108
163
  readonly markerManager: MarkerManager
109
164
  readonly drawingStore: DrawingStore
@@ -123,7 +178,6 @@ export class ChartRenderer {
123
178
  private frameCount = 0
124
179
  private paneCtxMap = new Map<string, RenderContext>()
125
180
  private currentPaneId = 'main'
126
- private sceneRenderer: Renderer = {} as Renderer
127
181
  private timeAxisCtx: RenderContext | null = null
128
182
  private timeAxisLayer: Layer | null = null
129
183
  private _prevFrameRange: { visible: VisibleRange; raw: VisibleRange } | null = null
@@ -134,11 +188,44 @@ export class ChartRenderer {
134
188
  this.drawingStore = new DrawingStore({
135
189
  drawings$: deps.drawings$,
136
190
  selectedDrawingId$: deps.selectedDrawingId$,
191
+ getOverlay: deps.getOverlay,
137
192
  })
138
193
  this.scene = createScene()
139
- const sharedSurface = deps.getSharedWebGLSurface()
140
- const surfaceBackend = createWebGLSurfaceBackend(sharedSurface)
141
- this.sceneRenderer = createWebGLRenderer(surfaceBackend, sharedSurface)
194
+ this.frameTx = createFrameTransaction<FrameDrawInput, FrameDrawSnapshot>({
195
+ initialInput: { level: UpdateLevel.All },
196
+ derive: (input, generation) => {
197
+ // generation 0 是 createFrameTransaction 构造占位,禁止 prepare/副作用
198
+ if (generation === 0) {
199
+ return { generation: 0, level: input.level, frame: null }
200
+ }
201
+ return {
202
+ generation,
203
+ level: input.level,
204
+ frame: this.prepareFrameData(input.level),
205
+ }
206
+ },
207
+ render: (snapshot) => {
208
+ // generation 0 占位不绘制
209
+ if (snapshot.generation === 0) return
210
+ // seal 几何 → flush hover(同代)→ paint;禁止 paint 中途再写 kernel 几何
211
+ if (snapshot.frame) {
212
+ this.sealFrameGeometry(snapshot.frame)
213
+ }
214
+ this.deps.getInteraction().flushPendingHover()
215
+ this.drawWithFrame(snapshot.level, snapshot.frame)
216
+ },
217
+ schedule: (run) => {
218
+ this.raf = requestAnimationFrame(() => {
219
+ this.raf = null
220
+ run()
221
+ // 若 paint 中又 scheduleDraw,已写入新 pendingLevel 且 raf 非 null,不得清掉
222
+ if (this.raf === null) {
223
+ this.pendingLevel = UpdateLevel.All
224
+ }
225
+ })
226
+ return this.raf
227
+ },
228
+ })
142
229
  }
143
230
 
144
231
  initCoreRenderers(): void {
@@ -260,14 +347,12 @@ export class ChartRenderer {
260
347
  {
261
348
  const plugin = createDrawingRendererPlugin({ store: this.drawingStore })
262
349
  this.deps.getRendererPluginManager().register(plugin)
263
- this.deps.getRendererPluginManager().setEnabled(plugin.name, false)
264
350
  const layer = createLayerFromPlugin(plugin, getCtxForCurrentPane, 'global')
265
351
  this.scene.addLayer(layer)
266
352
  }
267
353
  {
268
354
  const plugin = createDrawingLabelOverlayPlugin({ store: this.drawingStore })
269
355
  this.deps.getRendererPluginManager().register(plugin)
270
- this.deps.getRendererPluginManager().setEnabled(plugin.name, false)
271
356
  const layer = createLayerFromPlugin(plugin, getCtxForCurrentPane, 'global')
272
357
  this.scene.addLayer(layer)
273
358
  }
@@ -281,6 +366,10 @@ export class ChartRenderer {
281
366
  return this.paneCtxMap
282
367
  }
283
368
 
369
+ getCurrentPaneId(): string {
370
+ return this.currentPaneId
371
+ }
372
+
284
373
  getMarkerManager(): MarkerManager {
285
374
  return this.markerManager
286
375
  }
@@ -297,43 +386,62 @@ export class ChartRenderer {
297
386
  return this.deps.settings$.peek()
298
387
  }
299
388
 
389
+ /**
390
+ * 申请绘制:合并重绘级别并写入帧事务,由 rAF 最多 flush 一次。
391
+ *
392
+ * 已有调度时只更新 pending level(Main+Overlay→All),不重复注册 rAF。
393
+ * flush 内:prepareFrameData → sealFrameGeometry → drawWithFrame。
394
+ *
395
+ * @param level - Main 只画主层,Overlay 只画覆盖层(crosshair 等),All 全画
396
+ */
300
397
  scheduleDraw(level: UpdateLevel = UpdateLevel.All): void {
301
398
  if (this.raf !== null) {
302
- if (this.pendingUpdateLevel === UpdateLevel.All) return
303
- if (level === UpdateLevel.All) {
304
- this.pendingUpdateLevel = UpdateLevel.All
305
- return
306
- }
307
- if (
308
- (this.pendingUpdateLevel === UpdateLevel.Main && level === UpdateLevel.Overlay) ||
309
- (this.pendingUpdateLevel === UpdateLevel.Overlay && level === UpdateLevel.Main)
310
- ) {
311
- this.pendingUpdateLevel = UpdateLevel.All
312
- return
313
- }
399
+ this.pendingLevel = mergeUpdateLevel(this.pendingLevel, level)
400
+ this.frameTx.writeInput({ level: this.pendingLevel })
314
401
  return
315
402
  }
403
+ this.pendingLevel = level
404
+ this.frameTx.writeInput({ level })
405
+ this.frameTx.scheduleFlush()
406
+ }
316
407
 
317
- this.pendingUpdateLevel = level
318
- this.raf = requestAnimationFrame(() => {
319
- const levelToDraw = this.pendingUpdateLevel
320
- this.pendingUpdateLevel = UpdateLevel.All
321
-
322
- const frame = this.prepareFrameData(levelToDraw)
323
- if (frame) {
324
- this.writeFramePositionsFromFrame(frame)
325
- }
326
- this.drawWithFrame(levelToDraw, frame)
408
+ /**
409
+ * 同步绘制一帧,走与 rAF 相同的 flush 管线(prepare → seal → paint)。
410
+ *
411
+ * 若已有 rAF 挂起:与 pendingLevel 合并后同步 flush(消费合并后的 level)。
412
+ * 若正处于帧事务非 idle(render/publish 重入):只写输入并调度下一帧,禁止嵌套 flush。
413
+ *
414
+ * @param level - 同 scheduleDraw
415
+ */
416
+ draw(level: UpdateLevel = UpdateLevel.All): void {
417
+ if (this.frameTx.phase !== 'idle') {
418
+ this.pendingLevel = mergeUpdateLevel(this.pendingLevel, level)
419
+ this.frameTx.writeInput({ level: this.pendingLevel })
420
+ this.frameTx.scheduleFlush()
421
+ return
422
+ }
327
423
 
328
- this.raf = null
329
- if (this.pendingUpdateLevel !== UpdateLevel.All) {
330
- this.scheduleDraw(this.pendingUpdateLevel)
331
- }
332
- })
424
+ if (this.raf !== null) {
425
+ this.pendingLevel = mergeUpdateLevel(this.pendingLevel, level)
426
+ } else {
427
+ this.pendingLevel = level
428
+ }
429
+ this.frameTx.writeInput({ level: this.pendingLevel })
430
+ this.frameTx.flush()
431
+ // 同步 flush 已消费本帧;若 flush 中又 scheduleDraw,raf 非 null,保留 pendingLevel
432
+ if (this.raf === null) {
433
+ this.pendingLevel = UpdateLevel.All
434
+ }
333
435
  }
334
436
 
335
- draw(level: UpdateLevel = UpdateLevel.All): void {
336
- this.drawWithFrame(level, this.prepareFrameData(level))
437
+ /**
438
+ * 将本帧几何封存到 interaction,供 hover 二分与十字线重算读取。
439
+ * 在 paint 之前调用;引用未变时 interaction 侧应跳过 signal 通知。
440
+ */
441
+ private sealFrameGeometry(frame: FrameContext): void {
442
+ this.deps
443
+ .getInteraction()
444
+ .setKLinePositions(frame.kLinePositions, frame.range, frame.kWidthPx, frame.kLineCenters)
337
445
  }
338
446
 
339
447
  private drawWithFrame(level: UpdateLevel, frame: FrameContext | null): void {
@@ -394,19 +502,17 @@ export class ChartRenderer {
394
502
  )
395
503
  }
396
504
 
397
- /** 在 draw() 之前单独写入帧数据到 interactionState,分离状态变更与渲染 */
398
- private writeFramePositions(level: UpdateLevel): void {
399
- const frame = this.prepareFrameData(level)
400
- if (!frame) return
401
- this.writeFramePositionsFromFrame(frame)
402
- }
403
-
404
- private writeFramePositionsFromFrame(frame: FrameContext): void {
405
- batch(() => {
406
- this.deps.getInteraction().setKLinePositions(frame.kLinePositions, frame.range, frame.kWidthPx, frame.kLineCenters)
407
- })
408
- }
409
-
505
+ /**
506
+ * 准备一帧的绘制数据:viewport、可见区间、K 线位置。
507
+ *
508
+ * Overlay 且上次画完没清缓存时,直接复用 cachedDrawFrame,不重复
509
+ * 算 viewport 和 bar 位置。非缓存路径会刷新 cachedDrawFrame。
510
+ * range 变了会调用 checkVisibleRangeGapWhenIdle,方便空闲时补数据。
511
+ * TimeShare 模式按 plotWidth 平分 bar,不走 K 线物理宽度那套。
512
+ *
513
+ * @param level - Overlay 可走缓存,Main/All 强制重算
514
+ * @returns viewport 或无数据时返回 null,调用方自己清屏或跳过
515
+ */
410
516
  private prepareFrameData(level: UpdateLevel): FrameContext | null {
411
517
  const useCachedFrame = level === UpdateLevel.Overlay && this.cachedDrawFrame !== null
412
518
 
@@ -525,8 +631,6 @@ export class ChartRenderer {
525
631
  kWidthPx,
526
632
  useCachedFrame,
527
633
  data: internalData,
528
- mainIndicatorRange: null,
529
- hasCrosshair: false,
530
634
  zoomLevel: this.deps.getCurrentZoomLevel(),
531
635
  zoomLevelCount: this.deps.getZoomLevelCount(),
532
636
  }
@@ -566,6 +670,17 @@ export class ChartRenderer {
566
670
  const xH = xCtx.canvas.height
567
671
  xCtx.clearRect(0, 0, xW, xH)
568
672
  }
673
+ // M2 hybrid:可见 WebGPU canvas 不经 2D clearRect,需显式 transparent clear
674
+ const scene = this.deps.getSceneRenderer()
675
+ if (scene.caps.name === 'webgpu') {
676
+ scene.surface.clearRegion({
677
+ x: 0,
678
+ y: 0,
679
+ width: vp.plotWidth,
680
+ height: vp.plotHeight,
681
+ dpr: vp.dpr,
682
+ })
683
+ }
569
684
  }
570
685
 
571
686
  private renderPanes(
@@ -587,14 +702,11 @@ export class ChartRenderer {
587
702
  const sharedXAxisRanges: XAxisRange[] = []
588
703
 
589
704
  const dataManager = this.deps.getDataManager()
590
- const rendererPluginManager = this.deps.getRendererPluginManager()
591
- const pluginHost = this.deps.getPluginHost()
592
705
  const mode = this.deps.getActiveMode()
593
706
 
594
707
  for (const renderer of this.deps.getPaneRenderers()) {
595
708
  const pane = renderer.getPane()
596
709
  const { mainCtx, overlayCtx, yAxisCtx, leftAxisCtx } = renderer.getContexts()
597
- const { candleSurface, lineSurface } = renderer.getWebGL()
598
710
 
599
711
  if (!useCachedFrame) {
600
712
  const indicatorRange =
@@ -617,8 +729,6 @@ export class ChartRenderer {
617
729
  mainCtx.setTransform(1, 0, 0, 1, 0, 0)
618
730
  mainCtx.scale(vp.dpr, vp.dpr)
619
731
  mainCtx.clearRect(0, 0, vp.plotWidth + 1, pane.height + 2 / vp.dpr)
620
- candleSurface?.clear()
621
- lineSurface?.clear()
622
732
  }
623
733
 
624
734
  if (shouldUpdateOverlay && overlayCtx) {
@@ -660,8 +770,6 @@ export class ChartRenderer {
660
770
  crosshairIndex: this.deps.getInteraction().getCrosshairIndex(),
661
771
  yAxisCtx: yAxisCtx ?? undefined,
662
772
  leftAxisCtx: leftAxisCtx ?? undefined,
663
- candleWebGLSurface: candleSurface ?? undefined,
664
- lineWebGLSurface: lineSurface ?? undefined,
665
773
  zoomLevel: this.deps.getCurrentZoomLevel(),
666
774
  zoomLevelCount: this.deps.getZoomLevelCount(),
667
775
  viewport: {
@@ -701,33 +809,24 @@ export class ChartRenderer {
701
809
  this.paneCtxMap.set(pane.id, context)
702
810
  this.currentPaneId = pane.id
703
811
 
704
- if (shouldUpdateMain || shouldUpdateOverlay) {
705
- const errors = rendererPluginManager.render(pane.id, context, level)
706
- if (errors.length > 0) {
707
- pluginHost.events.emit('renderer:error', { paneId: pane.id, errors })
708
- }
709
- }
710
-
711
812
  const region = { x: 0, y: pane.top, width: vp.plotWidth, height: pane.height, dpr: vp.dpr }
813
+ const sceneRenderer = this.deps.getSceneRenderer()
712
814
  if (shouldUpdateMain) {
713
- this.sceneRenderer.beginFrame(region)
714
- ;(this.sceneRenderer as any).setFallbackContext(overlayCtx ?? null, vp.dpr)
815
+ sceneRenderer.beginFrame(region)
715
816
  this.scene.paintPane({
716
- renderer: this.sceneRenderer,
817
+ renderer: sceneRenderer,
717
818
  region,
718
819
  paneRole: (pane.id === 'main' ? 'main' : 'sub') as PaneRole,
719
820
  paneId: pane.id,
720
821
  frameNumber: this.frameCount++,
721
822
  deltaMs: 0,
722
823
  })
723
- this.sceneRenderer.endFrame()
724
824
  }
725
825
  if (shouldUpdateOverlay && !shouldUpdateMain) {
726
- this.sceneRenderer.beginFrame(region)
727
- ;(this.sceneRenderer as any).setFallbackContext(overlayCtx ?? null, vp.dpr)
826
+ sceneRenderer.beginFrame(region)
728
827
  this.scene.paintPane(
729
828
  {
730
- renderer: this.sceneRenderer,
829
+ renderer: sceneRenderer,
731
830
  region,
732
831
  paneRole: (pane.id === 'main' ? 'main' : 'sub') as PaneRole,
733
832
  paneId: pane.id,
@@ -736,10 +835,12 @@ export class ChartRenderer {
736
835
  },
737
836
  ['overlay'],
738
837
  )
739
- this.sceneRenderer.endFrame()
740
838
  }
741
839
  }
742
840
 
841
+ // WebGPU: one submit after all panes recorded draws
842
+ this.deps.getSceneRenderer().endFrame()
843
+
743
844
  return { sharedXAxisLabels, sharedXAxisRanges }
744
845
  }
745
846
 
@@ -817,7 +918,7 @@ export class ChartRenderer {
817
918
  dayKeys: dataManager.getDayKeys() ?? undefined,
818
919
  }
819
920
  const paintCtx: PaintContext = {
820
- renderer: this.sceneRenderer,
921
+ renderer: this.deps.getSceneRenderer(),
821
922
  region: { x: 0, y: 0, width: vp.plotWidth, height: opt.bottomAxisHeight, dpr: vp.dpr },
822
923
  paneRole: 'global',
823
924
  paneId: 'xAxis',
@@ -877,7 +978,6 @@ export class ChartRenderer {
877
978
  }
878
979
  this.cachedDrawFrame = null
879
980
  this.xAxisCtx = null
880
- this.sceneRenderer.dispose()
881
981
  this.scene.dispose()
882
982
  this.paneCtxMap.clear()
883
983
  }
@@ -16,6 +16,7 @@ import { createNonNegativeSparseVisibleStateComposer } from '../../indicators/vi
16
16
 
17
17
  import { createAtrScaleRendererPlugin } from './scale/atr_scale'
18
18
  import { createSingleLineTitleInfo } from './shared/titleInfo'
19
+ import { tryDrawLinesGpu } from '../linesViaRenderer'
19
20
 
20
21
  type LinePoint = { x: number; y: number }
21
22
 
@@ -98,7 +99,7 @@ function createATRRendererPlugin(options: ATRRendererOptions = {}): RendererPlug
98
99
  },
99
100
 
100
101
  draw(context: RenderContext) {
101
- const { ctx, pane, range, scrollLeft, kLineCenters, lineWebGLSurface } = context
102
+ const { ctx, pane, range, scrollLeft, kLineCenters } = context
102
103
  const colors = resolveThemeColors(
103
104
  context.theme,
104
105
  context.isAsiaMarket,
@@ -159,22 +160,9 @@ function createATRRendererPlugin(options: ATRRendererOptions = {}): RendererPlug
159
160
  }
160
161
  }
161
162
 
162
- const enableWebGL = context.settings?.enableWebGLRendering !== false
163
- let usedWebGL = false
164
- if (enableWebGL && lineWebGLSurface?.isAvailable()) {
165
- if (cachedPoints.length >= 2) {
166
- const ok = lineWebGLSurface.drawLineStrips(
167
- [{ points: cachedPoints, width: 1, color: atrColor }],
168
- scrollLeft,
169
- )
170
- if (ok) {
171
- usedWebGL = true
172
- lineWebGLSurface.compositeTo(ctx, { imageSmoothingEnabled: false })
173
- }
174
- }
175
- }
176
-
177
- if (!usedWebGL) {
163
+ if (
164
+ !tryDrawLinesGpu(context, [{ points: cachedPoints, width: 1, color: atrColor }], scrollLeft)
165
+ ) {
178
166
  drawWithCanvas2D(ctx, scrollLeft, cachedPoints, atrColor)
179
167
  }
180
168
  },
@@ -20,7 +20,8 @@ import type {
20
20
  import type { BOLLSchedulerConfig, IndicatorScheduler } from '../../indicators/scheduler'
21
21
  import { BOLL_STATE_KEY, type BOLLRenderState } from '../../indicators/state/bollState'
22
22
 
23
- import { getRgbaAlpha, toOpaqueRgba, compositeLineSurface } from './shared/webglBand'
23
+ import { getRgbaAlpha, toOpaqueRgba } from './shared/webglBand'
24
+ import { tryDrawFilledBandGpu, tryDrawLinesGpu } from '../linesViaRenderer'
24
25
 
25
26
  type LinePoint = { x: number; y: number }
26
27
 
@@ -32,6 +33,10 @@ interface PriceData {
32
33
  lower: number
33
34
  }
34
35
 
36
+ /**
37
+ * BOLL GPU:先 band fill(半透明 composite)再三轨折线。
38
+ * 仅 sceneRenderer;失败返回 false 走 2D。
39
+ */
35
40
  function drawBOLLWithWebGL(
36
41
  context: RenderContext,
37
42
  data: {
@@ -51,25 +56,18 @@ function drawBOLLWithWebGL(
51
56
  context.isAsiaMarket,
52
57
  context.colorPresetSettings,
53
58
  )
54
- if (context.settings?.enableWebGLRendering === false) return false
55
- const surface = context.lineWebGLSurface
56
- if (!surface || !surface.isAvailable()) return false
57
-
58
- surface.clear()
59
-
60
- let allOk = true
59
+ // band:画完立即 composite(alpha),再画线(MSAA clear FBO,band 已在 2D)
60
+ let bandOk = false
61
61
  if (data.showBand && data.bandUpperPoints.length >= 2 && data.bandLowerPoints.length >= 2) {
62
- surface.clear()
63
- allOk = surface.drawFilledBand(
64
- { upperPoints: data.bandUpperPoints, lowerPoints: data.bandLowerPoints },
62
+ bandOk = tryDrawFilledBandGpu(
63
+ context,
64
+ data.bandUpperPoints,
65
+ data.bandLowerPoints,
65
66
  toOpaqueRgba(colors.boll.bandFill),
66
67
  context.scrollLeft,
68
+ getRgbaAlpha(colors.boll.bandFill),
67
69
  )
68
- if (allOk) {
69
- compositeLineSurface(context, surface, getRgbaAlpha(colors.boll.bandFill))
70
- }
71
70
  }
72
- surface.clear()
73
71
 
74
72
  const lineStrips: Array<{ points: LinePoint[]; width: number; color: string }> = []
75
73
  if (data.showUpper && data.upperPoints.length >= 2) {
@@ -86,17 +84,8 @@ function drawBOLLWithWebGL(
86
84
  lineStrips.push({ points: data.lowerPoints, width: BOLL_LINE_WIDTH, color: colors.boll.lower })
87
85
  }
88
86
 
89
- if (lineStrips.length > 0) {
90
- allOk = surface.drawLineStrips(lineStrips, context.scrollLeft)
91
- }
92
- if (!allOk) {
93
- surface.clear()
94
- return false
95
- }
96
-
97
- compositeLineSurface(context, surface)
98
- surface.clear()
99
- return true
87
+ if (lineStrips.length === 0) return bandOk
88
+ return tryDrawLinesGpu(context, lineStrips, context.scrollLeft)
100
89
  }
101
90
 
102
91
  function buildPriceCacheKey(