@363045841yyt/klinechart-core 0.8.5 → 0.8.7

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