@363045841yyt/klinechart-core 0.8.6 → 0.8.8

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