@363045841yyt/klinechart-core 0.7.3

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 (919) hide show
  1. package/README.md +201 -0
  2. package/README.zh-CN.md +201 -0
  3. package/dist/config/chartSettings.d.ts +70 -0
  4. package/dist/config/chartSettings.d.ts.map +1 -0
  5. package/dist/config/chartSettings.js +50 -0
  6. package/dist/config/chartSettings.js.map +1 -0
  7. package/dist/controllers/createChartController.d.ts +16 -0
  8. package/dist/controllers/createChartController.d.ts.map +1 -0
  9. package/dist/controllers/createChartController.js +525 -0
  10. package/dist/controllers/createChartController.js.map +1 -0
  11. package/dist/controllers/createDrawingController.d.ts +25 -0
  12. package/dist/controllers/createDrawingController.d.ts.map +1 -0
  13. package/dist/controllers/createDrawingController.js +77 -0
  14. package/dist/controllers/createDrawingController.js.map +1 -0
  15. package/dist/controllers/createIndicatorSelectorController.d.ts +19 -0
  16. package/dist/controllers/createIndicatorSelectorController.d.ts.map +1 -0
  17. package/dist/controllers/createIndicatorSelectorController.js +256 -0
  18. package/dist/controllers/createIndicatorSelectorController.js.map +1 -0
  19. package/dist/controllers/createToolbarController.d.ts +28 -0
  20. package/dist/controllers/createToolbarController.d.ts.map +1 -0
  21. package/dist/controllers/createToolbarController.js +121 -0
  22. package/dist/controllers/createToolbarController.js.map +1 -0
  23. package/dist/controllers/index.d.ts +3 -0
  24. package/dist/controllers/index.d.ts.map +1 -0
  25. package/dist/controllers/index.js +2 -0
  26. package/dist/controllers/index.js.map +1 -0
  27. package/dist/controllers/types.d.ts +218 -0
  28. package/dist/controllers/types.d.ts.map +1 -0
  29. package/dist/controllers/types.js +11 -0
  30. package/dist/controllers/types.js.map +1 -0
  31. package/dist/engine/chart-store.d.ts +75 -0
  32. package/dist/engine/chart-store.d.ts.map +1 -0
  33. package/dist/engine/chart-store.js +88 -0
  34. package/dist/engine/chart-store.js.map +1 -0
  35. package/dist/engine/chart.d.ts +618 -0
  36. package/dist/engine/chart.d.ts.map +1 -0
  37. package/dist/engine/chart.js +2285 -0
  38. package/dist/engine/chart.js.map +1 -0
  39. package/dist/engine/controller/interaction.d.ts +168 -0
  40. package/dist/engine/controller/interaction.d.ts.map +1 -0
  41. package/dist/engine/controller/interaction.js +612 -0
  42. package/dist/engine/controller/interaction.js.map +1 -0
  43. package/dist/engine/controller/markerInteraction.d.ts +29 -0
  44. package/dist/engine/controller/markerInteraction.d.ts.map +1 -0
  45. package/dist/engine/controller/markerInteraction.js +111 -0
  46. package/dist/engine/controller/markerInteraction.js.map +1 -0
  47. package/dist/engine/controller/pinchTracker.d.ts +19 -0
  48. package/dist/engine/controller/pinchTracker.d.ts.map +1 -0
  49. package/dist/engine/controller/pinchTracker.js +72 -0
  50. package/dist/engine/controller/pinchTracker.js.map +1 -0
  51. package/dist/engine/controller/tooltipPosition.d.ts +22 -0
  52. package/dist/engine/controller/tooltipPosition.d.ts.map +1 -0
  53. package/dist/engine/controller/tooltipPosition.js +31 -0
  54. package/dist/engine/controller/tooltipPosition.js.map +1 -0
  55. package/dist/engine/draw/pixelAlign.d.ts +115 -0
  56. package/dist/engine/draw/pixelAlign.d.ts.map +1 -0
  57. package/dist/engine/draw/pixelAlign.js +185 -0
  58. package/dist/engine/draw/pixelAlign.js.map +1 -0
  59. package/dist/engine/drawing/index.d.ts +48 -0
  60. package/dist/engine/drawing/index.d.ts.map +1 -0
  61. package/dist/engine/drawing/index.js +561 -0
  62. package/dist/engine/drawing/index.js.map +1 -0
  63. package/dist/engine/drawing/interaction.d.ts +76 -0
  64. package/dist/engine/drawing/interaction.d.ts.map +1 -0
  65. package/dist/engine/drawing/interaction.js +702 -0
  66. package/dist/engine/drawing/interaction.js.map +1 -0
  67. package/dist/engine/drawing/plugin.d.ts +29 -0
  68. package/dist/engine/drawing/plugin.d.ts.map +1 -0
  69. package/dist/engine/drawing/plugin.js +292 -0
  70. package/dist/engine/drawing/plugin.js.map +1 -0
  71. package/dist/engine/indicators/atrState.d.ts +17 -0
  72. package/dist/engine/indicators/atrState.d.ts.map +1 -0
  73. package/dist/engine/indicators/atrState.js +13 -0
  74. package/dist/engine/indicators/atrState.js.map +1 -0
  75. package/dist/engine/indicators/bollState.d.ts +35 -0
  76. package/dist/engine/indicators/bollState.d.ts.map +1 -0
  77. package/dist/engine/indicators/bollState.js +25 -0
  78. package/dist/engine/indicators/bollState.js.map +1 -0
  79. package/dist/engine/indicators/calculators.d.ts +466 -0
  80. package/dist/engine/indicators/calculators.d.ts.map +1 -0
  81. package/dist/engine/indicators/calculators.js +1882 -0
  82. package/dist/engine/indicators/calculators.js.map +1 -0
  83. package/dist/engine/indicators/cciState.d.ts +16 -0
  84. package/dist/engine/indicators/cciState.d.ts.map +1 -0
  85. package/dist/engine/indicators/cciState.js +12 -0
  86. package/dist/engine/indicators/cciState.js.map +1 -0
  87. package/dist/engine/indicators/chaikinVolState.d.ts +19 -0
  88. package/dist/engine/indicators/chaikinVolState.d.ts.map +1 -0
  89. package/dist/engine/indicators/chaikinVolState.js +18 -0
  90. package/dist/engine/indicators/chaikinVolState.js.map +1 -0
  91. package/dist/engine/indicators/cmfState.d.ts +17 -0
  92. package/dist/engine/indicators/cmfState.d.ts.map +1 -0
  93. package/dist/engine/indicators/cmfState.js +13 -0
  94. package/dist/engine/indicators/cmfState.js.map +1 -0
  95. package/dist/engine/indicators/demaState.d.ts +17 -0
  96. package/dist/engine/indicators/demaState.d.ts.map +1 -0
  97. package/dist/engine/indicators/demaState.js +13 -0
  98. package/dist/engine/indicators/demaState.js.map +1 -0
  99. package/dist/engine/indicators/donchianState.d.ts +24 -0
  100. package/dist/engine/indicators/donchianState.d.ts.map +1 -0
  101. package/dist/engine/indicators/donchianState.js +18 -0
  102. package/dist/engine/indicators/donchianState.js.map +1 -0
  103. package/dist/engine/indicators/eneState.d.ts +31 -0
  104. package/dist/engine/indicators/eneState.d.ts.map +1 -0
  105. package/dist/engine/indicators/eneState.js +21 -0
  106. package/dist/engine/indicators/eneState.js.map +1 -0
  107. package/dist/engine/indicators/expmaState.d.ts +31 -0
  108. package/dist/engine/indicators/expmaState.d.ts.map +1 -0
  109. package/dist/engine/indicators/expmaState.js +21 -0
  110. package/dist/engine/indicators/expmaState.js.map +1 -0
  111. package/dist/engine/indicators/fastkState.d.ts +16 -0
  112. package/dist/engine/indicators/fastkState.d.ts.map +1 -0
  113. package/dist/engine/indicators/fastkState.js +12 -0
  114. package/dist/engine/indicators/fastkState.js.map +1 -0
  115. package/dist/engine/indicators/fibState.d.ts +27 -0
  116. package/dist/engine/indicators/fibState.d.ts.map +1 -0
  117. package/dist/engine/indicators/fibState.js +13 -0
  118. package/dist/engine/indicators/fibState.js.map +1 -0
  119. package/dist/engine/indicators/hmaState.d.ts +17 -0
  120. package/dist/engine/indicators/hmaState.d.ts.map +1 -0
  121. package/dist/engine/indicators/hmaState.js +13 -0
  122. package/dist/engine/indicators/hmaState.js.map +1 -0
  123. package/dist/engine/indicators/hvState.d.ts +19 -0
  124. package/dist/engine/indicators/hvState.d.ts.map +1 -0
  125. package/dist/engine/indicators/hvState.js +14 -0
  126. package/dist/engine/indicators/hvState.js.map +1 -0
  127. package/dist/engine/indicators/ichimokuState.d.ts +45 -0
  128. package/dist/engine/indicators/ichimokuState.d.ts.map +1 -0
  129. package/dist/engine/indicators/ichimokuState.js +27 -0
  130. package/dist/engine/indicators/ichimokuState.js.map +1 -0
  131. package/dist/engine/indicators/indicator.worker.d.ts +6 -0
  132. package/dist/engine/indicators/indicator.worker.d.ts.map +1 -0
  133. package/dist/engine/indicators/indicator.worker.js +144 -0
  134. package/dist/engine/indicators/indicator.worker.js.map +1 -0
  135. package/dist/engine/indicators/indicatorDefinitionRegistry.d.ts +31 -0
  136. package/dist/engine/indicators/indicatorDefinitionRegistry.d.ts.map +1 -0
  137. package/dist/engine/indicators/indicatorDefinitionRegistry.js +38 -0
  138. package/dist/engine/indicators/indicatorDefinitionRegistry.js.map +1 -0
  139. package/dist/engine/indicators/indicatorMetadata.d.ts +88 -0
  140. package/dist/engine/indicators/indicatorMetadata.d.ts.map +1 -0
  141. package/dist/engine/indicators/indicatorMetadata.js +22 -0
  142. package/dist/engine/indicators/indicatorMetadata.js.map +1 -0
  143. package/dist/engine/indicators/indicatorRegistry.d.ts +58 -0
  144. package/dist/engine/indicators/indicatorRegistry.d.ts.map +1 -0
  145. package/dist/engine/indicators/indicatorRegistry.js +91 -0
  146. package/dist/engine/indicators/indicatorRegistry.js.map +1 -0
  147. package/dist/engine/indicators/indicatorRuntime.d.ts +132 -0
  148. package/dist/engine/indicators/indicatorRuntime.d.ts.map +1 -0
  149. package/dist/engine/indicators/indicatorRuntime.js +1354 -0
  150. package/dist/engine/indicators/indicatorRuntime.js.map +1 -0
  151. package/dist/engine/indicators/kamaState.d.ts +21 -0
  152. package/dist/engine/indicators/kamaState.d.ts.map +1 -0
  153. package/dist/engine/indicators/kamaState.js +20 -0
  154. package/dist/engine/indicators/kamaState.js.map +1 -0
  155. package/dist/engine/indicators/keltnerState.d.ts +28 -0
  156. package/dist/engine/indicators/keltnerState.d.ts.map +1 -0
  157. package/dist/engine/indicators/keltnerState.js +22 -0
  158. package/dist/engine/indicators/keltnerState.js.map +1 -0
  159. package/dist/engine/indicators/kstState.d.ts +22 -0
  160. package/dist/engine/indicators/kstState.d.ts.map +1 -0
  161. package/dist/engine/indicators/kstState.js +20 -0
  162. package/dist/engine/indicators/kstState.js.map +1 -0
  163. package/dist/engine/indicators/maState.d.ts +27 -0
  164. package/dist/engine/indicators/maState.d.ts.map +1 -0
  165. package/dist/engine/indicators/maState.js +18 -0
  166. package/dist/engine/indicators/maState.js.map +1 -0
  167. package/dist/engine/indicators/macdState.d.ts +59 -0
  168. package/dist/engine/indicators/macdState.d.ts.map +1 -0
  169. package/dist/engine/indicators/macdState.js +33 -0
  170. package/dist/engine/indicators/macdState.js.map +1 -0
  171. package/dist/engine/indicators/mfiState.d.ts +17 -0
  172. package/dist/engine/indicators/mfiState.d.ts.map +1 -0
  173. package/dist/engine/indicators/mfiState.js +13 -0
  174. package/dist/engine/indicators/mfiState.js.map +1 -0
  175. package/dist/engine/indicators/momState.d.ts +16 -0
  176. package/dist/engine/indicators/momState.d.ts.map +1 -0
  177. package/dist/engine/indicators/momState.js +12 -0
  178. package/dist/engine/indicators/momState.js.map +1 -0
  179. package/dist/engine/indicators/obvState.d.ts +15 -0
  180. package/dist/engine/indicators/obvState.d.ts.map +1 -0
  181. package/dist/engine/indicators/obvState.js +12 -0
  182. package/dist/engine/indicators/obvState.js.map +1 -0
  183. package/dist/engine/indicators/parkinsonState.d.ts +19 -0
  184. package/dist/engine/indicators/parkinsonState.d.ts.map +1 -0
  185. package/dist/engine/indicators/parkinsonState.js +14 -0
  186. package/dist/engine/indicators/parkinsonState.js.map +1 -0
  187. package/dist/engine/indicators/pivotState.d.ts +30 -0
  188. package/dist/engine/indicators/pivotState.d.ts.map +1 -0
  189. package/dist/engine/indicators/pivotState.js +20 -0
  190. package/dist/engine/indicators/pivotState.js.map +1 -0
  191. package/dist/engine/indicators/pvtState.d.ts +15 -0
  192. package/dist/engine/indicators/pvtState.d.ts.map +1 -0
  193. package/dist/engine/indicators/pvtState.js +12 -0
  194. package/dist/engine/indicators/pvtState.js.map +1 -0
  195. package/dist/engine/indicators/rocState.d.ts +17 -0
  196. package/dist/engine/indicators/rocState.d.ts.map +1 -0
  197. package/dist/engine/indicators/rocState.js +13 -0
  198. package/dist/engine/indicators/rocState.js.map +1 -0
  199. package/dist/engine/indicators/rsiState.d.ts +44 -0
  200. package/dist/engine/indicators/rsiState.d.ts.map +1 -0
  201. package/dist/engine/indicators/rsiState.js +32 -0
  202. package/dist/engine/indicators/rsiState.js.map +1 -0
  203. package/dist/engine/indicators/sarState.d.ts +27 -0
  204. package/dist/engine/indicators/sarState.d.ts.map +1 -0
  205. package/dist/engine/indicators/sarState.js +18 -0
  206. package/dist/engine/indicators/sarState.js.map +1 -0
  207. package/dist/engine/indicators/scheduler.d.ts +277 -0
  208. package/dist/engine/indicators/scheduler.d.ts.map +1 -0
  209. package/dist/engine/indicators/scheduler.js +1012 -0
  210. package/dist/engine/indicators/scheduler.js.map +1 -0
  211. package/dist/engine/indicators/soa.d.ts +116 -0
  212. package/dist/engine/indicators/soa.d.ts.map +1 -0
  213. package/dist/engine/indicators/soa.js +242 -0
  214. package/dist/engine/indicators/soa.js.map +1 -0
  215. package/dist/engine/indicators/stateComposer.d.ts +151 -0
  216. package/dist/engine/indicators/stateComposer.d.ts.map +1 -0
  217. package/dist/engine/indicators/stateComposer.js +1018 -0
  218. package/dist/engine/indicators/stateComposer.js.map +1 -0
  219. package/dist/engine/indicators/stochState.d.ts +19 -0
  220. package/dist/engine/indicators/stochState.d.ts.map +1 -0
  221. package/dist/engine/indicators/stochState.js +12 -0
  222. package/dist/engine/indicators/stochState.js.map +1 -0
  223. package/dist/engine/indicators/structureState.d.ts +44 -0
  224. package/dist/engine/indicators/structureState.d.ts.map +1 -0
  225. package/dist/engine/indicators/structureState.js +22 -0
  226. package/dist/engine/indicators/structureState.js.map +1 -0
  227. package/dist/engine/indicators/supertrendState.d.ts +23 -0
  228. package/dist/engine/indicators/supertrendState.d.ts.map +1 -0
  229. package/dist/engine/indicators/supertrendState.js +18 -0
  230. package/dist/engine/indicators/supertrendState.js.map +1 -0
  231. package/dist/engine/indicators/temaState.d.ts +17 -0
  232. package/dist/engine/indicators/temaState.d.ts.map +1 -0
  233. package/dist/engine/indicators/temaState.js +13 -0
  234. package/dist/engine/indicators/temaState.js.map +1 -0
  235. package/dist/engine/indicators/trixState.d.ts +21 -0
  236. package/dist/engine/indicators/trixState.d.ts.map +1 -0
  237. package/dist/engine/indicators/trixState.js +20 -0
  238. package/dist/engine/indicators/trixState.js.map +1 -0
  239. package/dist/engine/indicators/vmaState.d.ts +17 -0
  240. package/dist/engine/indicators/vmaState.d.ts.map +1 -0
  241. package/dist/engine/indicators/vmaState.js +13 -0
  242. package/dist/engine/indicators/vmaState.js.map +1 -0
  243. package/dist/engine/indicators/volumeProfileState.d.ts +35 -0
  244. package/dist/engine/indicators/volumeProfileState.d.ts.map +1 -0
  245. package/dist/engine/indicators/volumeProfileState.js +28 -0
  246. package/dist/engine/indicators/volumeProfileState.js.map +1 -0
  247. package/dist/engine/indicators/vwapState.d.ts +17 -0
  248. package/dist/engine/indicators/vwapState.d.ts.map +1 -0
  249. package/dist/engine/indicators/vwapState.js +15 -0
  250. package/dist/engine/indicators/vwapState.js.map +1 -0
  251. package/dist/engine/indicators/wmaState.d.ts +17 -0
  252. package/dist/engine/indicators/wmaState.d.ts.map +1 -0
  253. package/dist/engine/indicators/wmaState.js +13 -0
  254. package/dist/engine/indicators/wmaState.js.map +1 -0
  255. package/dist/engine/indicators/wmsrState.d.ts +16 -0
  256. package/dist/engine/indicators/wmsrState.d.ts.map +1 -0
  257. package/dist/engine/indicators/wmsrState.js +12 -0
  258. package/dist/engine/indicators/wmsrState.js.map +1 -0
  259. package/dist/engine/indicators/workerProtocol.d.ts +501 -0
  260. package/dist/engine/indicators/workerProtocol.d.ts.map +1 -0
  261. package/dist/engine/indicators/workerProtocol.js +20 -0
  262. package/dist/engine/indicators/workerProtocol.js.map +1 -0
  263. package/dist/engine/indicators/zonesState.d.ts +27 -0
  264. package/dist/engine/indicators/zonesState.d.ts.map +1 -0
  265. package/dist/engine/indicators/zonesState.js +18 -0
  266. package/dist/engine/indicators/zonesState.js.map +1 -0
  267. package/dist/engine/layout/pane.d.ts +104 -0
  268. package/dist/engine/layout/pane.d.ts.map +1 -0
  269. package/dist/engine/layout/pane.js +107 -0
  270. package/dist/engine/layout/pane.js.map +1 -0
  271. package/dist/engine/marker/registry.d.ts +175 -0
  272. package/dist/engine/marker/registry.d.ts.map +1 -0
  273. package/dist/engine/marker/registry.js +171 -0
  274. package/dist/engine/marker/registry.js.map +1 -0
  275. package/dist/engine/paneRenderer.d.ts +46 -0
  276. package/dist/engine/paneRenderer.d.ts.map +1 -0
  277. package/dist/engine/paneRenderer.js +121 -0
  278. package/dist/engine/paneRenderer.js.map +1 -0
  279. package/dist/engine/renderers/Indicator/atr.d.ts +18 -0
  280. package/dist/engine/renderers/Indicator/atr.d.ts.map +1 -0
  281. package/dist/engine/renderers/Indicator/atr.js +237 -0
  282. package/dist/engine/renderers/Indicator/atr.js.map +1 -0
  283. package/dist/engine/renderers/Indicator/boll.d.ts +3 -0
  284. package/dist/engine/renderers/Indicator/boll.d.ts.map +1 -0
  285. package/dist/engine/renderers/Indicator/boll.js +312 -0
  286. package/dist/engine/renderers/Indicator/boll.js.map +1 -0
  287. package/dist/engine/renderers/Indicator/cci.d.ts +23 -0
  288. package/dist/engine/renderers/Indicator/cci.d.ts.map +1 -0
  289. package/dist/engine/renderers/Indicator/cci.js +266 -0
  290. package/dist/engine/renderers/Indicator/cci.js.map +1 -0
  291. package/dist/engine/renderers/Indicator/chaikinVol.d.ts +5 -0
  292. package/dist/engine/renderers/Indicator/chaikinVol.d.ts.map +1 -0
  293. package/dist/engine/renderers/Indicator/chaikinVol.js +175 -0
  294. package/dist/engine/renderers/Indicator/chaikinVol.js.map +1 -0
  295. package/dist/engine/renderers/Indicator/cmf.d.ts +5 -0
  296. package/dist/engine/renderers/Indicator/cmf.d.ts.map +1 -0
  297. package/dist/engine/renderers/Indicator/cmf.js +175 -0
  298. package/dist/engine/renderers/Indicator/cmf.js.map +1 -0
  299. package/dist/engine/renderers/Indicator/dema.d.ts +6 -0
  300. package/dist/engine/renderers/Indicator/dema.d.ts.map +1 -0
  301. package/dist/engine/renderers/Indicator/dema.js +164 -0
  302. package/dist/engine/renderers/Indicator/dema.js.map +1 -0
  303. package/dist/engine/renderers/Indicator/donchian.d.ts +6 -0
  304. package/dist/engine/renderers/Indicator/donchian.d.ts.map +1 -0
  305. package/dist/engine/renderers/Indicator/donchian.js +181 -0
  306. package/dist/engine/renderers/Indicator/donchian.js.map +1 -0
  307. package/dist/engine/renderers/Indicator/ene.d.ts +3 -0
  308. package/dist/engine/renderers/Indicator/ene.d.ts.map +1 -0
  309. package/dist/engine/renderers/Indicator/ene.js +280 -0
  310. package/dist/engine/renderers/Indicator/ene.js.map +1 -0
  311. package/dist/engine/renderers/Indicator/expma.d.ts +3 -0
  312. package/dist/engine/renderers/Indicator/expma.d.ts.map +1 -0
  313. package/dist/engine/renderers/Indicator/expma.js +216 -0
  314. package/dist/engine/renderers/Indicator/expma.js.map +1 -0
  315. package/dist/engine/renderers/Indicator/fastk.d.ts +23 -0
  316. package/dist/engine/renderers/Indicator/fastk.d.ts.map +1 -0
  317. package/dist/engine/renderers/Indicator/fastk.js +289 -0
  318. package/dist/engine/renderers/Indicator/fastk.js.map +1 -0
  319. package/dist/engine/renderers/Indicator/fib.d.ts +5 -0
  320. package/dist/engine/renderers/Indicator/fib.d.ts.map +1 -0
  321. package/dist/engine/renderers/Indicator/fib.js +182 -0
  322. package/dist/engine/renderers/Indicator/fib.js.map +1 -0
  323. package/dist/engine/renderers/Indicator/hma.d.ts +6 -0
  324. package/dist/engine/renderers/Indicator/hma.d.ts.map +1 -0
  325. package/dist/engine/renderers/Indicator/hma.js +164 -0
  326. package/dist/engine/renderers/Indicator/hma.js.map +1 -0
  327. package/dist/engine/renderers/Indicator/hv.d.ts +5 -0
  328. package/dist/engine/renderers/Indicator/hv.d.ts.map +1 -0
  329. package/dist/engine/renderers/Indicator/hv.js +162 -0
  330. package/dist/engine/renderers/Indicator/hv.js.map +1 -0
  331. package/dist/engine/renderers/Indicator/ichimoku.d.ts +6 -0
  332. package/dist/engine/renderers/Indicator/ichimoku.d.ts.map +1 -0
  333. package/dist/engine/renderers/Indicator/ichimoku.js +220 -0
  334. package/dist/engine/renderers/Indicator/ichimoku.js.map +1 -0
  335. package/dist/engine/renderers/Indicator/index.d.ts +63 -0
  336. package/dist/engine/renderers/Indicator/index.d.ts.map +1 -0
  337. package/dist/engine/renderers/Indicator/index.js +204 -0
  338. package/dist/engine/renderers/Indicator/index.js.map +1 -0
  339. package/dist/engine/renderers/Indicator/indicatorData.d.ts +23 -0
  340. package/dist/engine/renderers/Indicator/indicatorData.d.ts.map +1 -0
  341. package/dist/engine/renderers/Indicator/indicatorData.js +617 -0
  342. package/dist/engine/renderers/Indicator/indicatorData.js.map +1 -0
  343. package/dist/engine/renderers/Indicator/kama.d.ts +6 -0
  344. package/dist/engine/renderers/Indicator/kama.d.ts.map +1 -0
  345. package/dist/engine/renderers/Indicator/kama.js +164 -0
  346. package/dist/engine/renderers/Indicator/kama.js.map +1 -0
  347. package/dist/engine/renderers/Indicator/keltner.d.ts +6 -0
  348. package/dist/engine/renderers/Indicator/keltner.d.ts.map +1 -0
  349. package/dist/engine/renderers/Indicator/keltner.js +181 -0
  350. package/dist/engine/renderers/Indicator/keltner.js.map +1 -0
  351. package/dist/engine/renderers/Indicator/kst.d.ts +23 -0
  352. package/dist/engine/renderers/Indicator/kst.d.ts.map +1 -0
  353. package/dist/engine/renderers/Indicator/kst.js +290 -0
  354. package/dist/engine/renderers/Indicator/kst.js.map +1 -0
  355. package/dist/engine/renderers/Indicator/ma.d.ts +4 -0
  356. package/dist/engine/renderers/Indicator/ma.d.ts.map +1 -0
  357. package/dist/engine/renderers/Indicator/ma.js +218 -0
  358. package/dist/engine/renderers/Indicator/ma.js.map +1 -0
  359. package/dist/engine/renderers/Indicator/macd.d.ts +51 -0
  360. package/dist/engine/renderers/Indicator/macd.d.ts.map +1 -0
  361. package/dist/engine/renderers/Indicator/macd.js +432 -0
  362. package/dist/engine/renderers/Indicator/macd.js.map +1 -0
  363. package/dist/engine/renderers/Indicator/macdLegend.d.ts +13 -0
  364. package/dist/engine/renderers/Indicator/macdLegend.d.ts.map +1 -0
  365. package/dist/engine/renderers/Indicator/macdLegend.js +116 -0
  366. package/dist/engine/renderers/Indicator/macdLegend.js.map +1 -0
  367. package/dist/engine/renderers/Indicator/mainIndicatorLegend.d.ts +11 -0
  368. package/dist/engine/renderers/Indicator/mainIndicatorLegend.d.ts.map +1 -0
  369. package/dist/engine/renderers/Indicator/mainIndicatorLegend.js +220 -0
  370. package/dist/engine/renderers/Indicator/mainIndicatorLegend.js.map +1 -0
  371. package/dist/engine/renderers/Indicator/mfi.d.ts +5 -0
  372. package/dist/engine/renderers/Indicator/mfi.d.ts.map +1 -0
  373. package/dist/engine/renderers/Indicator/mfi.js +180 -0
  374. package/dist/engine/renderers/Indicator/mfi.js.map +1 -0
  375. package/dist/engine/renderers/Indicator/mom.d.ts +23 -0
  376. package/dist/engine/renderers/Indicator/mom.d.ts.map +1 -0
  377. package/dist/engine/renderers/Indicator/mom.js +285 -0
  378. package/dist/engine/renderers/Indicator/mom.js.map +1 -0
  379. package/dist/engine/renderers/Indicator/obv.d.ts +5 -0
  380. package/dist/engine/renderers/Indicator/obv.d.ts.map +1 -0
  381. package/dist/engine/renderers/Indicator/obv.js +162 -0
  382. package/dist/engine/renderers/Indicator/obv.js.map +1 -0
  383. package/dist/engine/renderers/Indicator/parkinson.d.ts +5 -0
  384. package/dist/engine/renderers/Indicator/parkinson.d.ts.map +1 -0
  385. package/dist/engine/renderers/Indicator/parkinson.js +162 -0
  386. package/dist/engine/renderers/Indicator/parkinson.js.map +1 -0
  387. package/dist/engine/renderers/Indicator/pivot.d.ts +5 -0
  388. package/dist/engine/renderers/Indicator/pivot.d.ts.map +1 -0
  389. package/dist/engine/renderers/Indicator/pivot.js +181 -0
  390. package/dist/engine/renderers/Indicator/pivot.js.map +1 -0
  391. package/dist/engine/renderers/Indicator/pvt.d.ts +5 -0
  392. package/dist/engine/renderers/Indicator/pvt.d.ts.map +1 -0
  393. package/dist/engine/renderers/Indicator/pvt.js +162 -0
  394. package/dist/engine/renderers/Indicator/pvt.js.map +1 -0
  395. package/dist/engine/renderers/Indicator/roc.d.ts +6 -0
  396. package/dist/engine/renderers/Indicator/roc.d.ts.map +1 -0
  397. package/dist/engine/renderers/Indicator/roc.js +175 -0
  398. package/dist/engine/renderers/Indicator/roc.js.map +1 -0
  399. package/dist/engine/renderers/Indicator/rsi.d.ts +34 -0
  400. package/dist/engine/renderers/Indicator/rsi.d.ts.map +1 -0
  401. package/dist/engine/renderers/Indicator/rsi.js +351 -0
  402. package/dist/engine/renderers/Indicator/rsi.js.map +1 -0
  403. package/dist/engine/renderers/Indicator/sar.d.ts +6 -0
  404. package/dist/engine/renderers/Indicator/sar.d.ts.map +1 -0
  405. package/dist/engine/renderers/Indicator/sar.js +146 -0
  406. package/dist/engine/renderers/Indicator/sar.js.map +1 -0
  407. package/dist/engine/renderers/Indicator/scale/atr_scale.d.ts +12 -0
  408. package/dist/engine/renderers/Indicator/scale/atr_scale.d.ts.map +1 -0
  409. package/dist/engine/renderers/Indicator/scale/atr_scale.js +13 -0
  410. package/dist/engine/renderers/Indicator/scale/atr_scale.js.map +1 -0
  411. package/dist/engine/renderers/Indicator/scale/cci_scale.d.ts +12 -0
  412. package/dist/engine/renderers/Indicator/scale/cci_scale.d.ts.map +1 -0
  413. package/dist/engine/renderers/Indicator/scale/cci_scale.js +13 -0
  414. package/dist/engine/renderers/Indicator/scale/cci_scale.js.map +1 -0
  415. package/dist/engine/renderers/Indicator/scale/fastk_scale.d.ts +12 -0
  416. package/dist/engine/renderers/Indicator/scale/fastk_scale.d.ts.map +1 -0
  417. package/dist/engine/renderers/Indicator/scale/fastk_scale.js +13 -0
  418. package/dist/engine/renderers/Indicator/scale/fastk_scale.js.map +1 -0
  419. package/dist/engine/renderers/Indicator/scale/indicator_scale.d.ts +39 -0
  420. package/dist/engine/renderers/Indicator/scale/indicator_scale.d.ts.map +1 -0
  421. package/dist/engine/renderers/Indicator/scale/indicator_scale.js +120 -0
  422. package/dist/engine/renderers/Indicator/scale/indicator_scale.js.map +1 -0
  423. package/dist/engine/renderers/Indicator/scale/kst_scale.d.ts +12 -0
  424. package/dist/engine/renderers/Indicator/scale/kst_scale.d.ts.map +1 -0
  425. package/dist/engine/renderers/Indicator/scale/kst_scale.js +13 -0
  426. package/dist/engine/renderers/Indicator/scale/kst_scale.js.map +1 -0
  427. package/dist/engine/renderers/Indicator/scale/macd_scale.d.ts +15 -0
  428. package/dist/engine/renderers/Indicator/scale/macd_scale.d.ts.map +1 -0
  429. package/dist/engine/renderers/Indicator/scale/macd_scale.js +16 -0
  430. package/dist/engine/renderers/Indicator/scale/macd_scale.js.map +1 -0
  431. package/dist/engine/renderers/Indicator/scale/mom_scale.d.ts +12 -0
  432. package/dist/engine/renderers/Indicator/scale/mom_scale.d.ts.map +1 -0
  433. package/dist/engine/renderers/Indicator/scale/mom_scale.js +13 -0
  434. package/dist/engine/renderers/Indicator/scale/mom_scale.js.map +1 -0
  435. package/dist/engine/renderers/Indicator/scale/rsi_scale.d.ts +12 -0
  436. package/dist/engine/renderers/Indicator/scale/rsi_scale.d.ts.map +1 -0
  437. package/dist/engine/renderers/Indicator/scale/rsi_scale.js +13 -0
  438. package/dist/engine/renderers/Indicator/scale/rsi_scale.js.map +1 -0
  439. package/dist/engine/renderers/Indicator/scale/stoch_scale.d.ts +12 -0
  440. package/dist/engine/renderers/Indicator/scale/stoch_scale.d.ts.map +1 -0
  441. package/dist/engine/renderers/Indicator/scale/stoch_scale.js +13 -0
  442. package/dist/engine/renderers/Indicator/scale/stoch_scale.js.map +1 -0
  443. package/dist/engine/renderers/Indicator/scale/volume_scale.d.ts +15 -0
  444. package/dist/engine/renderers/Indicator/scale/volume_scale.d.ts.map +1 -0
  445. package/dist/engine/renderers/Indicator/scale/volume_scale.js +19 -0
  446. package/dist/engine/renderers/Indicator/scale/volume_scale.js.map +1 -0
  447. package/dist/engine/renderers/Indicator/scale/wmsr_scale.d.ts +12 -0
  448. package/dist/engine/renderers/Indicator/scale/wmsr_scale.d.ts.map +1 -0
  449. package/dist/engine/renderers/Indicator/scale/wmsr_scale.js +13 -0
  450. package/dist/engine/renderers/Indicator/scale/wmsr_scale.js.map +1 -0
  451. package/dist/engine/renderers/Indicator/stoch.d.ts +23 -0
  452. package/dist/engine/renderers/Indicator/stoch.d.ts.map +1 -0
  453. package/dist/engine/renderers/Indicator/stoch.js +329 -0
  454. package/dist/engine/renderers/Indicator/stoch.js.map +1 -0
  455. package/dist/engine/renderers/Indicator/structure.d.ts +5 -0
  456. package/dist/engine/renderers/Indicator/structure.d.ts.map +1 -0
  457. package/dist/engine/renderers/Indicator/structure.js +176 -0
  458. package/dist/engine/renderers/Indicator/structure.js.map +1 -0
  459. package/dist/engine/renderers/Indicator/subPaneConfig.d.ts +16 -0
  460. package/dist/engine/renderers/Indicator/subPaneConfig.d.ts.map +1 -0
  461. package/dist/engine/renderers/Indicator/subPaneConfig.js +194 -0
  462. package/dist/engine/renderers/Indicator/subPaneConfig.js.map +1 -0
  463. package/dist/engine/renderers/Indicator/supertrend.d.ts +6 -0
  464. package/dist/engine/renderers/Indicator/supertrend.d.ts.map +1 -0
  465. package/dist/engine/renderers/Indicator/supertrend.js +149 -0
  466. package/dist/engine/renderers/Indicator/supertrend.js.map +1 -0
  467. package/dist/engine/renderers/Indicator/tema.d.ts +6 -0
  468. package/dist/engine/renderers/Indicator/tema.d.ts.map +1 -0
  469. package/dist/engine/renderers/Indicator/tema.js +164 -0
  470. package/dist/engine/renderers/Indicator/tema.js.map +1 -0
  471. package/dist/engine/renderers/Indicator/trix.d.ts +6 -0
  472. package/dist/engine/renderers/Indicator/trix.d.ts.map +1 -0
  473. package/dist/engine/renderers/Indicator/trix.js +197 -0
  474. package/dist/engine/renderers/Indicator/trix.js.map +1 -0
  475. package/dist/engine/renderers/Indicator/vma.d.ts +5 -0
  476. package/dist/engine/renderers/Indicator/vma.d.ts.map +1 -0
  477. package/dist/engine/renderers/Indicator/vma.js +162 -0
  478. package/dist/engine/renderers/Indicator/vma.js.map +1 -0
  479. package/dist/engine/renderers/Indicator/volumeProfile.d.ts +5 -0
  480. package/dist/engine/renderers/Indicator/volumeProfile.d.ts.map +1 -0
  481. package/dist/engine/renderers/Indicator/volumeProfile.js +165 -0
  482. package/dist/engine/renderers/Indicator/volumeProfile.js.map +1 -0
  483. package/dist/engine/renderers/Indicator/vwap.d.ts +5 -0
  484. package/dist/engine/renderers/Indicator/vwap.d.ts.map +1 -0
  485. package/dist/engine/renderers/Indicator/vwap.js +162 -0
  486. package/dist/engine/renderers/Indicator/vwap.js.map +1 -0
  487. package/dist/engine/renderers/Indicator/wma.d.ts +6 -0
  488. package/dist/engine/renderers/Indicator/wma.d.ts.map +1 -0
  489. package/dist/engine/renderers/Indicator/wma.js +164 -0
  490. package/dist/engine/renderers/Indicator/wma.js.map +1 -0
  491. package/dist/engine/renderers/Indicator/wmsr.d.ts +23 -0
  492. package/dist/engine/renderers/Indicator/wmsr.d.ts.map +1 -0
  493. package/dist/engine/renderers/Indicator/wmsr.js +298 -0
  494. package/dist/engine/renderers/Indicator/wmsr.js.map +1 -0
  495. package/dist/engine/renderers/Indicator/zones.d.ts +5 -0
  496. package/dist/engine/renderers/Indicator/zones.d.ts.map +1 -0
  497. package/dist/engine/renderers/Indicator/zones.js +151 -0
  498. package/dist/engine/renderers/Indicator/zones.js.map +1 -0
  499. package/dist/engine/renderers/candle.d.ts +22 -0
  500. package/dist/engine/renderers/candle.d.ts.map +1 -0
  501. package/dist/engine/renderers/candle.js +356 -0
  502. package/dist/engine/renderers/candle.js.map +1 -0
  503. package/dist/engine/renderers/crosshair.d.ts +18 -0
  504. package/dist/engine/renderers/crosshair.d.ts.map +1 -0
  505. package/dist/engine/renderers/crosshair.js +54 -0
  506. package/dist/engine/renderers/crosshair.js.map +1 -0
  507. package/dist/engine/renderers/customMarkers.d.ts +7 -0
  508. package/dist/engine/renderers/customMarkers.d.ts.map +1 -0
  509. package/dist/engine/renderers/customMarkers.js +145 -0
  510. package/dist/engine/renderers/customMarkers.js.map +1 -0
  511. package/dist/engine/renderers/extremaMarkers.d.ts +6 -0
  512. package/dist/engine/renderers/extremaMarkers.d.ts.map +1 -0
  513. package/dist/engine/renderers/extremaMarkers.js +181 -0
  514. package/dist/engine/renderers/extremaMarkers.js.map +1 -0
  515. package/dist/engine/renderers/gridLines.d.ts +8 -0
  516. package/dist/engine/renderers/gridLines.d.ts.map +1 -0
  517. package/dist/engine/renderers/gridLines.js +84 -0
  518. package/dist/engine/renderers/gridLines.js.map +1 -0
  519. package/dist/engine/renderers/lastPrice.d.ts +10 -0
  520. package/dist/engine/renderers/lastPrice.d.ts.map +1 -0
  521. package/dist/engine/renderers/lastPrice.js +87 -0
  522. package/dist/engine/renderers/lastPrice.js.map +1 -0
  523. package/dist/engine/renderers/paneTitle.d.ts +41 -0
  524. package/dist/engine/renderers/paneTitle.d.ts.map +1 -0
  525. package/dist/engine/renderers/paneTitle.js +86 -0
  526. package/dist/engine/renderers/paneTitle.js.map +1 -0
  527. package/dist/engine/renderers/subVolume.d.ts +14 -0
  528. package/dist/engine/renderers/subVolume.d.ts.map +1 -0
  529. package/dist/engine/renderers/subVolume.js +247 -0
  530. package/dist/engine/renderers/subVolume.js.map +1 -0
  531. package/dist/engine/renderers/timeAxis.d.ts +15 -0
  532. package/dist/engine/renderers/timeAxis.d.ts.map +1 -0
  533. package/dist/engine/renderers/timeAxis.js +107 -0
  534. package/dist/engine/renderers/timeAxis.js.map +1 -0
  535. package/dist/engine/renderers/webgl/candleSurface.d.ts +81 -0
  536. package/dist/engine/renderers/webgl/candleSurface.d.ts.map +1 -0
  537. package/dist/engine/renderers/webgl/candleSurface.js +811 -0
  538. package/dist/engine/renderers/webgl/candleSurface.js.map +1 -0
  539. package/dist/engine/renderers/webgl/sharedWebGLSurface.d.ts +34 -0
  540. package/dist/engine/renderers/webgl/sharedWebGLSurface.d.ts.map +1 -0
  541. package/dist/engine/renderers/webgl/sharedWebGLSurface.js +102 -0
  542. package/dist/engine/renderers/webgl/sharedWebGLSurface.js.map +1 -0
  543. package/dist/engine/renderers/yAxis.d.ts +15 -0
  544. package/dist/engine/renderers/yAxis.d.ts.map +1 -0
  545. package/dist/engine/renderers/yAxis.js +93 -0
  546. package/dist/engine/renderers/yAxis.js.map +1 -0
  547. package/dist/engine/scale/logFormula.d.ts +67 -0
  548. package/dist/engine/scale/logFormula.d.ts.map +1 -0
  549. package/dist/engine/scale/logFormula.js +107 -0
  550. package/dist/engine/scale/logFormula.js.map +1 -0
  551. package/dist/engine/scale/price.d.ts +12 -0
  552. package/dist/engine/scale/price.d.ts.map +1 -0
  553. package/dist/engine/scale/price.js +20 -0
  554. package/dist/engine/scale/price.js.map +1 -0
  555. package/dist/engine/scale/priceScale.d.ts +88 -0
  556. package/dist/engine/scale/priceScale.d.ts.map +1 -0
  557. package/dist/engine/scale/priceScale.js +227 -0
  558. package/dist/engine/scale/priceScale.js.map +1 -0
  559. package/dist/engine/subPaneManager.d.ts +23 -0
  560. package/dist/engine/subPaneManager.d.ts.map +1 -0
  561. package/dist/engine/subPaneManager.js +342 -0
  562. package/dist/engine/subPaneManager.js.map +1 -0
  563. package/dist/engine/theme/colors.d.ts +223 -0
  564. package/dist/engine/theme/colors.d.ts.map +1 -0
  565. package/dist/engine/theme/colors.js +375 -0
  566. package/dist/engine/theme/colors.js.map +1 -0
  567. package/dist/engine/theme/fonts.d.ts +13 -0
  568. package/dist/engine/theme/fonts.d.ts.map +1 -0
  569. package/dist/engine/theme/fonts.js +18 -0
  570. package/dist/engine/theme/fonts.js.map +1 -0
  571. package/dist/engine/utils/klineConfig.d.ts +29 -0
  572. package/dist/engine/utils/klineConfig.d.ts.map +1 -0
  573. package/dist/engine/utils/klineConfig.js +46 -0
  574. package/dist/engine/utils/klineConfig.js.map +1 -0
  575. package/dist/engine/utils/tickCount.d.ts +9 -0
  576. package/dist/engine/utils/tickCount.d.ts.map +1 -0
  577. package/dist/engine/utils/tickCount.js +12 -0
  578. package/dist/engine/utils/tickCount.js.map +1 -0
  579. package/dist/engine/utils/tickPosition.d.ts +25 -0
  580. package/dist/engine/utils/tickPosition.d.ts.map +1 -0
  581. package/dist/engine/utils/tickPosition.js +141 -0
  582. package/dist/engine/utils/tickPosition.js.map +1 -0
  583. package/dist/engine/utils/zoom.d.ts +31 -0
  584. package/dist/engine/utils/zoom.d.ts.map +1 -0
  585. package/dist/engine/utils/zoom.js +43 -0
  586. package/dist/engine/utils/zoom.js.map +1 -0
  587. package/dist/engine/viewport/viewport.d.ts +32 -0
  588. package/dist/engine/viewport/viewport.d.ts.map +1 -0
  589. package/dist/engine/viewport/viewport.js +54 -0
  590. package/dist/engine/viewport/viewport.js.map +1 -0
  591. package/dist/index.d.ts +4 -0
  592. package/dist/index.d.ts.map +1 -0
  593. package/dist/index.js +4 -0
  594. package/dist/index.js.map +1 -0
  595. package/dist/plugin/ConfigManager.d.ts +32 -0
  596. package/dist/plugin/ConfigManager.d.ts.map +1 -0
  597. package/dist/plugin/ConfigManager.js +81 -0
  598. package/dist/plugin/ConfigManager.js.map +1 -0
  599. package/dist/plugin/EventBus.d.ts +38 -0
  600. package/dist/plugin/EventBus.d.ts.map +1 -0
  601. package/dist/plugin/EventBus.js +66 -0
  602. package/dist/plugin/EventBus.js.map +1 -0
  603. package/dist/plugin/HookSystem.d.ts +32 -0
  604. package/dist/plugin/HookSystem.d.ts.map +1 -0
  605. package/dist/plugin/HookSystem.js +86 -0
  606. package/dist/plugin/HookSystem.js.map +1 -0
  607. package/dist/plugin/PluginHost.d.ts +61 -0
  608. package/dist/plugin/PluginHost.d.ts.map +1 -0
  609. package/dist/plugin/PluginHost.js +196 -0
  610. package/dist/plugin/PluginHost.js.map +1 -0
  611. package/dist/plugin/PluginRegistry.d.ts +44 -0
  612. package/dist/plugin/PluginRegistry.d.ts.map +1 -0
  613. package/dist/plugin/PluginRegistry.js +77 -0
  614. package/dist/plugin/PluginRegistry.js.map +1 -0
  615. package/dist/plugin/StateStore.d.ts +42 -0
  616. package/dist/plugin/StateStore.d.ts.map +1 -0
  617. package/dist/plugin/StateStore.js +63 -0
  618. package/dist/plugin/StateStore.js.map +1 -0
  619. package/dist/plugin/index.d.ts +12 -0
  620. package/dist/plugin/index.d.ts.map +1 -0
  621. package/dist/plugin/index.js +15 -0
  622. package/dist/plugin/index.js.map +1 -0
  623. package/dist/plugin/rendererPluginManager.d.ts +81 -0
  624. package/dist/plugin/rendererPluginManager.d.ts.map +1 -0
  625. package/dist/plugin/rendererPluginManager.js +309 -0
  626. package/dist/plugin/rendererPluginManager.js.map +1 -0
  627. package/dist/plugin/stateKeys.d.ts +7 -0
  628. package/dist/plugin/stateKeys.d.ts.map +1 -0
  629. package/dist/plugin/stateKeys.js +7 -0
  630. package/dist/plugin/stateKeys.js.map +1 -0
  631. package/dist/plugin/types.d.ts +449 -0
  632. package/dist/plugin/types.d.ts.map +1 -0
  633. package/dist/plugin/types.js +63 -0
  634. package/dist/plugin/types.js.map +1 -0
  635. package/dist/reactivity/index.d.ts +3 -0
  636. package/dist/reactivity/index.d.ts.map +1 -0
  637. package/dist/reactivity/index.js +2 -0
  638. package/dist/reactivity/index.js.map +1 -0
  639. package/dist/reactivity/signal.d.ts +40 -0
  640. package/dist/reactivity/signal.d.ts.map +1 -0
  641. package/dist/reactivity/signal.js +92 -0
  642. package/dist/reactivity/signal.js.map +1 -0
  643. package/dist/semantic/controller.d.ts +41 -0
  644. package/dist/semantic/controller.d.ts.map +1 -0
  645. package/dist/semantic/controller.js +189 -0
  646. package/dist/semantic/controller.js.map +1 -0
  647. package/dist/semantic/drawShape.d.ts +19 -0
  648. package/dist/semantic/drawShape.d.ts.map +1 -0
  649. package/dist/semantic/drawShape.js +209 -0
  650. package/dist/semantic/drawShape.js.map +1 -0
  651. package/dist/semantic/index.d.ts +6 -0
  652. package/dist/semantic/index.d.ts.map +1 -0
  653. package/dist/semantic/index.js +4 -0
  654. package/dist/semantic/index.js.map +1 -0
  655. package/dist/semantic/schema.json +256 -0
  656. package/dist/semantic/types.d.ts +299 -0
  657. package/dist/semantic/types.d.ts.map +1 -0
  658. package/dist/semantic/types.js +6 -0
  659. package/dist/semantic/types.js.map +1 -0
  660. package/dist/semantic/validator.d.ts +48 -0
  661. package/dist/semantic/validator.d.ts.map +1 -0
  662. package/dist/semantic/validator.js +288 -0
  663. package/dist/semantic/validator.js.map +1 -0
  664. package/dist/types/kLine.d.ts +4 -0
  665. package/dist/types/kLine.d.ts.map +1 -0
  666. package/dist/types/kLine.js +12 -0
  667. package/dist/types/kLine.js.map +1 -0
  668. package/dist/types/price.d.ts +32 -0
  669. package/dist/types/price.d.ts.map +1 -0
  670. package/dist/types/price.js +19 -0
  671. package/dist/types/price.js.map +1 -0
  672. package/dist/types/volumePrice.d.ts +27 -0
  673. package/dist/types/volumePrice.d.ts.map +1 -0
  674. package/dist/types/volumePrice.js +23 -0
  675. package/dist/types/volumePrice.js.map +1 -0
  676. package/dist/utils/dateFormat.d.ts +84 -0
  677. package/dist/utils/dateFormat.d.ts.map +1 -0
  678. package/dist/utils/dateFormat.js +193 -0
  679. package/dist/utils/dateFormat.js.map +1 -0
  680. package/dist/utils/kLineDraw/axis.d.ts +151 -0
  681. package/dist/utils/kLineDraw/axis.d.ts.map +1 -0
  682. package/dist/utils/kLineDraw/axis.js +243 -0
  683. package/dist/utils/kLineDraw/axis.js.map +1 -0
  684. package/dist/utils/priceToY.d.ts +8 -0
  685. package/dist/utils/priceToY.d.ts.map +1 -0
  686. package/dist/utils/priceToY.js +19 -0
  687. package/dist/utils/priceToY.js.map +1 -0
  688. package/dist/utils/volumePrice.d.ts +55 -0
  689. package/dist/utils/volumePrice.d.ts.map +1 -0
  690. package/dist/utils/volumePrice.js +170 -0
  691. package/dist/utils/volumePrice.js.map +1 -0
  692. package/dist/version.d.ts +2 -0
  693. package/dist/version.d.ts.map +1 -0
  694. package/dist/version.js +3 -0
  695. package/dist/version.js.map +1 -0
  696. package/package.json +122 -0
  697. package/src/__tests__/signal.test.ts +124 -0
  698. package/src/config/chartSettings.ts +66 -0
  699. package/src/controllers/__tests__/drawing.test.ts +214 -0
  700. package/src/controllers/__tests__/indicatorSelector.test.ts +481 -0
  701. package/src/controllers/__tests__/toolbar.test.ts +225 -0
  702. package/src/controllers/createChartController.ts +665 -0
  703. package/src/controllers/createDrawingController.ts +96 -0
  704. package/src/controllers/createIndicatorSelectorController.ts +307 -0
  705. package/src/controllers/createToolbarController.ts +146 -0
  706. package/src/controllers/index.ts +19 -0
  707. package/src/controllers/types.ts +284 -0
  708. package/src/engine/__tests__/chart.dpr.test.ts +401 -0
  709. package/src/engine/__tests__/paneRenderer.resize.test.ts +92 -0
  710. package/src/engine/chart-store.ts +121 -0
  711. package/src/engine/chart.d.ts +618 -0
  712. package/src/engine/chart.ts +2815 -0
  713. package/src/engine/controller/__tests__/interaction.dpr.test.ts +259 -0
  714. package/src/engine/controller/interaction.ts +722 -0
  715. package/src/engine/controller/markerInteraction.ts +130 -0
  716. package/src/engine/controller/pinchTracker.ts +82 -0
  717. package/src/engine/controller/tooltipPosition.ts +48 -0
  718. package/src/engine/draw/__tests__/pixelAlign.spec.ts +177 -0
  719. package/src/engine/draw/pixelAlign.ts +260 -0
  720. package/src/engine/drawing/index.ts +655 -0
  721. package/src/engine/drawing/interaction.ts +842 -0
  722. package/src/engine/drawing/plugin.ts +343 -0
  723. package/src/engine/indicators/__tests__/__fixtures__/golden/atr.json +38 -0
  724. package/src/engine/indicators/__tests__/__fixtures__/golden/dema.json +14 -0
  725. package/src/engine/indicators/__tests__/__fixtures__/golden/hma.json +14 -0
  726. package/src/engine/indicators/__tests__/__fixtures__/golden/index.ts +55 -0
  727. package/src/engine/indicators/__tests__/__fixtures__/golden/kama.json +14 -0
  728. package/src/engine/indicators/__tests__/__fixtures__/golden/tema.json +14 -0
  729. package/src/engine/indicators/__tests__/__fixtures__/golden/wma.json +40 -0
  730. package/src/engine/indicators/__tests__/__fixtures__/synthetic.ts +65 -0
  731. package/src/engine/indicators/__tests__/_propertyAssertions.ts +76 -0
  732. package/src/engine/indicators/__tests__/atr.test.ts +153 -0
  733. package/src/engine/indicators/__tests__/calculators.test.ts +614 -0
  734. package/src/engine/indicators/__tests__/cmf-mfi.test.ts +100 -0
  735. package/src/engine/indicators/__tests__/dema.test.ts +73 -0
  736. package/src/engine/indicators/__tests__/donchian.test.ts +70 -0
  737. package/src/engine/indicators/__tests__/hma.test.ts +73 -0
  738. package/src/engine/indicators/__tests__/ichimoku.test.ts +105 -0
  739. package/src/engine/indicators/__tests__/kama.test.ts +80 -0
  740. package/src/engine/indicators/__tests__/keltner.test.ts +65 -0
  741. package/src/engine/indicators/__tests__/pivot-fib.test.ts +110 -0
  742. package/src/engine/indicators/__tests__/roc.test.ts +68 -0
  743. package/src/engine/indicators/__tests__/sar.test.ts +86 -0
  744. package/src/engine/indicators/__tests__/scheduler.test.ts +831 -0
  745. package/src/engine/indicators/__tests__/soa.test.ts +533 -0
  746. package/src/engine/indicators/__tests__/structure.test.ts +110 -0
  747. package/src/engine/indicators/__tests__/supertrend.test.ts +65 -0
  748. package/src/engine/indicators/__tests__/tema.test.ts +68 -0
  749. package/src/engine/indicators/__tests__/trix.test.ts +70 -0
  750. package/src/engine/indicators/__tests__/volatility.test.ts +117 -0
  751. package/src/engine/indicators/__tests__/volume.test.ts +115 -0
  752. package/src/engine/indicators/__tests__/volumeProfile.test.ts +74 -0
  753. package/src/engine/indicators/__tests__/vwap.test.ts +69 -0
  754. package/src/engine/indicators/__tests__/wma.test.ts +112 -0
  755. package/src/engine/indicators/__tests__/zones.test.ts +95 -0
  756. package/src/engine/indicators/atrState.ts +27 -0
  757. package/src/engine/indicators/bollState.ts +51 -0
  758. package/src/engine/indicators/calculators.ts +2593 -0
  759. package/src/engine/indicators/cciState.ts +25 -0
  760. package/src/engine/indicators/chaikinVolState.ts +32 -0
  761. package/src/engine/indicators/cmfState.ts +27 -0
  762. package/src/engine/indicators/demaState.ts +27 -0
  763. package/src/engine/indicators/donchianState.ts +43 -0
  764. package/src/engine/indicators/eneState.ts +43 -0
  765. package/src/engine/indicators/expmaState.ts +43 -0
  766. package/src/engine/indicators/fastkState.ts +25 -0
  767. package/src/engine/indicators/fibState.ts +41 -0
  768. package/src/engine/indicators/hmaState.ts +27 -0
  769. package/src/engine/indicators/hvState.ts +28 -0
  770. package/src/engine/indicators/ichimokuState.ts +70 -0
  771. package/src/engine/indicators/indicator.worker.ts +169 -0
  772. package/src/engine/indicators/indicatorDefinitionRegistry.ts +62 -0
  773. package/src/engine/indicators/indicatorMetadata.ts +110 -0
  774. package/src/engine/indicators/indicatorRegistry.ts +106 -0
  775. package/src/engine/indicators/indicatorRuntime.ts +1548 -0
  776. package/src/engine/indicators/kamaState.ts +34 -0
  777. package/src/engine/indicators/keltnerState.ts +49 -0
  778. package/src/engine/indicators/kstState.ts +42 -0
  779. package/src/engine/indicators/maState.ts +36 -0
  780. package/src/engine/indicators/macdState.ts +76 -0
  781. package/src/engine/indicators/mfiState.ts +27 -0
  782. package/src/engine/indicators/momState.ts +25 -0
  783. package/src/engine/indicators/obvState.ts +25 -0
  784. package/src/engine/indicators/parkinsonState.ts +28 -0
  785. package/src/engine/indicators/pivotState.ts +51 -0
  786. package/src/engine/indicators/pvtState.ts +25 -0
  787. package/src/engine/indicators/rocState.ts +27 -0
  788. package/src/engine/indicators/rsiState.ts +65 -0
  789. package/src/engine/indicators/sarState.ts +41 -0
  790. package/src/engine/indicators/scheduler.ts +1205 -0
  791. package/src/engine/indicators/soa.ts +352 -0
  792. package/src/engine/indicators/stateComposer.ts +1262 -0
  793. package/src/engine/indicators/stochState.ts +26 -0
  794. package/src/engine/indicators/structureState.ts +69 -0
  795. package/src/engine/indicators/supertrendState.ts +37 -0
  796. package/src/engine/indicators/temaState.ts +27 -0
  797. package/src/engine/indicators/trixState.ts +35 -0
  798. package/src/engine/indicators/vmaState.ts +27 -0
  799. package/src/engine/indicators/volumeProfileState.ts +63 -0
  800. package/src/engine/indicators/vwapState.ts +29 -0
  801. package/src/engine/indicators/wmaState.ts +27 -0
  802. package/src/engine/indicators/wmsrState.ts +25 -0
  803. package/src/engine/indicators/workerProtocol.ts +613 -0
  804. package/src/engine/indicators/zonesState.ts +47 -0
  805. package/src/engine/layout/pane.ts +161 -0
  806. package/src/engine/marker/registry.ts +266 -0
  807. package/src/engine/paneRenderer.ts +169 -0
  808. package/src/engine/renderers/Indicator/atr.ts +237 -0
  809. package/src/engine/renderers/Indicator/boll.ts +317 -0
  810. package/src/engine/renderers/Indicator/cci.ts +275 -0
  811. package/src/engine/renderers/Indicator/chaikinVol.ts +138 -0
  812. package/src/engine/renderers/Indicator/cmf.ts +137 -0
  813. package/src/engine/renderers/Indicator/dema.ts +136 -0
  814. package/src/engine/renderers/Indicator/donchian.ts +138 -0
  815. package/src/engine/renderers/Indicator/ene.ts +271 -0
  816. package/src/engine/renderers/Indicator/expma.ts +197 -0
  817. package/src/engine/renderers/Indicator/fastk.ts +316 -0
  818. package/src/engine/renderers/Indicator/fib.ts +141 -0
  819. package/src/engine/renderers/Indicator/hma.ts +136 -0
  820. package/src/engine/renderers/Indicator/hv.ts +124 -0
  821. package/src/engine/renderers/Indicator/ichimoku.ts +182 -0
  822. package/src/engine/renderers/Indicator/index.ts +241 -0
  823. package/src/engine/renderers/Indicator/indicatorData.ts +650 -0
  824. package/src/engine/renderers/Indicator/kama.ts +136 -0
  825. package/src/engine/renderers/Indicator/keltner.ts +138 -0
  826. package/src/engine/renderers/Indicator/kst.ts +302 -0
  827. package/src/engine/renderers/Indicator/ma.ts +200 -0
  828. package/src/engine/renderers/Indicator/macd.ts +477 -0
  829. package/src/engine/renderers/Indicator/macdLegend.ts +141 -0
  830. package/src/engine/renderers/Indicator/mainIndicatorLegend.ts +272 -0
  831. package/src/engine/renderers/Indicator/mfi.ts +142 -0
  832. package/src/engine/renderers/Indicator/mom.ts +311 -0
  833. package/src/engine/renderers/Indicator/obv.ts +123 -0
  834. package/src/engine/renderers/Indicator/parkinson.ts +124 -0
  835. package/src/engine/renderers/Indicator/pivot.ts +131 -0
  836. package/src/engine/renderers/Indicator/pvt.ts +123 -0
  837. package/src/engine/renderers/Indicator/roc.ts +143 -0
  838. package/src/engine/renderers/Indicator/rsi.ts +390 -0
  839. package/src/engine/renderers/Indicator/sar.ts +113 -0
  840. package/src/engine/renderers/Indicator/scale/atr_scale.ts +19 -0
  841. package/src/engine/renderers/Indicator/scale/cci_scale.ts +19 -0
  842. package/src/engine/renderers/Indicator/scale/fastk_scale.ts +19 -0
  843. package/src/engine/renderers/Indicator/scale/indicator_scale.ts +204 -0
  844. package/src/engine/renderers/Indicator/scale/kst_scale.ts +19 -0
  845. package/src/engine/renderers/Indicator/scale/macd_scale.ts +22 -0
  846. package/src/engine/renderers/Indicator/scale/mom_scale.ts +19 -0
  847. package/src/engine/renderers/Indicator/scale/rsi_scale.ts +19 -0
  848. package/src/engine/renderers/Indicator/scale/stoch_scale.ts +19 -0
  849. package/src/engine/renderers/Indicator/scale/volume_scale.ts +26 -0
  850. package/src/engine/renderers/Indicator/scale/wmsr_scale.ts +19 -0
  851. package/src/engine/renderers/Indicator/stoch.ts +359 -0
  852. package/src/engine/renderers/Indicator/structure.ts +126 -0
  853. package/src/engine/renderers/Indicator/subPaneConfig.ts +265 -0
  854. package/src/engine/renderers/Indicator/supertrend.ts +115 -0
  855. package/src/engine/renderers/Indicator/tema.ts +136 -0
  856. package/src/engine/renderers/Indicator/trix.ts +158 -0
  857. package/src/engine/renderers/Indicator/vma.ts +124 -0
  858. package/src/engine/renderers/Indicator/volumeProfile.ts +125 -0
  859. package/src/engine/renderers/Indicator/vwap.ts +123 -0
  860. package/src/engine/renderers/Indicator/wma.ts +136 -0
  861. package/src/engine/renderers/Indicator/wmsr.ts +328 -0
  862. package/src/engine/renderers/Indicator/zones.ts +105 -0
  863. package/src/engine/renderers/__tests__/boll.renderer.test.ts +314 -0
  864. package/src/engine/renderers/__tests__/ene.renderer.test.ts +305 -0
  865. package/src/engine/renderers/__tests__/expma.renderer.test.ts +279 -0
  866. package/src/engine/renderers/__tests__/ma.renderer.test.ts +426 -0
  867. package/src/engine/renderers/__tests__/mainIndicatorLegend.renderer.test.ts +502 -0
  868. package/src/engine/renderers/__tests__/yAxis.renderer.test.ts +173 -0
  869. package/src/engine/renderers/candle.ts +459 -0
  870. package/src/engine/renderers/crosshair.ts +69 -0
  871. package/src/engine/renderers/customMarkers.ts +162 -0
  872. package/src/engine/renderers/extremaMarkers.ts +246 -0
  873. package/src/engine/renderers/gridLines.ts +90 -0
  874. package/src/engine/renderers/lastPrice.ts +97 -0
  875. package/src/engine/renderers/paneTitle.ts +136 -0
  876. package/src/engine/renderers/subVolume.ts +236 -0
  877. package/src/engine/renderers/timeAxis.ts +121 -0
  878. package/src/engine/renderers/webgl/candleSurface.ts +955 -0
  879. package/src/engine/renderers/webgl/sharedWebGLSurface.ts +146 -0
  880. package/src/engine/renderers/yAxis.ts +105 -0
  881. package/src/engine/scale/__tests__/logFormula.spec.ts +148 -0
  882. package/src/engine/scale/logFormula.ts +130 -0
  883. package/src/engine/scale/price.ts +39 -0
  884. package/src/engine/scale/priceScale.ts +264 -0
  885. package/src/engine/subPaneManager.ts +427 -0
  886. package/src/engine/theme/colors.ts +642 -0
  887. package/src/engine/theme/fonts.ts +20 -0
  888. package/src/engine/utils/klineConfig.ts +49 -0
  889. package/src/engine/utils/tickCount.ts +11 -0
  890. package/src/engine/utils/tickPosition.ts +214 -0
  891. package/src/engine/utils/zoom.ts +83 -0
  892. package/src/engine/viewport/viewport.ts +67 -0
  893. package/src/index.ts +3 -0
  894. package/src/plugin/ConfigManager.ts +93 -0
  895. package/src/plugin/EventBus.ts +77 -0
  896. package/src/plugin/HookSystem.ts +106 -0
  897. package/src/plugin/PluginHost.ts +243 -0
  898. package/src/plugin/PluginRegistry.ts +92 -0
  899. package/src/plugin/StateStore.ts +73 -0
  900. package/src/plugin/index.ts +19 -0
  901. package/src/plugin/rendererPluginManager.ts +368 -0
  902. package/src/plugin/stateKeys.ts +8 -0
  903. package/src/plugin/types.ts +526 -0
  904. package/src/reactivity/index.ts +2 -0
  905. package/src/reactivity/signal.ts +119 -0
  906. package/src/semantic/controller.ts +251 -0
  907. package/src/semantic/drawShape.ts +260 -0
  908. package/src/semantic/index.ts +28 -0
  909. package/src/semantic/schema.json +256 -0
  910. package/src/semantic/types.ts +251 -0
  911. package/src/semantic/validator.ts +349 -0
  912. package/src/types/kLine.ts +13 -0
  913. package/src/types/price.ts +56 -0
  914. package/src/types/volumePrice.ts +33 -0
  915. package/src/utils/dateFormat.ts +208 -0
  916. package/src/utils/kLineDraw/axis.ts +562 -0
  917. package/src/utils/priceToY.ts +34 -0
  918. package/src/utils/volumePrice.ts +203 -0
  919. package/src/version.ts +1 -0
@@ -0,0 +1,2285 @@
1
+ import { createSignal } from '../reactivity/signal';
2
+ import { getVisibleRange } from './viewport/viewport';
3
+ import { Pane, UpdateLevel } from './layout/pane';
4
+ import { InteractionController } from './controller/interaction';
5
+ import { PaneRenderer } from './paneRenderer';
6
+ import { SharedWebGLSurface } from './renderers/webgl/sharedWebGLSurface';
7
+ import { MarkerManager } from './marker/registry';
8
+ import { getPhysicalKLineConfig, calcKWidthPx } from './utils/klineConfig';
9
+ import { computeContentWidth } from './chart-store';
10
+ import { computeZoom } from './utils/zoom';
11
+ import { IndicatorScheduler } from './indicators/scheduler';
12
+ import { getRegisteredIndicatorDefinitions } from './indicators/indicatorDefinitionRegistry';
13
+ import { SubPaneManager } from './subPaneManager';
14
+ import { createPluginHost, RendererPluginManager, wrapPaneInfo, } from '../plugin';
15
+ import { createSubIndicatorRenderer } from './renderers/Indicator';
16
+ import { createMARendererPlugin } from './renderers/Indicator/ma';
17
+ import { createBOLLRendererPlugin } from './renderers/Indicator/boll';
18
+ import { createEXPMARendererPlugin } from './renderers/Indicator/expma';
19
+ import { createENERendererPlugin } from './renderers/Indicator/ene';
20
+ import { createWMARendererPlugin } from './renderers/Indicator/wma';
21
+ import { createDEMARendererPlugin } from './renderers/Indicator/dema';
22
+ import { createTEMARendererPlugin } from './renderers/Indicator/tema';
23
+ import { createHMARendererPlugin } from './renderers/Indicator/hma';
24
+ import { createKAMARendererPlugin } from './renderers/Indicator/kama';
25
+ import { createSARRendererPlugin } from './renderers/Indicator/sar';
26
+ import { createSuperTrendRendererPlugin } from './renderers/Indicator/supertrend';
27
+ import { createKeltnerRendererPlugin } from './renderers/Indicator/keltner';
28
+ import { createDonchianRendererPlugin } from './renderers/Indicator/donchian';
29
+ import { createIchimokuRendererPlugin } from './renderers/Indicator/ichimoku';
30
+ import { createPivotRendererPlugin } from './renderers/Indicator/pivot';
31
+ import { createFibRendererPlugin } from './renderers/Indicator/fib';
32
+ import { createStructureRendererPlugin } from './renderers/Indicator/structure';
33
+ import { createZonesRendererPlugin } from './renderers/Indicator/zones';
34
+ import { createMainIndicatorLegendRendererPlugin } from './renderers/Indicator/mainIndicatorLegend';
35
+ import { DrawingStore } from './drawing';
36
+ import { createDrawingRendererPlugin, createDrawingLabelOverlayPlugin } from './drawing/plugin';
37
+ import { createGridLinesRendererPlugin } from './renderers/gridLines';
38
+ import { createCandleRenderer } from './renderers/candle';
39
+ import { createLastPriceLineRendererPlugin, createLastPriceLabelRegistrarPlugin } from './renderers/lastPrice';
40
+ import { createCustomMarkersRenderer } from './renderers/customMarkers';
41
+ import { createYAxisRendererPlugin } from './renderers/yAxis';
42
+ import { createCrosshairRendererPlugin } from './renderers/crosshair';
43
+ import { createTimeAxisRendererPlugin } from './renderers/timeAxis';
44
+ // 重新导出以保持向后兼容
45
+ export { getPhysicalKLineConfig, calcKWidthPx };
46
+ export class Chart {
47
+ dom;
48
+ opt;
49
+ _internalData = [];
50
+ raf = null;
51
+ pendingUpdateLevel = UpdateLevel.All;
52
+ _internalViewport = null;
53
+ paneRenderers = [];
54
+ markerManager;
55
+ drawingStore = new DrawingStore();
56
+ interaction;
57
+ /** 插件宿主 */
58
+ pluginHost;
59
+ /** 渲染器插件管理器 */
60
+ rendererPluginManager;
61
+ /** 精确 DPR(来自 ResizeObserver 的 devicePixelContentBoxSize) */
62
+ preciseDpr = 0;
63
+ /** 统一监听容器尺寸与 DPR 变化 */
64
+ resizeObserver;
65
+ /** scroll 事件处理器引用(用于 cleanup) */
66
+ onScroll;
67
+ /** 最近一次观测到的容器尺寸 */
68
+ observedSize = { width: 0, height: 0 };
69
+ /** 缓存的 scrollLeft(通过 scroll 事件同步,避免每帧读取 DOM 触发强制回流) */
70
+ cachedScrollLeft = 0;
71
+ /** overlay 上一帧是否有十字线(用于判断何时需要清除) */
72
+ overlayHadCrosshair = false;
73
+ /** 用户设置配置(传递给渲染器) */
74
+ settings = {};
75
+ /** pane ratio 状态(按 paneId 维护,sum=1 仅对可见 pane) */
76
+ _internalPaneRatios = new Map();
77
+ /** 视口变化回调(供外部同步 DPR/尺寸) */
78
+ onViewportChange;
79
+ /** 共享 X 轴上下文缓存 */
80
+ xAxisCtx = null;
81
+ /** Chart 级共享 WebGL canvas/context */
82
+ sharedWebGLSurface;
83
+ /** pane 布局回流回调(Chart -> UI 单向) */
84
+ onPaneLayoutChange;
85
+ /** 数据变化回调(供外部同步 dataLength) */
86
+ onDataChange;
87
+ /** 当前缩放级别(1 ~ zoomLevelCount) */
88
+ currentZoomLevel = 1;
89
+ /** 缩放级别总数 */
90
+ zoomLevelCount;
91
+ /** 指标调度器(负责计算 MA 等指标并写入 StateStore)
92
+ * TODO: 阶段5迁移为插件注册,Scheduler 通过事件监听 data/viewport 变更,Chart 不直接持有
93
+ */
94
+ indicatorScheduler;
95
+ /** 上次可见范围(用于检测视口变化) */
96
+ lastVisibleRange = { start: 0, end: 0 };
97
+ /** Overlay 帧复用的最近主渲染结果 */
98
+ cachedDrawFrame = null;
99
+ /** 副图管理器 */
100
+ subPaneManager;
101
+ /** 当前激活的主图指标列表(如 ['boll', 'ma']) */
102
+ activeMainIndicators = new Set();
103
+ /** 主图指标参数配置 */
104
+ mainIndicatorParams = {
105
+ MA: { ma5: true, ma10: true, ma20: true, ma30: true, ma60: true },
106
+ BOLL: { period: 20, multiplier: 2, showUpper: true, showMiddle: true, showLower: true, showBand: true },
107
+ EXPMA: { fastPeriod: 12, slowPeriod: 50 },
108
+ ENE: { period: 10, deviation: 11 },
109
+ WMA: { period: 10, showWMA: true },
110
+ DEMA: { period: 14, showDEMA: true },
111
+ TEMA: { period: 14, showTEMA: true },
112
+ HMA: { period: 14, showHMA: true },
113
+ KAMA: { period: 10, fastPeriod: 2, slowPeriod: 30, showKAMA: true },
114
+ SAR: { step: 0.02, maxStep: 0.2, showSAR: true },
115
+ SUPERTREND: { atrPeriod: 10, multiplier: 3, showSuperTrend: true },
116
+ KELTNER: { emaPeriod: 20, atrPeriod: 10, multiplier: 2, showUpper: true, showMiddle: true, showLower: true },
117
+ DONCHIAN: { period: 20, showUpper: true, showMiddle: true, showLower: true },
118
+ ICHIMOKU: { tenkanPeriod: 9, kijunPeriod: 26, spanBPeriod: 52, displacement: 26, showTenkan: true, showKijun: true, showSpanA: true, showSpanB: true, showChikou: true, showCloud: true },
119
+ PIVOT: { showPP: true, showR1: true, showR2: true, showR3: false, showS1: true, showS2: true, showS3: false },
120
+ FIB: { period: 50, showLevels: true },
121
+ STRUCTURE: { leftWindow: 2, rightWindow: 2, breakoutSource: 'close', showSwingLabels: true, showBOS: true, showCHOCH: true, showProvisional: false },
122
+ ZONES: { showFVG: true, showOB: true, showFilledZones: false, obLookback: 5 },
123
+ };
124
+ /**
125
+ * 启用主图指标
126
+ * @param indicatorId 指标ID
127
+ * @param params 可选的指标参数
128
+ * @returns 是否成功启用
129
+ */
130
+ enableMainIndicator(indicatorId, params) {
131
+ const id = indicatorId.toUpperCase();
132
+ if (!['MA', 'BOLL', 'EXPMA', 'ENE', 'WMA', 'DEMA', 'TEMA', 'HMA', 'KAMA', 'SAR', 'SUPERTREND', 'KELTNER', 'DONCHIAN', 'ICHIMOKU', 'PIVOT', 'FIB', 'STRUCTURE', 'ZONES'].includes(id)) {
133
+ console.warn(`[Chart] 未知的主图指标: ${indicatorId}`);
134
+ return false;
135
+ }
136
+ if (this.activeMainIndicators.has(id)) {
137
+ // 已启用,更新参数
138
+ if (params) {
139
+ this.mainIndicatorParams[id] = { ...this.mainIndicatorParams[id], ...params };
140
+ this.updateIndicatorSchedulerConfig(id);
141
+ this.syncIndicatorsSignal();
142
+ }
143
+ return true;
144
+ }
145
+ this.activeMainIndicators.add(id);
146
+ // 合并默认参数和传入参数
147
+ if (params) {
148
+ this.mainIndicatorParams[id] = { ...this.mainIndicatorParams[id], ...params };
149
+ }
150
+ // 启用对应的渲染器
151
+ this.enableMainIndicatorRenderer(id);
152
+ // 更新调度器配置
153
+ this.updateIndicatorSchedulerConfig(id);
154
+ this.scheduleDraw();
155
+ this.syncIndicatorsSignal();
156
+ return true;
157
+ }
158
+ /**
159
+ * 禁用主图指标
160
+ * @param indicatorId 指标ID
161
+ * @returns 是否成功禁用
162
+ */
163
+ disableMainIndicator(indicatorId) {
164
+ const id = indicatorId.toUpperCase();
165
+ if (!this.activeMainIndicators.has(id))
166
+ return false;
167
+ this.activeMainIndicators.delete(id);
168
+ // 禁用对应的渲染器
169
+ this.disableMainIndicatorRenderer(id);
170
+ // 更新调度器配置
171
+ this.updateIndicatorSchedulerConfig(id);
172
+ this.scheduleDraw();
173
+ this.syncIndicatorsSignal();
174
+ return true;
175
+ }
176
+ /**
177
+ * 切换主图指标启用状态
178
+ * @param indicatorId 指标ID
179
+ * @param enabled 是否启用
180
+ */
181
+ toggleMainIndicator(indicatorId, enabled) {
182
+ if (enabled) {
183
+ this.enableMainIndicator(indicatorId);
184
+ }
185
+ else {
186
+ this.disableMainIndicator(indicatorId);
187
+ }
188
+ }
189
+ /**
190
+ * 获取当前激活的主图指标列表
191
+ * @returns 激活的指标ID数组
192
+ */
193
+ getActiveMainIndicators() {
194
+ return Array.from(this.activeMainIndicators);
195
+ }
196
+ /**
197
+ * 检查主图指标是否激活
198
+ * @param indicatorId 指标ID
199
+ */
200
+ isMainIndicatorActive(indicatorId) {
201
+ return this.activeMainIndicators.has(indicatorId.toUpperCase());
202
+ }
203
+ /**
204
+ * 更新主图指标参数
205
+ * @param indicatorId 指标ID
206
+ * @param params 参数对象
207
+ */
208
+ updateMainIndicatorParams(indicatorId, params) {
209
+ const id = indicatorId.toUpperCase();
210
+ if (!this.mainIndicatorParams[id]) {
211
+ this.mainIndicatorParams[id] = {};
212
+ }
213
+ this.mainIndicatorParams[id] = { ...this.mainIndicatorParams[id], ...params };
214
+ // 同步更新渲染器配置
215
+ const rendererName = id.toLowerCase();
216
+ const renderer = this.getRenderer(rendererName);
217
+ if (renderer && renderer.setConfig) {
218
+ renderer.setConfig(this.mainIndicatorParams[id]);
219
+ }
220
+ // 更新调度器
221
+ this.updateIndicatorSchedulerConfig(id);
222
+ this.scheduleDraw();
223
+ this.syncIndicatorsSignal();
224
+ }
225
+ /**
226
+ * 获取主图指标参数
227
+ * @param indicatorId 指标ID
228
+ */
229
+ getMainIndicatorParams(indicatorId) {
230
+ return this.mainIndicatorParams[indicatorId.toUpperCase()] ?? null;
231
+ }
232
+ /**
233
+ * 清除所有主图指标
234
+ */
235
+ clearMainIndicators() {
236
+ for (const id of this.activeMainIndicators) {
237
+ this.disableMainIndicatorRenderer(id);
238
+ }
239
+ this.activeMainIndicators.clear();
240
+ this.scheduleDraw();
241
+ this.syncIndicatorsSignal();
242
+ }
243
+ /**
244
+ * 启用主图指标渲染器(内部方法)
245
+ */
246
+ enableMainIndicatorRenderer(indicatorId) {
247
+ const rendererMap = {
248
+ 'MA': () => {
249
+ if (!this.getRenderer('ma')) {
250
+ this.useRenderer(createMARendererPlugin());
251
+ }
252
+ this.setRendererEnabled('ma', true);
253
+ },
254
+ 'BOLL': () => {
255
+ if (!this.getRenderer('boll')) {
256
+ this.useRenderer(createBOLLRendererPlugin());
257
+ }
258
+ this.setRendererEnabled('boll', true);
259
+ },
260
+ 'EXPMA': () => {
261
+ if (!this.getRenderer('expma')) {
262
+ this.useRenderer(createEXPMARendererPlugin());
263
+ }
264
+ this.setRendererEnabled('expma', true);
265
+ },
266
+ 'ENE': () => {
267
+ if (!this.getRenderer('ene')) {
268
+ this.useRenderer(createENERendererPlugin());
269
+ }
270
+ this.setRendererEnabled('ene', true);
271
+ },
272
+ 'WMA': () => {
273
+ if (!this.getRenderer('wma_main')) {
274
+ this.useRenderer(createWMARendererPlugin({ paneId: 'main' }));
275
+ }
276
+ this.setRendererEnabled('wma_main', true);
277
+ },
278
+ 'DEMA': () => {
279
+ if (!this.getRenderer('dema_main')) {
280
+ this.useRenderer(createDEMARendererPlugin({ paneId: 'main' }));
281
+ }
282
+ this.setRendererEnabled('dema_main', true);
283
+ },
284
+ 'TEMA': () => {
285
+ if (!this.getRenderer('tema_main')) {
286
+ this.useRenderer(createTEMARendererPlugin({ paneId: 'main' }));
287
+ }
288
+ this.setRendererEnabled('tema_main', true);
289
+ },
290
+ 'HMA': () => {
291
+ if (!this.getRenderer('hma_main')) {
292
+ this.useRenderer(createHMARendererPlugin({ paneId: 'main' }));
293
+ }
294
+ this.setRendererEnabled('hma_main', true);
295
+ },
296
+ 'KAMA': () => {
297
+ if (!this.getRenderer('kama_main')) {
298
+ this.useRenderer(createKAMARendererPlugin({ paneId: 'main' }));
299
+ }
300
+ this.setRendererEnabled('kama_main', true);
301
+ },
302
+ 'SAR': () => {
303
+ if (!this.getRenderer('sar_main')) {
304
+ this.useRenderer(createSARRendererPlugin({ paneId: 'main' }));
305
+ }
306
+ this.setRendererEnabled('sar_main', true);
307
+ },
308
+ 'SUPERTREND': () => {
309
+ if (!this.getRenderer('supertrend_main')) {
310
+ this.useRenderer(createSuperTrendRendererPlugin({ paneId: 'main' }));
311
+ }
312
+ this.setRendererEnabled('supertrend_main', true);
313
+ },
314
+ 'KELTNER': () => {
315
+ if (!this.getRenderer('keltner_main')) {
316
+ this.useRenderer(createKeltnerRendererPlugin({ paneId: 'main' }));
317
+ }
318
+ this.setRendererEnabled('keltner_main', true);
319
+ },
320
+ 'DONCHIAN': () => {
321
+ if (!this.getRenderer('donchian_main')) {
322
+ this.useRenderer(createDonchianRendererPlugin({ paneId: 'main' }));
323
+ }
324
+ this.setRendererEnabled('donchian_main', true);
325
+ },
326
+ 'ICHIMOKU': () => {
327
+ if (!this.getRenderer('ichimoku_main')) {
328
+ this.useRenderer(createIchimokuRendererPlugin({ paneId: 'main' }));
329
+ }
330
+ this.setRendererEnabled('ichimoku_main', true);
331
+ },
332
+ 'PIVOT': () => {
333
+ if (!this.getRenderer('pivot_main')) {
334
+ this.useRenderer(createPivotRendererPlugin({ paneId: 'main' }));
335
+ }
336
+ this.setRendererEnabled('pivot_main', true);
337
+ },
338
+ 'FIB': () => {
339
+ if (!this.getRenderer('fib_main')) {
340
+ this.useRenderer(createFibRendererPlugin({ paneId: 'main' }));
341
+ }
342
+ this.setRendererEnabled('fib_main', true);
343
+ },
344
+ 'STRUCTURE': () => {
345
+ if (!this.getRenderer('structure_main')) {
346
+ this.useRenderer(createStructureRendererPlugin({ paneId: 'main' }));
347
+ }
348
+ this.setRendererEnabled('structure_main', true);
349
+ },
350
+ 'ZONES': () => {
351
+ if (!this.getRenderer('zones_main')) {
352
+ this.useRenderer(createZonesRendererPlugin({ paneId: 'main' }));
353
+ }
354
+ this.setRendererEnabled('zones_main', true);
355
+ },
356
+ };
357
+ const fn = rendererMap[indicatorId];
358
+ if (fn)
359
+ fn();
360
+ // 确保图例渲染器已注册
361
+ if (!this.getRenderer('mainIndicatorLegend')) {
362
+ this.useRenderer(createMainIndicatorLegendRendererPlugin({ yPaddingPx: this.opt.yPaddingPx }));
363
+ }
364
+ }
365
+ /**
366
+ * 禁用主图指标渲染器(内部方法)
367
+ */
368
+ disableMainIndicatorRenderer(indicatorId) {
369
+ const rendererMap = {
370
+ 'MA': 'ma',
371
+ 'BOLL': 'boll',
372
+ 'EXPMA': 'expma',
373
+ 'ENE': 'ene',
374
+ 'WMA': 'wma_main',
375
+ 'DEMA': 'dema_main',
376
+ 'TEMA': 'tema_main',
377
+ 'HMA': 'hma_main',
378
+ 'KAMA': 'kama_main',
379
+ 'SAR': 'sar_main',
380
+ 'SUPERTREND': 'supertrend_main',
381
+ 'KELTNER': 'keltner_main',
382
+ 'DONCHIAN': 'donchian_main',
383
+ 'ICHIMOKU': 'ichimoku_main',
384
+ 'PIVOT': 'pivot_main',
385
+ 'FIB': 'fib_main',
386
+ 'STRUCTURE': 'structure_main',
387
+ 'ZONES': 'zones_main',
388
+ };
389
+ const rendererName = rendererMap[indicatorId];
390
+ if (rendererName) {
391
+ this.setRendererEnabled(rendererName, false);
392
+ }
393
+ }
394
+ /**
395
+ * 更新调度器配置(内部方法)
396
+ */
397
+ updateIndicatorSchedulerConfig(indicatorId) {
398
+ const isActive = this.activeMainIndicators.has(indicatorId);
399
+ const params = this.mainIndicatorParams[indicatorId] || {};
400
+ switch (indicatorId) {
401
+ case 'MA':
402
+ this.indicatorScheduler.updateMAConfig({
403
+ ma5: isActive,
404
+ ma10: isActive,
405
+ ma20: isActive,
406
+ ma30: isActive,
407
+ ma60: isActive,
408
+ });
409
+ break;
410
+ case 'BOLL':
411
+ if (isActive) {
412
+ this.indicatorScheduler.updateBOLLConfig(params);
413
+ }
414
+ else {
415
+ this.indicatorScheduler.updateBOLLConfig({ ...params, showUpper: false, showMiddle: false, showLower: false, showBand: false });
416
+ }
417
+ break;
418
+ case 'EXPMA':
419
+ if (isActive) {
420
+ this.indicatorScheduler.updateEXPMAConfig(params);
421
+ }
422
+ break;
423
+ case 'ENE':
424
+ if (isActive) {
425
+ this.indicatorScheduler.updateENEConfig(params);
426
+ }
427
+ break;
428
+ case 'WMA':
429
+ this.indicatorScheduler.updateWMAConfig({ ...params, showWMA: isActive }, 'main');
430
+ break;
431
+ case 'DEMA':
432
+ this.indicatorScheduler.updateDEMAConfig({ ...params, showDEMA: isActive }, 'main');
433
+ break;
434
+ case 'TEMA':
435
+ this.indicatorScheduler.updateTEMAConfig({ ...params, showTEMA: isActive }, 'main');
436
+ break;
437
+ case 'HMA':
438
+ this.indicatorScheduler.updateHMAConfig({ ...params, showHMA: isActive }, 'main');
439
+ break;
440
+ case 'KAMA':
441
+ this.indicatorScheduler.updateKAMAConfig({ ...params, showKAMA: isActive }, 'main');
442
+ break;
443
+ case 'SAR':
444
+ this.indicatorScheduler.updateSARConfig({ ...params, showSAR: isActive }, 'main');
445
+ break;
446
+ case 'SUPERTREND':
447
+ this.indicatorScheduler.updateSuperTrendConfig({ ...params, showSuperTrend: isActive }, 'main');
448
+ break;
449
+ case 'KELTNER':
450
+ this.indicatorScheduler.updateKeltnerConfig({ ...params, showUpper: isActive, showMiddle: isActive, showLower: isActive }, 'main');
451
+ break;
452
+ case 'DONCHIAN':
453
+ this.indicatorScheduler.updateDonchianConfig({ ...params, showUpper: isActive, showMiddle: isActive, showLower: isActive }, 'main');
454
+ break;
455
+ case 'ICHIMOKU':
456
+ this.indicatorScheduler.updateIchimokuConfig({ ...params, showTenkan: isActive, showKijun: isActive, showSpanA: isActive, showSpanB: isActive, showChikou: isActive, showCloud: isActive }, 'main');
457
+ break;
458
+ case 'PIVOT':
459
+ this.indicatorScheduler.updatePivotConfig({ ...params, showPP: isActive, showR1: isActive, showR2: isActive, showR3: isActive, showS1: isActive, showS2: isActive, showS3: isActive }, 'main');
460
+ break;
461
+ case 'FIB':
462
+ this.indicatorScheduler.updateFibConfig({ ...params, showLevels: isActive }, 'main');
463
+ break;
464
+ case 'STRUCTURE':
465
+ this.indicatorScheduler.updateStructureConfig({ ...params, showSwingLabels: isActive, showBOS: isActive, showCHOCH: isActive }, 'main');
466
+ break;
467
+ case 'ZONES':
468
+ this.indicatorScheduler.updateZonesConfig({ ...params, showFVG: isActive, showOB: isActive, showFilledZones: isActive }, 'main');
469
+ break;
470
+ }
471
+ }
472
+ /**
473
+ * @deprecated 使用 enableMainIndicator/disableMainIndicator 替代
474
+ */
475
+ setActiveMainIndicators(indicators) {
476
+ // 计算需要启用和禁用的指标
477
+ const newSet = new Set(indicators.map(i => i.toUpperCase()));
478
+ const currentSet = new Set(this.activeMainIndicators);
479
+ // 禁用不再激活的
480
+ for (const id of currentSet) {
481
+ if (!newSet.has(id)) {
482
+ this.disableMainIndicator(id);
483
+ }
484
+ }
485
+ // 启用新激活的
486
+ for (const id of newSet) {
487
+ if (!currentSet.has(id)) {
488
+ this.enableMainIndicator(id);
489
+ }
490
+ }
491
+ }
492
+ /**
493
+ * 创建图表实例
494
+ * @param dom 由 Vue 组件传入的 DOM 句柄
495
+ * @param opt 初始配置
496
+ */
497
+ constructor(dom, opt) {
498
+ this.dom = dom;
499
+ const { kWidth: _kWidth, kGap: _kGap, ...restOpt } = opt;
500
+ // Chart 不持有业务 SSOT,kWidth/kGap/zoomLevel 由外部通过 applyRenderState() 传入
501
+ this.opt = { ...restOpt, kWidth: _kWidth ?? 0, kGap: _kGap ?? 0 };
502
+ this.interaction = new InteractionController(this);
503
+ this.interaction.setOnInteractionChange((snapshot) => {
504
+ this._interactionSignal.set(snapshot);
505
+ });
506
+ this.markerManager = new MarkerManager();
507
+ this.pluginHost = createPluginHost();
508
+ this.rendererPluginManager = new RendererPluginManager();
509
+ this.sharedWebGLSurface = new SharedWebGLSurface();
510
+ // 注入依赖
511
+ this.rendererPluginManager.setPluginHost(this.pluginHost);
512
+ this.rendererPluginManager.setInvalidateCallback(() => this.scheduleDraw());
513
+ this.syncPaneRatiosFromSpecs(this.opt.panes);
514
+ // 缩放级别由外部 SSOT 管理,Chart 只接收不计算
515
+ this.zoomLevelCount = Math.max(2, Math.round(this.opt.zoomLevels ?? 20));
516
+ this.currentZoomLevel = this.opt.initialZoomLevel ?? 1;
517
+ this.currentZoomLevel = Math.max(1, Math.min(this.zoomLevelCount, this.currentZoomLevel));
518
+ // 注意:初始 kWidth/kGap 应由外部通过 applyRenderState() 传入
519
+ // 初始化指标调度器
520
+ this.indicatorScheduler = new IndicatorScheduler();
521
+ this.indicatorScheduler.setPluginHost(this.pluginHost);
522
+ for (const definition of getRegisteredIndicatorDefinitions()) {
523
+ this.indicatorScheduler.registerIndicator(definition);
524
+ }
525
+ this.indicatorScheduler.setInvalidateCallback(() => this.scheduleDraw());
526
+ // 初始化副图管理器
527
+ this.subPaneManager = new SubPaneManager();
528
+ // 注册副图活跃列表提供者,调度器据此只计算启用的副图
529
+ this.indicatorScheduler.setActiveSubPaneProvider(() => this.subPaneManager.getPaneIds());
530
+ this.initPanes();
531
+ // 注册绘图主插件(负责绘制 shape,layer: 'main')
532
+ this.useRenderer(createDrawingRendererPlugin({ store: this.drawingStore }));
533
+ // 注册绘图标签插件(负责推送选中绘图的轴标签,layer: 'overlay')
534
+ // 注意:此插件依赖 overlay 更新级别,若将来添加 Main 级别需调整
535
+ this.useRenderer(createDrawingLabelOverlayPlugin({ store: this.drawingStore }));
536
+ this.initCoreRenderers();
537
+ this.initResizeObserver();
538
+ }
539
+ initCoreRenderers() {
540
+ const axisWidth = this.opt.rightAxisWidth + (this.opt.priceLabelWidth ?? 0);
541
+ this.useRenderer(createGridLinesRendererPlugin());
542
+ this.useRenderer(createCandleRenderer());
543
+ this.useRenderer(createLastPriceLineRendererPlugin());
544
+ this.useRenderer(createLastPriceLabelRegistrarPlugin());
545
+ this.useRenderer(createCustomMarkersRenderer());
546
+ this.useRenderer(createMainIndicatorLegendRendererPlugin({
547
+ yPaddingPx: this.opt.yPaddingPx,
548
+ }));
549
+ this.useRenderer(createYAxisRendererPlugin({
550
+ axisWidth,
551
+ yPaddingPx: this.opt.yPaddingPx,
552
+ getCrosshair: () => {
553
+ const pos = this.interaction.crosshairPos;
554
+ const price = this.interaction.crosshairPrice;
555
+ const activePaneId = this.interaction.activePaneId;
556
+ if (pos && price !== null) {
557
+ return { y: pos.y, price, activePaneId };
558
+ }
559
+ return null;
560
+ },
561
+ }));
562
+ this.useRenderer(createCrosshairRendererPlugin({
563
+ getCrosshairState: () => ({
564
+ pos: this.interaction.crosshairPos,
565
+ activePaneId: this.interaction.activePaneId,
566
+ isDragging: this.interaction.isDraggingState(),
567
+ price: this.interaction.crosshairPrice,
568
+ }),
569
+ }));
570
+ this.useRenderer(createTimeAxisRendererPlugin({
571
+ height: this.opt.bottomAxisHeight,
572
+ getCrosshair: () => {
573
+ const pos = this.interaction.crosshairPos;
574
+ const idx = this.interaction.crosshairIndex;
575
+ if (pos && idx !== null) {
576
+ return { x: pos.x, index: idx };
577
+ }
578
+ return null;
579
+ },
580
+ }));
581
+ }
582
+ initResizeObserver() {
583
+ if (typeof ResizeObserver === 'undefined')
584
+ return;
585
+ const target = this.dom.container;
586
+ if (!target)
587
+ return;
588
+ // 初始化 scrollLeft 缓存
589
+ this.cachedScrollLeft = target.scrollLeft;
590
+ this.onScroll = () => { this.cachedScrollLeft = target.scrollLeft; };
591
+ target.addEventListener('scroll', this.onScroll, { passive: true });
592
+ this.resizeObserver = new ResizeObserver((entries) => {
593
+ const entry = entries[0];
594
+ if (!entry)
595
+ return;
596
+ const prevWidth = this.observedSize.width;
597
+ const prevHeight = this.observedSize.height;
598
+ const prevDpr = this.preciseDpr;
599
+ this.updateObservedMetrics(entry);
600
+ const widthChanged = this.observedSize.width !== prevWidth;
601
+ const heightChanged = this.observedSize.height !== prevHeight;
602
+ const dprChanged = this.preciseDpr !== prevDpr;
603
+ if (import.meta.env?.MODE !== 'production') {
604
+ console.log(`[Chart] resize observer: ` +
605
+ `size ${prevWidth}x${prevHeight} -> ${this.observedSize.width}x${this.observedSize.height} ` +
606
+ `dpr ${prevDpr} -> ${this.preciseDpr} ` +
607
+ `changed: ${widthChanged || heightChanged ? 'size' : ''}${widthChanged || heightChanged && dprChanged ? '+' : ''}${dprChanged ? 'dpr' : ''}`);
608
+ }
609
+ if (widthChanged || heightChanged || dprChanged) {
610
+ this.resize();
611
+ }
612
+ });
613
+ try {
614
+ this.resizeObserver.observe(target, { box: 'device-pixel-content-box' });
615
+ }
616
+ catch {
617
+ this.resizeObserver.observe(target);
618
+ }
619
+ }
620
+ updateObservedMetrics(entry) {
621
+ const cssWidth = Math.max(1, Math.round(entry.contentRect.width));
622
+ const cssHeight = Math.max(1, Math.round(entry.contentRect.height));
623
+ this.observedSize.width = cssWidth;
624
+ this.observedSize.height = cssHeight;
625
+ const pixelSize = entry.devicePixelContentBoxSize?.[0];
626
+ const cssSize = entry.contentBoxSize?.[0];
627
+ if (!pixelSize || !cssSize || cssSize.inlineSize <= 0) {
628
+ this.preciseDpr = 0;
629
+ return;
630
+ }
631
+ const raw = pixelSize.inlineSize / cssSize.inlineSize;
632
+ this.preciseDpr = Math.round(raw * 64) / 64;
633
+ }
634
+ getEffectiveDpr() {
635
+ let dpr = this.preciseDpr > 0
636
+ ? this.preciseDpr
637
+ : Math.round((window.devicePixelRatio || 1) * 64) / 64;
638
+ if (dpr < 1)
639
+ dpr = 1;
640
+ return dpr;
641
+ }
642
+ getViewport() {
643
+ return this._internalViewport;
644
+ }
645
+ getCurrentDpr() {
646
+ return this.getEffectiveDpr();
647
+ }
648
+ /** 获取缓存的 scrollLeft(避免读取 DOM 触发强制回流) */
649
+ getCachedScrollLeft() {
650
+ return this.cachedScrollLeft;
651
+ }
652
+ /** 获取插件宿主 */
653
+ get plugin() {
654
+ return this.pluginHost;
655
+ }
656
+ // ========== 渲染器插件 API ==========
657
+ /** 安装渲染器插件 */
658
+ useRenderer(plugin, config) {
659
+ this.rendererPluginManager.register(plugin);
660
+ if (config && plugin.setConfig) {
661
+ plugin.setConfig(config);
662
+ }
663
+ }
664
+ /** 移除渲染器插件 */
665
+ removeRenderer(name) {
666
+ this.rendererPluginManager.unregister(name);
667
+ }
668
+ /** 获取渲染器插件 */
669
+ getRenderer(name) {
670
+ return this.rendererPluginManager.getPlugin(name);
671
+ }
672
+ /** 更新渲染器配置(自动重绘) */
673
+ updateRendererConfig(name, config) {
674
+ this.rendererPluginManager.updateConfig(name, config);
675
+ }
676
+ /** 启用/禁用渲染器 */
677
+ setRendererEnabled(name, enabled) {
678
+ this.rendererPluginManager.setEnabled(name, enabled);
679
+ }
680
+ /** 获取所有渲染器 */
681
+ getAllRenderers() {
682
+ return this.rendererPluginManager.getAllPlugins();
683
+ }
684
+ /** 更新用户设置(触发重绘) */
685
+ updateSettings(settings) {
686
+ this.settings = { ...settings };
687
+ this.interaction.updateSettings(settings);
688
+ // 同步对数刻度设置到所有 pane
689
+ const scaleType = settings.logarithmicScale ? 'log' : 'linear';
690
+ for (const renderer of this.paneRenderers) {
691
+ renderer.getPane().yAxis.setScaleType(scaleType);
692
+ }
693
+ this.scheduleDraw();
694
+ }
695
+ /**
696
+ * 绘制一帧
697
+ * @param level 更新级别,决定渲染哪些层
698
+ */
699
+ draw(level = UpdateLevel.All) {
700
+ // 1. 重置 Marker 标记
701
+ this.markerManager.clear();
702
+ // 2. 准备帧数据(视口 / 可见范围 / K 线坐标,优先走缓存)
703
+ const frame = this.prepareFrameData(level);
704
+ if (!frame)
705
+ return;
706
+ const { vp, range, kLinePositions, kLineCenters, kBarRects, kWidthPx, useCachedFrame } = frame;
707
+ // 3. 更新交互控制器坐标映射
708
+ this.interaction.setKLinePositions(kLinePositions, range, kWidthPx);
709
+ // 4. 通知调度器当前活跃主图指标 + 获取价格范围
710
+ this.indicatorScheduler.setActiveMainIndicators(Array.from(this.activeMainIndicators));
711
+ const mainIndicatorRange = useCachedFrame ? null : this.indicatorScheduler.getMainIndicatorPriceRange();
712
+ const hasCrosshair = this.interaction.getCrosshairIndex() !== null;
713
+ // 5. 遍历所有 Pane 渲染主层 / overlay / Y 轴
714
+ const { sharedXAxisLabels, sharedXAxisRanges } = this.renderPanes(vp, range, kLinePositions, kLineCenters, kBarRects, kWidthPx, mainIndicatorRange, hasCrosshair, useCachedFrame, level);
715
+ // 6. 持久化十字线状态供下帧判断清除
716
+ this.overlayHadCrosshair = hasCrosshair;
717
+ // 7. 渲染 X 轴时间轴
718
+ this.renderXAxis(vp, range, kLinePositions, kLineCenters, kBarRects, kWidthPx, sharedXAxisLabels, sharedXAxisRanges);
719
+ }
720
+ prepareFrameData(level) {
721
+ const useCachedFrame = level === UpdateLevel.Overlay && this.cachedDrawFrame !== null;
722
+ const vp = useCachedFrame ? this.cachedDrawFrame.viewport : this.computeViewport();
723
+ if (!vp)
724
+ return null;
725
+ if (this._internalData.length === 0)
726
+ return null;
727
+ const range = useCachedFrame
728
+ ? this.cachedDrawFrame.range
729
+ : (() => {
730
+ const { start, end } = getVisibleRange(vp.scrollLeft, vp.plotWidth, this.opt.kWidth, this.opt.kGap, this._internalData.length, vp.dpr);
731
+ return { start, end };
732
+ })();
733
+ if (!useCachedFrame && (range.start !== this.lastVisibleRange.start || range.end !== this.lastVisibleRange.end)) {
734
+ this.indicatorScheduler.updateVisibleRange(range);
735
+ this.lastVisibleRange = range;
736
+ }
737
+ const kLinePositions = useCachedFrame
738
+ ? this.cachedDrawFrame.kLinePositions
739
+ : this.calcKLinePositions(range);
740
+ let kLineCenters;
741
+ let kBarRects;
742
+ let kWidthPx;
743
+ if (useCachedFrame) {
744
+ kLineCenters = this.cachedDrawFrame.kLineCenters;
745
+ kBarRects = this.cachedDrawFrame.kBarRects;
746
+ kWidthPx = this.cachedDrawFrame.kWidthPx;
747
+ }
748
+ else {
749
+ const physConfig = getPhysicalKLineConfig(this.opt.kWidth, this.opt.kGap, vp.dpr);
750
+ let barWidthPx = Math.max(1, physConfig.unitPx - 1);
751
+ if (barWidthPx % 2 === 0)
752
+ barWidthPx -= 1;
753
+ kLineCenters = new Array(kLinePositions.length);
754
+ kBarRects = new Array(kLinePositions.length);
755
+ for (let i = 0; i < kLinePositions.length; i++) {
756
+ const x = kLinePositions[i];
757
+ const leftPx = Math.round(x * vp.dpr);
758
+ const wickXPx = leftPx + (physConfig.kWidthPx - 1) / 2;
759
+ kLineCenters[i] = wickXPx / vp.dpr;
760
+ const barLeftPx = wickXPx - (barWidthPx - 1) / 2;
761
+ kBarRects[i] = { x: barLeftPx / vp.dpr, width: barWidthPx / vp.dpr };
762
+ }
763
+ kWidthPx = getPhysicalKLineConfig(this.opt.kWidth, this.opt.kGap, vp.dpr).kWidthPx;
764
+ this.cachedDrawFrame = {
765
+ viewport: { ...vp },
766
+ range: { ...range },
767
+ kLinePositions,
768
+ kLineCenters,
769
+ kBarRects,
770
+ kWidthPx,
771
+ };
772
+ }
773
+ return { vp, range, kLinePositions, kLineCenters, kBarRects, kWidthPx, useCachedFrame };
774
+ }
775
+ renderPanes(vp, range, kLinePositions, kLineCenters, kBarRects, kWidthPx, mainIndicatorRange, hasCrosshair, useCachedFrame, level) {
776
+ const sharedYAxisLabels = [];
777
+ const sharedXAxisLabels = [];
778
+ const sharedYAxisRanges = [];
779
+ const sharedXAxisRanges = [];
780
+ for (const renderer of this.paneRenderers) {
781
+ const pane = renderer.getPane();
782
+ const { mainCtx, overlayCtx, yAxisCtx } = renderer.getContexts();
783
+ const { candleSurface, lineSurface } = renderer.getWebGL();
784
+ if (!useCachedFrame) {
785
+ const indicatorRange = pane.role === 'price' ? mainIndicatorRange : null;
786
+ pane.updateRange(this._internalData, range, indicatorRange);
787
+ }
788
+ const shouldUpdateMain = level === UpdateLevel.Main || level === UpdateLevel.All;
789
+ const shouldUpdateOverlay = level === UpdateLevel.All || (level === UpdateLevel.Overlay && (hasCrosshair || this.overlayHadCrosshair));
790
+ if (shouldUpdateMain && mainCtx) {
791
+ mainCtx.setTransform(1, 0, 0, 1, 0, 0);
792
+ mainCtx.scale(vp.dpr, vp.dpr);
793
+ mainCtx.clearRect(0, 0, vp.plotWidth + 1, pane.height + 2 / vp.dpr);
794
+ candleSurface?.clear();
795
+ lineSurface?.clear();
796
+ }
797
+ if (shouldUpdateOverlay && overlayCtx) {
798
+ const overlayWidth = overlayCtx.canvas.width / vp.dpr;
799
+ overlayCtx.setTransform(1, 0, 0, 1, 0, 0);
800
+ overlayCtx.scale(vp.dpr, vp.dpr);
801
+ overlayCtx.clearRect(0, 0, overlayWidth + 1, pane.height + 2 / vp.dpr);
802
+ }
803
+ if (yAxisCtx && !useCachedFrame) {
804
+ const yAxisWidth = yAxisCtx.canvas.width / vp.dpr;
805
+ yAxisCtx.setTransform(1, 0, 0, 1, 0, 0);
806
+ yAxisCtx.scale(vp.dpr, vp.dpr);
807
+ yAxisCtx.clearRect(0, 0, yAxisWidth, pane.height + 2 / vp.dpr);
808
+ }
809
+ const context = {
810
+ ctx: mainCtx,
811
+ overlayCtx: overlayCtx ?? undefined,
812
+ pane: wrapPaneInfo(pane),
813
+ data: this._internalData,
814
+ range,
815
+ scrollLeft: vp.scrollLeft,
816
+ kWidth: this.opt.kWidth,
817
+ kGap: this.opt.kGap,
818
+ dpr: vp.dpr,
819
+ paneWidth: vp.plotWidth,
820
+ kLinePositions,
821
+ kLineCenters,
822
+ kBarRects,
823
+ markerManager: this.markerManager,
824
+ crosshairIndex: this.interaction.getCrosshairIndex(),
825
+ yAxisCtx: yAxisCtx ?? undefined,
826
+ candleWebGLSurface: candleSurface ?? undefined,
827
+ lineWebGLSurface: lineSurface ?? undefined,
828
+ zoomLevel: this.currentZoomLevel,
829
+ zoomLevelCount: this.zoomLevelCount,
830
+ viewport: {
831
+ scrollLeft: vp.scrollLeft,
832
+ plotWidth: vp.plotWidth,
833
+ plotHeight: vp.plotHeight,
834
+ },
835
+ settings: this.settings,
836
+ yAxisLabels: sharedYAxisLabels,
837
+ xAxisLabels: sharedXAxisLabels,
838
+ yAxisRanges: sharedYAxisRanges,
839
+ xAxisRanges: sharedXAxisRanges,
840
+ theme: this._themeSignal.peek(),
841
+ };
842
+ if (shouldUpdateMain || shouldUpdateOverlay) {
843
+ const errors = this.rendererPluginManager.render(pane.id, context, level);
844
+ if (errors.length > 0) {
845
+ this.pluginHost.events.emit('renderer:error', { paneId: pane.id, errors });
846
+ }
847
+ const yAxisErrors = this.rendererPluginManager.renderPlugin('yAxis', context);
848
+ if (yAxisErrors.length > 0) {
849
+ this.pluginHost.events.emit('renderer:error', { paneId: pane.id, errors: yAxisErrors });
850
+ }
851
+ }
852
+ }
853
+ return { sharedXAxisLabels, sharedXAxisRanges };
854
+ }
855
+ renderXAxis(vp, range, kLinePositions, kLineCenters, kBarRects, kWidthPx, sharedXAxisLabels, sharedXAxisRanges) {
856
+ const xAxisCtx = this.xAxisCtx ?? this.dom.xAxisCanvas.getContext('2d');
857
+ if (!this.xAxisCtx) {
858
+ this.xAxisCtx = xAxisCtx;
859
+ }
860
+ if (xAxisCtx) {
861
+ const timeAxisContext = {
862
+ ctx: xAxisCtx,
863
+ pane: {
864
+ id: 'xAxis',
865
+ role: 'auxiliary',
866
+ capabilities: {
867
+ showPriceAxisTicks: false,
868
+ showCrosshairPriceLabel: false,
869
+ candleHitTest: false,
870
+ supportsPriceTranslate: false,
871
+ },
872
+ top: 0,
873
+ height: this.opt.bottomAxisHeight,
874
+ yAxis: {
875
+ priceToY: () => 0,
876
+ yToPrice: () => 0,
877
+ getPaddingTop: () => 0,
878
+ getPaddingBottom: () => 0,
879
+ getPriceOffset: () => 0,
880
+ getDisplayRange: (baseRange) => baseRange ?? { maxPrice: 0, minPrice: 0 },
881
+ getScaleType: () => 'linear',
882
+ },
883
+ priceRange: { maxPrice: 0, minPrice: 0 },
884
+ },
885
+ data: this._internalData,
886
+ range,
887
+ scrollLeft: vp.scrollLeft,
888
+ kWidth: this.opt.kWidth,
889
+ kGap: this.opt.kGap,
890
+ dpr: vp.dpr,
891
+ paneWidth: vp.plotWidth,
892
+ kLinePositions,
893
+ kLineCenters,
894
+ kBarRects,
895
+ xAxisCtx,
896
+ viewport: {
897
+ scrollLeft: vp.scrollLeft,
898
+ plotWidth: vp.plotWidth,
899
+ plotHeight: vp.plotHeight,
900
+ },
901
+ yAxisLabels: [],
902
+ xAxisLabels: sharedXAxisLabels,
903
+ xAxisRanges: sharedXAxisRanges,
904
+ theme: this._themeSignal.peek(),
905
+ };
906
+ const errors = this.rendererPluginManager.renderPlugin('timeAxis', timeAxisContext);
907
+ if (errors.length > 0) {
908
+ this.pluginHost.events.emit('renderer:error', { paneId: 'timeAxis', errors });
909
+ }
910
+ }
911
+ }
912
+ // ========== Render State API (Vue SSOT) ==========
913
+ /**
914
+ * 应用渲染状态(由 Vue/Store 层在状态更新后调用)
915
+ * Chart 不拥有业务 SSOT,只负责接收参数并渲染
916
+ * 这是写入 opt.kWidth/kGap 和 currentZoomLevel 的唯一入口
917
+ */
918
+ applyRenderState(kWidth, kGap, zoomLevel) {
919
+ const nextZoomLevel = zoomLevel !== undefined
920
+ ? Math.max(1, Math.min(this.zoomLevelCount, zoomLevel))
921
+ : this.currentZoomLevel;
922
+ const renderStateChanged = this.opt.kWidth !== kWidth
923
+ || this.opt.kGap !== kGap
924
+ || this.currentZoomLevel !== nextZoomLevel;
925
+ if (!renderStateChanged) {
926
+ return;
927
+ }
928
+ this.opt = { ...this.opt, kWidth, kGap };
929
+ if (zoomLevel !== undefined) {
930
+ this.currentZoomLevel = nextZoomLevel;
931
+ }
932
+ this.updateViewportSignal();
933
+ this.scheduleDraw();
934
+ }
935
+ /** 获取总缩放级别数 */
936
+ getZoomLevelCount() {
937
+ return this.zoomLevelCount;
938
+ }
939
+ /** 注册视口变化回调 */
940
+ setOnViewportChange(cb) {
941
+ this.onViewportChange = cb;
942
+ }
943
+ /** 注册 pane 布局回流回调 */
944
+ setOnPaneLayoutChange(cb) {
945
+ this.onPaneLayoutChange = cb;
946
+ }
947
+ /** 注册数据变化回调 */
948
+ setOnDataChange(cb) {
949
+ this.onDataChange = cb;
950
+ }
951
+ /** 获取所有 PaneRenderer */
952
+ getPaneRenderers() {
953
+ return this.paneRenderers;
954
+ }
955
+ /** 获取 MarkerManager(供 InteractionController 使用) */
956
+ getMarkerManager() {
957
+ return this.markerManager;
958
+ }
959
+ /** 更新自定义标记 */
960
+ updateCustomMarkers(markers) {
961
+ this.markerManager.setCustomMarkers(markers);
962
+ this.scheduleDraw();
963
+ }
964
+ /** 清除自定义标记 */
965
+ clearCustomMarkers() {
966
+ this.markerManager.clearCustomMarkers();
967
+ this.scheduleDraw();
968
+ }
969
+ /** 获取 ChartDom(供 InteractionController 使用) */
970
+ getDom() {
971
+ return this.dom;
972
+ }
973
+ /** 获取当前 ChartOptions(返回内部当前快照) */
974
+ getOption() {
975
+ return this.opt;
976
+ }
977
+ /**
978
+ * 计算 K 线起始 x 坐标数组,与 candle.ts 的像素对齐方式保持一致
979
+ * @param range 可见 K 线索引范围
980
+ * @returns x 坐标数组(逻辑像素,经过物理像素对齐)
981
+ */
982
+ calcKLinePositions(range) {
983
+ const { start, end } = range;
984
+ const count = end - start;
985
+ // 边界检查:防止负数或零长度数组
986
+ if (count <= 0) {
987
+ return [];
988
+ }
989
+ const dpr = this.getEffectiveDpr();
990
+ // 统一使用 getPhysicalKLineConfig,确保与渲染完全一致
991
+ const { unitPx, startXPx } = getPhysicalKLineConfig(this.opt.kWidth, this.opt.kGap, dpr);
992
+ const positions = new Array(count);
993
+ for (let i = 0; i < count; i++) {
994
+ const dataIndex = start + i;
995
+ const leftPx = startXPx + dataIndex * unitPx;
996
+ positions[i] = leftPx / dpr;
997
+ }
998
+ return positions;
999
+ }
1000
+ /**
1001
+ * 更新配置并触发布局/重绘
1002
+ * @param partial 部分配置项
1003
+ */
1004
+ updateOptions(partial) {
1005
+ // 缩放参数由 zoomLevel 派生,不允许直接修改
1006
+ if (partial.kWidth !== undefined) {
1007
+ console.warn('[Chart] kWidth cannot be set directly. Use applyRenderState() instead.');
1008
+ delete partial.kWidth;
1009
+ }
1010
+ if (partial.kGap !== undefined) {
1011
+ delete partial.kGap;
1012
+ }
1013
+ if (partial.panes) {
1014
+ const nextPanes = partial.panes.map((pane) => ({ ...pane }));
1015
+ this.opt = { ...this.opt, ...partial, panes: nextPanes };
1016
+ this.applyPaneLayoutSpecs(nextPanes);
1017
+ return;
1018
+ }
1019
+ this.opt = { ...this.opt, ...partial };
1020
+ this.resize();
1021
+ }
1022
+ /** 更新 pane 布局配置
1023
+ * @param panes 新的 pane 配置数组
1024
+ *
1025
+ * 显式整盘替换:清空之前 user-resize 留下的 paneRatios 缓存,让 spec 中的 ratio
1026
+ * 真正生效。`addPane`/`upsertPane`/`removePaneDefinition` 走 `applyPaneLayoutSpecs`
1027
+ * 时仍保留 prev 值以记住用户拖拽过的高度——只有显式的 layout replacement 才重置。
1028
+ */
1029
+ updatePaneLayout(panes) {
1030
+ this._internalPaneRatios.clear();
1031
+ this.applyPaneLayoutSpecs(panes);
1032
+ }
1033
+ setPaneDefinitions(defs) {
1034
+ this.applyPaneLayoutSpecs(defs);
1035
+ }
1036
+ upsertPane(def) {
1037
+ const idx = this.opt.panes.findIndex((pane) => pane.id === def.id);
1038
+ if (idx === -1) {
1039
+ this.applyPaneLayoutSpecs([...this.opt.panes, { ...def }]);
1040
+ return;
1041
+ }
1042
+ const next = [...this.opt.panes];
1043
+ next[idx] = { ...next[idx], ...def };
1044
+ this.applyPaneLayoutSpecs(next);
1045
+ }
1046
+ removePaneDefinition(paneId) {
1047
+ if (!this.opt.panes.some((pane) => pane.id === paneId))
1048
+ return;
1049
+ this._internalPaneRatios.delete(paneId);
1050
+ this.applyPaneLayoutSpecs(this.opt.panes.filter((pane) => pane.id !== paneId));
1051
+ }
1052
+ bindIndicatorToPane(paneId, indicatorId, params) {
1053
+ const paneExists = this.opt.panes.some((pane) => pane.id === paneId);
1054
+ if (!paneExists) {
1055
+ this.upsertPane({ id: paneId, ratio: 1, visible: true, role: 'indicator' });
1056
+ }
1057
+ const rendererName = `${indicatorId.toLowerCase()}_${paneId}`;
1058
+ const existing = this.getRenderer(rendererName);
1059
+ if (existing) {
1060
+ if (params)
1061
+ this.updateRendererConfig(rendererName, params);
1062
+ return;
1063
+ }
1064
+ const renderer = createSubIndicatorRenderer({ indicatorId, paneId });
1065
+ this.useRenderer(renderer, params);
1066
+ }
1067
+ /** 更新绘图对象 */
1068
+ setDrawings(drawings) {
1069
+ this.drawingStore.setAll(drawings);
1070
+ this._drawingsSignal.set(drawings);
1071
+ this.scheduleDraw();
1072
+ }
1073
+ /** 更新选中的绘图 ID */
1074
+ setSelectedDrawingId(id) {
1075
+ if (this.drawingStore.getSelectedId() === id)
1076
+ return;
1077
+ this.drawingStore.setSelectedId(id);
1078
+ this.scheduleDraw();
1079
+ }
1080
+ /** 获取当前 pane 布局快照(含 ratio) */
1081
+ getPaneLayoutSpecs() {
1082
+ const visible = this.opt.panes.filter(p => p.visible !== false);
1083
+ const sum = visible.reduce((s, p) => s + (this._internalPaneRatios.get(p.id) ?? p.ratio ?? 0), 0);
1084
+ const safeSum = sum > 0 ? sum : 1;
1085
+ return this.opt.panes.map((spec) => {
1086
+ const base = this._internalPaneRatios.get(spec.id) ?? spec.ratio ?? 0;
1087
+ const ratio = spec.visible === false ? base : base / safeSum;
1088
+ const pane = this.paneRenderers.find((r) => r.getPane().id === spec.id)?.getPane();
1089
+ return {
1090
+ ...spec,
1091
+ ratio,
1092
+ role: pane?.role ?? spec.role,
1093
+ capabilities: pane ? { ...pane.capabilities } : spec.capabilities,
1094
+ };
1095
+ });
1096
+ }
1097
+ emitPaneLayoutChange() {
1098
+ // 同步 pane ratios 到 signal
1099
+ const ratios = {};
1100
+ this._internalPaneRatios.forEach((ratio, id) => {
1101
+ ratios[id] = ratio;
1102
+ });
1103
+ this._paneRatiosSignal.set(ratios);
1104
+ this.syncSubPanesSignal();
1105
+ this.onPaneLayoutChange?.(this.getPaneLayoutSpecs());
1106
+ }
1107
+ applyPaneLayoutSpecs(panes) {
1108
+ this.opt.panes = panes.map((spec) => ({ ...spec }));
1109
+ this.syncPaneRatiosFromSpecs(this.opt.panes);
1110
+ this.initPanes();
1111
+ this.layoutPanes();
1112
+ this.emitPaneLayoutChange();
1113
+ this.scheduleDraw();
1114
+ }
1115
+ /**
1116
+ * 调整相邻 pane 边界(支持连锁挤压)
1117
+ * @param upperPaneId 上方 pane ID(边界位于此 pane 与其下方邻居之间)
1118
+ * @param deltaY Y 方向位移(逻辑像素,正数表示边界向下,upper 增大;负数表示向上,upper 减小)
1119
+ */
1120
+ resizePaneBoundary(upperPaneId, deltaY) {
1121
+ // === 1. 参数校验 ===
1122
+ if (!Number.isFinite(deltaY) || deltaY === 0)
1123
+ return false;
1124
+ const vp = this._internalViewport;
1125
+ if (!vp)
1126
+ return false;
1127
+ // === 2. 定位相邻 pane 对(边界两侧) ===
1128
+ const visibleSpecs = this.opt.panes.filter(p => p.visible !== false);
1129
+ const boundaryIndex = visibleSpecs.findIndex(p => p.id === upperPaneId);
1130
+ if (boundaryIndex < 0 || boundaryIndex >= visibleSpecs.length - 1)
1131
+ return false;
1132
+ const upperSpec = visibleSpecs[boundaryIndex];
1133
+ const lowerSpec = visibleSpecs[boundaryIndex + 1];
1134
+ if (!upperSpec || !lowerSpec)
1135
+ return false;
1136
+ // === 3. 收集所有 pane 当前高度 ===
1137
+ const heights = new Map();
1138
+ for (const spec of visibleSpecs) {
1139
+ const renderer = this.paneRenderers.find(r => r.getPane().id === spec.id);
1140
+ if (renderer) {
1141
+ heights.set(spec.id, renderer.getPane().height);
1142
+ }
1143
+ }
1144
+ // === 4. 连锁挤压/扩展 ===
1145
+ // deltaY > 0: 边界下移,upper expand,lower shrink
1146
+ // deltaY < 0: 边界上移,upper shrink,lower expand
1147
+ const expandIdx = deltaY > 0 ? boundaryIndex : boundaryIndex + 1;
1148
+ const shrinkIdx = deltaY > 0 ? boundaryIndex + 1 : boundaryIndex;
1149
+ const expandDir = deltaY > 0 ? -1 : 1; // expand 方向(向边界方向找)
1150
+ const shrinkDir = deltaY > 0 ? 1 : -1; // shrink 方向(远离边界方向找)
1151
+ let remaining = Math.abs(deltaY);
1152
+ // 先尝试 shrink(从 shrinkIdx 开始,沿 shrinkDir 方向连锁)
1153
+ let shrinkCursor = shrinkIdx;
1154
+ while (remaining > 0 && shrinkCursor >= 0 && shrinkCursor < visibleSpecs.length) {
1155
+ const spec = visibleSpecs[shrinkCursor];
1156
+ if (!spec)
1157
+ break;
1158
+ const currentH = heights.get(spec.id) ?? 0;
1159
+ const minH = this.getPaneMinHeight(spec, vp.plotHeight);
1160
+ const canShrink = Math.max(0, currentH - minH);
1161
+ if (canShrink > 0) {
1162
+ const shrink = Math.min(canShrink, remaining);
1163
+ heights.set(spec.id, currentH - shrink);
1164
+ remaining -= shrink;
1165
+ }
1166
+ // 继续向 shrinkDir 方向找下一个可 shrink 的 pane
1167
+ if (remaining > 0) {
1168
+ shrinkCursor += shrinkDir;
1169
+ }
1170
+ }
1171
+ // 如果还有剩余(无法完全 shrink),说明拖拽无效
1172
+ if (remaining > 0)
1173
+ return false;
1174
+ // 将节省的高度全部加到 expand 方
1175
+ const expandSpec = visibleSpecs[expandIdx];
1176
+ if (!expandSpec)
1177
+ return false;
1178
+ const expandCurrentH = heights.get(expandSpec.id) ?? 0;
1179
+ heights.set(expandSpec.id, expandCurrentH + Math.abs(deltaY));
1180
+ // === 5. 将像素高度转换为 ratio ===
1181
+ const gap = Math.max(0, this.opt.paneGap ?? 0);
1182
+ const totalGaps = gap * Math.max(0, visibleSpecs.length - 1);
1183
+ const availableH = Math.max(1, vp.plotHeight - totalGaps);
1184
+ for (const spec of visibleSpecs) {
1185
+ const h = heights.get(spec.id) ?? 0;
1186
+ this._internalPaneRatios.set(spec.id, h / availableH);
1187
+ }
1188
+ // === 6. 归一化并同步 ===
1189
+ this.normalizeVisiblePaneRatios(visibleSpecs);
1190
+ this.syncPaneRatiosToSpecs();
1191
+ // === 7. 应用布局 ===
1192
+ this.layoutPanes();
1193
+ this.emitPaneLayoutChange();
1194
+ this.scheduleDraw();
1195
+ return true;
1196
+ }
1197
+ resolvePaneRole(spec, index) {
1198
+ if (spec.role)
1199
+ return spec.role;
1200
+ return index === 0 ? 'price' : 'indicator';
1201
+ }
1202
+ addPane(paneId) {
1203
+ if (this.opt.panes.some((spec) => spec.id === paneId)) {
1204
+ console.warn(`Pane "${paneId}" already exists`);
1205
+ return;
1206
+ }
1207
+ const hasPricePane = this.opt.panes.some((spec, index) => this.resolvePaneRole(spec, index) === 'price');
1208
+ const role = hasPricePane ? 'indicator' : 'price';
1209
+ this.applyPaneLayoutSpecs([
1210
+ ...this.opt.panes,
1211
+ { id: paneId, ratio: 1, visible: true, role },
1212
+ ]);
1213
+ }
1214
+ /**
1215
+ * 动态移除 pane
1216
+ * @param paneId pane 标识符
1217
+ */
1218
+ removePane(paneId) {
1219
+ if (!this.opt.panes.some((spec) => spec.id === paneId))
1220
+ return;
1221
+ const next = this.opt.panes.filter((spec) => spec.id !== paneId);
1222
+ this._internalPaneRatios.delete(paneId);
1223
+ this.applyPaneLayoutSpecs(next);
1224
+ }
1225
+ /**
1226
+ * 检查 pane 是否存在
1227
+ * @param paneId pane 标识符
1228
+ */
1229
+ hasPane(paneId) {
1230
+ return this.opt.panes.some((spec) => spec.id === paneId);
1231
+ }
1232
+ // ========== 副图管理 API ==========
1233
+ /**
1234
+ * 创建副图面板并注册指标渲染器
1235
+ * @param paneId 副图实例标识符(如 'RSI_0', 'MACD_0')
1236
+ * @param indicatorId 指标类型
1237
+ * @param params 指标参数
1238
+ * @returns 是否创建成功
1239
+ */
1240
+ createSubPane(paneId, indicatorId, params) {
1241
+ // 调整 pane ratios:主图占 3,副图各占 1
1242
+ const visibleSpecs = this.opt.panes.filter((pane) => pane.visible !== false);
1243
+ const pricePanes = visibleSpecs.filter((pane, index) => this.resolvePaneRole(pane, index) === 'price');
1244
+ const indicatorPanes = visibleSpecs.filter((pane, index) => this.resolvePaneRole(pane, index) === 'indicator');
1245
+ if (pricePanes.length === 1) {
1246
+ const pricePane = pricePanes[0];
1247
+ if (pricePane) {
1248
+ this._internalPaneRatios.set(pricePane.id, 3);
1249
+ }
1250
+ for (const pane of indicatorPanes) {
1251
+ this._internalPaneRatios.set(pane.id, 1);
1252
+ }
1253
+ this._internalPaneRatios.set(paneId, 1);
1254
+ }
1255
+ else {
1256
+ this._internalPaneRatios.set(paneId, 1);
1257
+ }
1258
+ this.upsertPane({ id: paneId, ratio: this._internalPaneRatios.get(paneId) ?? 1, visible: true, role: 'indicator' });
1259
+ const success = this.subPaneManager.create(this, paneId, indicatorId, params ?? this.getDefaultSubPaneParams(indicatorId));
1260
+ this.syncIndicatorsSignal();
1261
+ this.syncSubPanesSignal();
1262
+ return success;
1263
+ }
1264
+ /**
1265
+ * 移除副图面板及其渲染器
1266
+ * @param paneId 副图实例标识符
1267
+ */
1268
+ removeSubPane(paneId) {
1269
+ this.subPaneManager.remove(this, paneId);
1270
+ this._internalPaneRatios.delete(paneId);
1271
+ this.syncIndicatorsSignal();
1272
+ this.syncSubPanesSignal();
1273
+ }
1274
+ /**
1275
+ * 替换副图的指标类型
1276
+ * @param paneId 副图实例标识符
1277
+ * @param newIndicatorId 新的指标类型
1278
+ * @param params 新指标参数
1279
+ */
1280
+ replaceSubPaneIndicator(paneId, newIndicatorId, params) {
1281
+ this.subPaneManager.replaceIndicator(this, paneId, newIndicatorId, params ?? this.getDefaultSubPaneParams(newIndicatorId));
1282
+ this.syncIndicatorsSignal();
1283
+ this.syncSubPanesSignal();
1284
+ }
1285
+ /**
1286
+ * 更新副图指标参数
1287
+ * @param paneId 副图实例标识符
1288
+ * @param params 新参数
1289
+ */
1290
+ updateSubPaneParams(paneId, params) {
1291
+ this.subPaneManager.updateParams(this, paneId, params);
1292
+ this.syncIndicatorsSignal();
1293
+ }
1294
+ /**
1295
+ * 清除所有副图面板
1296
+ */
1297
+ clearSubPanes() {
1298
+ // 获取所有副图 paneId
1299
+ const subPaneIds = this.subPaneManager.getPaneIds();
1300
+ if (subPaneIds.length === 0)
1301
+ return;
1302
+ // 移除所有副图
1303
+ this.subPaneManager.clear(this);
1304
+ // 清理 pane ratios
1305
+ for (const paneId of subPaneIds) {
1306
+ this._internalPaneRatios.delete(paneId);
1307
+ }
1308
+ // 更新布局,移除所有副图 pane
1309
+ this.applyPaneLayoutSpecs(this.opt.panes.filter((spec) => !subPaneIds.includes(spec.id)));
1310
+ this.syncIndicatorsSignal();
1311
+ this.syncSubPanesSignal();
1312
+ }
1313
+ /**
1314
+ * 获取当前所有副图指标类型
1315
+ * @deprecated 使用 getSubPaneEntries 获取完整信息
1316
+ */
1317
+ getSubPaneIndicators() {
1318
+ return this.subPaneManager.getAll().map((entry) => entry.indicatorId);
1319
+ }
1320
+ /**
1321
+ * 获取所有副图条目
1322
+ */
1323
+ getSubPaneEntries() {
1324
+ return this.subPaneManager.getAll();
1325
+ }
1326
+ /**
1327
+ * 根据 paneId 获取副图条目
1328
+ * @param paneId 副图实例标识符
1329
+ */
1330
+ getSubPaneEntry(paneId) {
1331
+ return this.subPaneManager.getByPaneId(paneId);
1332
+ }
1333
+ getDefaultSubPaneParams(indicatorId) {
1334
+ // 默认参数定义在 SubPaneManager 中,这里导入使用
1335
+ const defaults = {
1336
+ VOLUME: {},
1337
+ MACD: { fastPeriod: 12, slowPeriod: 26, signalPeriod: 9 },
1338
+ RSI: { period1: 6, period2: 12, period3: 24 },
1339
+ CCI: { period: 14, showCCI: true },
1340
+ STOCH: { n: 9, m: 3, showK: true, showD: true },
1341
+ MOM: { period: 10, showMOM: true },
1342
+ WMSR: { period: 14, showWMSR: true },
1343
+ KST: { roc1: 10, roc2: 15, roc3: 20, roc4: 30, signalPeriod: 9, showKST: true, showSignal: true },
1344
+ FASTK: { period: 9, showFASTK: true },
1345
+ ATR: { period: 14, showATR: true },
1346
+ WMA: { period: 10, showWMA: true },
1347
+ DEMA: { period: 14, showDEMA: true },
1348
+ TEMA: { period: 14, showTEMA: true },
1349
+ HMA: { period: 14, showHMA: true },
1350
+ KAMA: { period: 10, fastPeriod: 2, slowPeriod: 30, showKAMA: true },
1351
+ SAR: { step: 0.02, maxStep: 0.2, showSAR: true },
1352
+ SUPERTREND: { atrPeriod: 10, multiplier: 3, showSuperTrend: true },
1353
+ KELTNER: { emaPeriod: 20, atrPeriod: 10, multiplier: 2, showUpper: true, showMiddle: true, showLower: true },
1354
+ DONCHIAN: { period: 20, showUpper: true, showMiddle: true, showLower: true },
1355
+ ICHIMOKU: { tenkanPeriod: 9, kijunPeriod: 26, spanBPeriod: 52, displacement: 26, showTenkan: true, showKijun: true, showSpanA: true, showSpanB: true, showChikou: true, showCloud: true },
1356
+ ROC: { period: 12, showROC: true },
1357
+ TRIX: { period: 15, signalPeriod: 9, showTRIX: true, showSignal: true },
1358
+ HV: { period: 20, annualizationFactor: 252, showHV: true },
1359
+ PARKINSON: { period: 20, annualizationFactor: 252, showParkinson: true },
1360
+ CHAIKIN_VOL: { emaPeriod: 10, rocPeriod: 10, showChaikinVol: true },
1361
+ VMA: { period: 5, showVMA: true },
1362
+ OBV: { showOBV: true },
1363
+ PVT: { showPVT: true },
1364
+ VWAP: { sessionResetGapMs: 0, showVWAP: true },
1365
+ CMF: { period: 20, showCMF: true },
1366
+ MFI: { period: 14, showMFI: true },
1367
+ PIVOT: { showPP: true, showR1: true, showR2: true, showR3: false, showS1: true, showS2: true, showS3: false },
1368
+ FIB: { period: 50, showLevels: true },
1369
+ STRUCTURE: { leftWindow: 2, rightWindow: 2, breakoutSource: 'close', showSwingLabels: true, showBOS: true, showCHOCH: true, showProvisional: false },
1370
+ ZONES: { showFVG: true, showOB: true, showFilledZones: true, obLookback: 5 },
1371
+ VOLUME_PROFILE: { bins: 24, lookback: 0, valueAreaPercent: 0.7, showVolumeProfile: true },
1372
+ };
1373
+ return { ...defaults[indicatorId] };
1374
+ }
1375
+ /** 副图渲染器名称前缀(保留向后兼容) */
1376
+ static SUB_PANE_PREFIX = 'sub_';
1377
+ /**
1378
+ * 平移价格轴(用于主图区域上下拖动)
1379
+ * @param paneId 目标 pane ID
1380
+ * @param deltaY Y轴像素偏移(正数向下拖动)
1381
+ */
1382
+ translatePrice(paneId, deltaY) {
1383
+ const renderer = this.paneRenderers.find(r => r.getPane().id === paneId);
1384
+ if (!renderer)
1385
+ return;
1386
+ const pane = renderer.getPane();
1387
+ if (!pane.capabilities.supportsPriceTranslate)
1388
+ return;
1389
+ const priceOffset = pane.yAxis.deltaYToPriceOffset(deltaY);
1390
+ const currentOffset = pane.yAxis.getPriceOffset();
1391
+ pane.yAxis.setPriceOffset(currentOffset + priceOffset);
1392
+ this.scheduleDraw();
1393
+ }
1394
+ /**
1395
+ * 重置价格轴垂直偏移
1396
+ * @param paneId 目标 pane ID
1397
+ */
1398
+ resetPriceOffset(paneId) {
1399
+ const renderer = this.paneRenderers.find(r => r.getPane().id === paneId);
1400
+ if (!renderer)
1401
+ return;
1402
+ renderer.getPane().yAxis.resetPriceOffset();
1403
+ this.scheduleDraw();
1404
+ }
1405
+ /**
1406
+ * 缩放价格轴(用于右侧刻度栏上下拖动)
1407
+ * @param paneId 目标 pane ID
1408
+ * @param deltaY Y轴像素偏移(向上拖动放大,向下拖动缩小)
1409
+ */
1410
+ scalePrice(paneId, deltaY) {
1411
+ const renderer = this.paneRenderers.find(r => r.getPane().id === paneId);
1412
+ if (!renderer)
1413
+ return;
1414
+ const pane = renderer.getPane();
1415
+ if (!pane.capabilities.supportsPriceTranslate)
1416
+ return;
1417
+ pane.yAxis.scaleByDelta(deltaY);
1418
+ this.scheduleDraw();
1419
+ }
1420
+ /**
1421
+ * 更新数据并请求重绘
1422
+ * @param data K 线数据数组
1423
+ */
1424
+ updateData(data) {
1425
+ this._internalData = data ?? [];
1426
+ this._dataSignal.set([...this._internalData]);
1427
+ this.onDataChange?.(this._internalData);
1428
+ // 重算 DOM scrollLeft 状态, 防止左右滚动超出数据长度范围
1429
+ const container = this.dom.container;
1430
+ if (container) {
1431
+ const contentWidth = this.getContentWidth();
1432
+ const maxScrollLeft = Math.max(0, contentWidth - container.clientWidth);
1433
+ if (this.cachedScrollLeft > maxScrollLeft) {
1434
+ container.scrollLeft = maxScrollLeft;
1435
+ this.cachedScrollLeft = maxScrollLeft;
1436
+ }
1437
+ }
1438
+ // 重置交互状态
1439
+ this.interaction.reset();
1440
+ // 触发指标计算(在 scheduleDraw 之前,确保渲染器读到最新状态)
1441
+ this.indicatorScheduler.update(this._internalData, this.lastVisibleRange);
1442
+ this.scheduleDraw();
1443
+ }
1444
+ /** 获取当前数据源(供 renderers 和 interaction 使用) */
1445
+ getData() {
1446
+ return this._internalData;
1447
+ }
1448
+ /** 获取指标调度器(供外部控制器更新指标配置) */
1449
+ getIndicatorScheduler() {
1450
+ return this.indicatorScheduler;
1451
+ }
1452
+ getTrailingSlotCount() {
1453
+ return 24;
1454
+ }
1455
+ getLogicalSlotCount() {
1456
+ return this._internalData.length + this.getTrailingSlotCount();
1457
+ }
1458
+ getTimestampAtLogicalIndex(index) {
1459
+ if (!Number.isInteger(index) || index < 0 || index >= this._internalData.length)
1460
+ return null;
1461
+ return this._internalData[index]?.timestamp ?? null;
1462
+ }
1463
+ /** 根据视口内 X 坐标反查逻辑索引(允许超出最后一根 K 线) */
1464
+ getLogicalIndexAtX(mouseX) {
1465
+ const vp = this._internalViewport;
1466
+ if (!vp || this._internalData.length === 0)
1467
+ return null;
1468
+ const dpr = this.getEffectiveDpr();
1469
+ const { startXPx, unitPx } = getPhysicalKLineConfig(this.opt.kWidth, this.opt.kGap, dpr);
1470
+ const worldX = Math.round((vp.scrollLeft + mouseX) * dpr);
1471
+ const index = Math.floor((worldX - startXPx) / unitPx);
1472
+ if (index < 0)
1473
+ return null;
1474
+ return index;
1475
+ }
1476
+ /** 根据视口内 X 坐标反查数据索引(用于绘图落点) */
1477
+ getDataIndexAtX(mouseX) {
1478
+ const index = this.getLogicalIndexAtX(mouseX);
1479
+ if (index === null || index >= this._internalData.length)
1480
+ return null;
1481
+ return index;
1482
+ }
1483
+ /** 获取内容总宽度(用于外部 scroll-content 撑开 scrollWidth) */
1484
+ getContentWidth() {
1485
+ return computeContentWidth({
1486
+ dataLength: this._internalData.length,
1487
+ kWidth: this.opt.kWidth,
1488
+ kGap: this.opt.kGap,
1489
+ viewWidth: this._internalViewport?.plotWidth ?? 0,
1490
+ viewportDpr: this.getEffectiveDpr(),
1491
+ });
1492
+ }
1493
+ /** 容器尺寸变化时调用 */
1494
+ resize() {
1495
+ const vp = this.computeViewport();
1496
+ // 防御性检查:容器尺寸无效时跳过布局
1497
+ if (!vp || vp.viewWidth < 10 || vp.viewHeight < 10) {
1498
+ return;
1499
+ }
1500
+ this.cachedDrawFrame = null;
1501
+ this.layoutPanes();
1502
+ this.emitPaneLayoutChange();
1503
+ this.updateViewportSignal();
1504
+ this.scheduleDraw();
1505
+ }
1506
+ /**
1507
+ * 请求下一帧重绘(RAF 合并,支持分层更新)
1508
+ * @param level 更新级别,默认为 All
1509
+ */
1510
+ scheduleDraw(level = UpdateLevel.All) {
1511
+ // 合并更新级别:如果已有更高级别的调度,保持高级别
1512
+ if (this.raf !== null) {
1513
+ // 已有 All 级别调度,任何新请求都忽略
1514
+ if (this.pendingUpdateLevel === UpdateLevel.All)
1515
+ return;
1516
+ // 新请求是 All,覆盖之前的 Main/Overlay
1517
+ if (level === UpdateLevel.All) {
1518
+ this.pendingUpdateLevel = UpdateLevel.All;
1519
+ return;
1520
+ }
1521
+ // Main + Overlay = All
1522
+ if ((this.pendingUpdateLevel === UpdateLevel.Main && level === UpdateLevel.Overlay) ||
1523
+ (this.pendingUpdateLevel === UpdateLevel.Overlay && level === UpdateLevel.Main)) {
1524
+ this.pendingUpdateLevel = UpdateLevel.All;
1525
+ return;
1526
+ }
1527
+ // 同级别或更低级别,忽略
1528
+ return;
1529
+ }
1530
+ this.pendingUpdateLevel = level;
1531
+ this.raf = requestAnimationFrame(() => {
1532
+ this.raf = null;
1533
+ const levelToDraw = this.pendingUpdateLevel;
1534
+ this.pendingUpdateLevel = UpdateLevel.All; // 重置为默认值
1535
+ this.draw(levelToDraw);
1536
+ });
1537
+ }
1538
+ /** 销毁图表实例 */
1539
+ async destroy() {
1540
+ if (this.raf !== null) {
1541
+ cancelAnimationFrame(this.raf);
1542
+ this.raf = null;
1543
+ }
1544
+ // 清理尺寸观察器
1545
+ this.resizeObserver?.disconnect();
1546
+ this.resizeObserver = undefined;
1547
+ this.preciseDpr = 0;
1548
+ this.observedSize = { width: 0, height: 0 };
1549
+ // 清理 scroll 监听
1550
+ if (this.onScroll) {
1551
+ this.dom.container?.removeEventListener('scroll', this.onScroll);
1552
+ this.onScroll = undefined;
1553
+ }
1554
+ this._internalViewport = null;
1555
+ this.cachedDrawFrame = null;
1556
+ this.xAxisCtx = null;
1557
+ this.paneRenderers.forEach((r) => r.destroy());
1558
+ this.paneRenderers = [];
1559
+ this.sharedWebGLSurface.destroy();
1560
+ // 清理渲染器插件管理器(会调用所有 onUninstall)
1561
+ this.rendererPluginManager.clear();
1562
+ this.onViewportChange = undefined;
1563
+ this.onPaneLayoutChange = undefined;
1564
+ this.indicatorScheduler.destroy();
1565
+ await this.pluginHost.destroy();
1566
+ }
1567
+ /** 初始化所有 pane */
1568
+ initPanes() {
1569
+ this.paneRenderers = this.opt.panes.map((spec, index) => {
1570
+ const pane = new Pane(spec.id, {
1571
+ role: this.resolvePaneRole(spec, index),
1572
+ capabilities: spec.capabilities,
1573
+ });
1574
+ const mainCanvas = document.createElement('canvas');
1575
+ const overlayCanvas = document.createElement('canvas');
1576
+ const yAxisCanvas = document.createElement('canvas');
1577
+ const isMain = pane.role === 'price';
1578
+ // Main Canvas - K线、指标、网格
1579
+ mainCanvas.id = `${spec.id}-main`;
1580
+ mainCanvas.className = isMain ? 'main-canvas main' : 'main-canvas sub';
1581
+ mainCanvas.style.position = 'absolute';
1582
+ mainCanvas.style.left = '0';
1583
+ mainCanvas.style.top = '0';
1584
+ // Overlay Canvas - 十字线、Tooltip(透明,事件穿透)
1585
+ overlayCanvas.id = `${spec.id}-overlay`;
1586
+ overlayCanvas.className = 'overlay-canvas';
1587
+ overlayCanvas.style.position = 'absolute';
1588
+ overlayCanvas.style.left = '0';
1589
+ overlayCanvas.style.top = '0';
1590
+ overlayCanvas.style.pointerEvents = 'none'; // 事件穿透到 mainCanvas
1591
+ overlayCanvas.style.backgroundColor = 'transparent';
1592
+ yAxisCanvas.id = `${spec.id}-yAxis`;
1593
+ yAxisCanvas.className = 'right-axis';
1594
+ yAxisCanvas.style.position = 'absolute';
1595
+ yAxisCanvas.style.left = '0';
1596
+ const renderer = new PaneRenderer({ mainCanvas, overlayCanvas, yAxisCanvas }, pane, {
1597
+ rightAxisWidth: this.opt.rightAxisWidth,
1598
+ yPaddingPx: this.opt.yPaddingPx,
1599
+ priceLabelWidth: this.opt.priceLabelWidth,
1600
+ }, this.sharedWebGLSurface);
1601
+ return renderer;
1602
+ });
1603
+ const canvasLayer = this.dom.canvasLayer;
1604
+ const rightAxisLayer = this.dom.rightAxisLayer;
1605
+ if (canvasLayer) {
1606
+ const existingCanvases = canvasLayer.querySelectorAll('canvas:not(.x-axis-canvas)');
1607
+ existingCanvases.forEach((canvas) => canvas.remove());
1608
+ }
1609
+ if (rightAxisLayer) {
1610
+ const existingAxisCanvases = rightAxisLayer.querySelectorAll('canvas.right-axis');
1611
+ existingAxisCanvases.forEach((canvas) => canvas.remove());
1612
+ }
1613
+ this.paneRenderers.forEach((renderer) => {
1614
+ const dom = renderer.getDom();
1615
+ // 先添加 mainCanvas,再添加 overlayCanvas(overlay 在上层)
1616
+ canvasLayer.appendChild(dom.mainCanvas);
1617
+ canvasLayer.appendChild(dom.overlayCanvas);
1618
+ rightAxisLayer.appendChild(dom.yAxisCanvas);
1619
+ });
1620
+ this.rendererPluginManager.setKnownPaneIds(this.paneRenderers.map((renderer) => renderer.getPane().id));
1621
+ }
1622
+ syncPaneRatiosFromSpecs(specs) {
1623
+ const next = new Map();
1624
+ for (const spec of specs) {
1625
+ const prev = this._internalPaneRatios.get(spec.id);
1626
+ const incoming = Number.isFinite(spec.ratio) ? spec.ratio : 0;
1627
+ const ratio = prev !== undefined ? prev : (incoming > 0 ? incoming : 1);
1628
+ next.set(spec.id, ratio);
1629
+ }
1630
+ this._internalPaneRatios = next;
1631
+ this.normalizeVisiblePaneRatios(specs);
1632
+ this.syncPaneRatiosToSpecs();
1633
+ }
1634
+ syncPaneRatiosToSpecs() {
1635
+ const visible = this.opt.panes.filter(p => p.visible !== false);
1636
+ const visibleSum = visible.reduce((s, p) => s + (this._internalPaneRatios.get(p.id) ?? p.ratio ?? 0), 0);
1637
+ const safeVisibleSum = visibleSum > 0 ? visibleSum : 1;
1638
+ this.opt.panes = this.opt.panes.map((spec) => {
1639
+ const ratio = this._internalPaneRatios.get(spec.id) ?? spec.ratio ?? 0;
1640
+ if (spec.visible === false) {
1641
+ return { ...spec, ratio };
1642
+ }
1643
+ return { ...spec, ratio: ratio / safeVisibleSum };
1644
+ });
1645
+ }
1646
+ normalizeVisiblePaneRatios(specs) {
1647
+ const visible = specs.filter(p => p.visible !== false);
1648
+ if (visible.length === 0)
1649
+ return;
1650
+ let sum = 0;
1651
+ for (const spec of visible) {
1652
+ const raw = this._internalPaneRatios.get(spec.id) ?? spec.ratio ?? 0;
1653
+ const safe = Number.isFinite(raw) && raw > 0 ? raw : 0;
1654
+ this._internalPaneRatios.set(spec.id, safe);
1655
+ sum += safe;
1656
+ }
1657
+ if (sum <= 0) {
1658
+ const equal = 1 / visible.length;
1659
+ for (const spec of visible) {
1660
+ this._internalPaneRatios.set(spec.id, equal);
1661
+ }
1662
+ return;
1663
+ }
1664
+ for (const spec of visible) {
1665
+ const v = this._internalPaneRatios.get(spec.id) ?? 0;
1666
+ this._internalPaneRatios.set(spec.id, v / sum);
1667
+ }
1668
+ }
1669
+ getPaneMinHeight(spec, plotHeight) {
1670
+ const fallback = this.opt.defaultPaneMinHeightPx ?? 120; // 最小高度
1671
+ const raw = spec.minHeightPx ?? fallback;
1672
+ return Math.max(1, Math.min(Math.round(raw), Math.max(1, plotHeight)));
1673
+ }
1674
+ computePaneHeightsByRatio(visibleSpecs, availableH) {
1675
+ if (visibleSpecs.length === 0)
1676
+ return [];
1677
+ const ratios = visibleSpecs.map(spec => this._internalPaneRatios.get(spec.id) ?? spec.ratio ?? 0);
1678
+ const ratioSum = ratios.reduce((s, r) => s + (r > 0 ? r : 0), 0);
1679
+ const safeRatios = ratioSum > 0
1680
+ ? ratios.map(r => (r > 0 ? r : 0) / ratioSum)
1681
+ : visibleSpecs.map(() => 1 / visibleSpecs.length);
1682
+ const heights = safeRatios.map(r => Math.max(1, Math.round(availableH * r)));
1683
+ const mins = visibleSpecs.map(spec => this.getPaneMinHeight(spec, availableH));
1684
+ for (let i = 0; i < heights.length; i++) {
1685
+ heights[i] = Math.max(heights[i], Math.min(mins[i], availableH));
1686
+ }
1687
+ let total = heights.reduce((s, h) => s + h, 0);
1688
+ if (total > availableH) {
1689
+ let overflow = total - availableH;
1690
+ while (overflow > 0) {
1691
+ let shrunk = false;
1692
+ for (let i = heights.length - 1; i >= 0 && overflow > 0; i--) {
1693
+ const minH = Math.max(1, Math.min(mins[i], availableH));
1694
+ const h = heights[i];
1695
+ if (h > minH) {
1696
+ heights[i] = h - 1;
1697
+ overflow--;
1698
+ shrunk = true;
1699
+ }
1700
+ }
1701
+ if (!shrunk)
1702
+ break;
1703
+ }
1704
+ }
1705
+ else if (total < availableH) {
1706
+ heights[heights.length - 1] = (heights[heights.length - 1] ?? 1) + (availableH - total);
1707
+ }
1708
+ total = heights.reduce((s, h) => s + h, 0);
1709
+ if (total !== availableH && heights.length > 0) {
1710
+ heights[heights.length - 1] = Math.max(1, (heights[heights.length - 1] ?? 1) + (availableH - total));
1711
+ }
1712
+ return heights;
1713
+ }
1714
+ /** 计算每个 pane 的布局(top 和 height) */
1715
+ layoutPanes() {
1716
+ const vp = this._internalViewport;
1717
+ if (!vp)
1718
+ return;
1719
+ const visibleSpecs = this.opt.panes.filter(p => p.visible !== false);
1720
+ if (visibleSpecs.length === 0)
1721
+ return;
1722
+ const gap = Math.max(0, this.opt.paneGap ?? 0);
1723
+ let y = 0;
1724
+ const totalGaps = gap * Math.max(0, visibleSpecs.length - 1);
1725
+ const availableH = Math.max(1, vp.plotHeight - totalGaps);
1726
+ this.normalizeVisiblePaneRatios(visibleSpecs);
1727
+ const paneHeights = this.computePaneHeightsByRatio(visibleSpecs, availableH);
1728
+ for (let i = 0; i < visibleSpecs.length; i++) {
1729
+ const spec = visibleSpecs[i];
1730
+ if (!spec)
1731
+ continue;
1732
+ const renderer = this.paneRenderers.find(r => r.getPane().id === spec.id);
1733
+ if (!renderer)
1734
+ continue;
1735
+ const pane = renderer.getPane();
1736
+ const h = paneHeights[i] ?? 1;
1737
+ pane.setLayout(y, h);
1738
+ pane.setPadding(this.opt.yPaddingPx, this.opt.yPaddingPx);
1739
+ renderer.resize(vp.plotWidth, h, vp.dpr);
1740
+ renderer.setWebGLRegion({
1741
+ x: 0,
1742
+ y,
1743
+ width: vp.plotWidth,
1744
+ height: h,
1745
+ dpr: vp.dpr,
1746
+ });
1747
+ this.rendererPluginManager.notifyResize(pane.id, wrapPaneInfo(pane));
1748
+ const dom = renderer.getDom();
1749
+ dom.mainCanvas.style.top = `${y}px`;
1750
+ dom.overlayCanvas.style.top = `${y}px`;
1751
+ dom.yAxisCanvas.style.top = `${y}px`;
1752
+ dom.yAxisCanvas.style.left = '0px';
1753
+ y += h + gap;
1754
+ }
1755
+ // 按实际像素高度回写 ratio,确保后续 resize 视觉比例稳定
1756
+ const finalAvailable = Math.max(1, availableH);
1757
+ for (const spec of visibleSpecs) {
1758
+ const renderer = this.paneRenderers.find(r => r.getPane().id === spec.id);
1759
+ if (!renderer)
1760
+ continue;
1761
+ const h = renderer.getPane().height;
1762
+ this._internalPaneRatios.set(spec.id, h / finalAvailable);
1763
+ }
1764
+ this.normalizeVisiblePaneRatios(visibleSpecs);
1765
+ this.syncPaneRatiosToSpecs();
1766
+ }
1767
+ computeViewport() {
1768
+ const container = this.dom.container;
1769
+ if (!container)
1770
+ return null;
1771
+ const observedWidth = this.observedSize.width;
1772
+ const observedHeight = this.observedSize.height;
1773
+ const viewWidth = observedWidth > 0
1774
+ ? observedWidth
1775
+ : Math.max(1, Math.round(container.clientWidth));
1776
+ const viewHeight = observedHeight > 0
1777
+ ? observedHeight
1778
+ : Math.max(1, Math.round(container.clientHeight));
1779
+ const plotWidth = Math.round(viewWidth);
1780
+ const plotHeight = Math.round(viewHeight - this.opt.bottomAxisHeight);
1781
+ let dpr = this.getEffectiveDpr();
1782
+ const MAX_CANVAS_PIXELS = 16 * 1024 * 1024;
1783
+ const requestedPixels = viewWidth * dpr * (viewHeight * dpr);
1784
+ if (requestedPixels > MAX_CANVAS_PIXELS) {
1785
+ dpr = Math.sqrt(MAX_CANVAS_PIXELS / (viewWidth * viewHeight));
1786
+ }
1787
+ // 对齐 scrollLeft,消除 translate 亚像素偏移
1788
+ const scrollLeft = Math.round(this.cachedScrollLeft * dpr) / dpr;
1789
+ const canvasLayerWidth = `${viewWidth}px`;
1790
+ if (this.dom.canvasLayer.style.width !== canvasLayerWidth) {
1791
+ this.dom.canvasLayer.style.width = canvasLayerWidth;
1792
+ }
1793
+ const canvasLayerHeight = `${viewHeight}px`;
1794
+ if (this.dom.canvasLayer.style.height !== canvasLayerHeight) {
1795
+ this.dom.canvasLayer.style.height = canvasLayerHeight;
1796
+ }
1797
+ const xAxisWidth = Math.round(plotWidth * dpr);
1798
+ if (this.dom.xAxisCanvas.width !== xAxisWidth) {
1799
+ this.dom.xAxisCanvas.width = xAxisWidth;
1800
+ }
1801
+ const xAxisHeight = Math.round(this.opt.bottomAxisHeight * dpr);
1802
+ if (this.dom.xAxisCanvas.height !== xAxisHeight) {
1803
+ this.dom.xAxisCanvas.height = xAxisHeight;
1804
+ }
1805
+ const xAxisCssWidth = `${xAxisWidth / dpr}px`;
1806
+ if (this.dom.xAxisCanvas.style.width !== xAxisCssWidth) {
1807
+ this.dom.xAxisCanvas.style.width = xAxisCssWidth;
1808
+ }
1809
+ const xAxisCssHeight = `${xAxisHeight / dpr}px`;
1810
+ if (this.dom.xAxisCanvas.style.height !== xAxisCssHeight) {
1811
+ this.dom.xAxisCanvas.style.height = xAxisCssHeight;
1812
+ }
1813
+ this.sharedWebGLSurface.resize(plotWidth, plotHeight, dpr);
1814
+ const vp = {
1815
+ viewWidth,
1816
+ viewHeight,
1817
+ plotWidth,
1818
+ plotHeight,
1819
+ scrollLeft,
1820
+ dpr,
1821
+ };
1822
+ const prevViewport = this._internalViewport;
1823
+ const viewportChanged = !prevViewport
1824
+ || prevViewport.viewWidth !== vp.viewWidth
1825
+ || prevViewport.viewHeight !== vp.viewHeight
1826
+ || prevViewport.plotWidth !== vp.plotWidth
1827
+ || prevViewport.plotHeight !== vp.plotHeight
1828
+ || prevViewport.scrollLeft !== vp.scrollLeft
1829
+ || prevViewport.dpr !== vp.dpr;
1830
+ this._internalViewport = vp;
1831
+ if (viewportChanged) {
1832
+ this.onViewportChange?.(vp);
1833
+ }
1834
+ return vp;
1835
+ }
1836
+ // ==================== Facade API (High-level interface for adapters) ====================
1837
+ // ---------- Signals ----------
1838
+ _viewportSignal = createSignal({
1839
+ zoomLevel: 1,
1840
+ plotWidth: 0,
1841
+ plotHeight: 0,
1842
+ dpr: 1,
1843
+ visibleFrom: 0,
1844
+ visibleTo: 0,
1845
+ desiredScrollLeft: undefined,
1846
+ kWidth: 0,
1847
+ kGap: 1,
1848
+ });
1849
+ _dataSignal = createSignal([]);
1850
+ _themeSignal = createSignal('light');
1851
+ _indicatorsSignal = createSignal([]);
1852
+ _subPanesSignal = createSignal([]);
1853
+ _drawingToolSignal = createSignal(null);
1854
+ _drawingsSignal = createSignal([]);
1855
+ _paneRatiosSignal = createSignal({});
1856
+ _interactionSignal = createSignal({
1857
+ crosshairPos: null,
1858
+ crosshairIndex: null,
1859
+ crosshairPrice: null,
1860
+ hoveredIndex: null,
1861
+ activePaneId: null,
1862
+ tooltipPos: { x: 0, y: 0 },
1863
+ tooltipAnchorPlacement: 'right-bottom',
1864
+ hoveredMarkerData: null,
1865
+ hoveredCustomMarker: null,
1866
+ isDragging: false,
1867
+ isResizingPaneBoundary: false,
1868
+ isHoveringPaneBoundary: false,
1869
+ hoveredPaneBoundaryId: null,
1870
+ isHoveringRightAxis: false,
1871
+ });
1872
+ /** 视口状态信号 */
1873
+ get viewport() {
1874
+ return this._viewportSignal;
1875
+ }
1876
+ /** 数据信号 */
1877
+ get data() {
1878
+ return this._dataSignal;
1879
+ }
1880
+ /** 主题信号 */
1881
+ get theme() {
1882
+ return this._themeSignal;
1883
+ }
1884
+ /** 指标实例列表信号 */
1885
+ get indicators() {
1886
+ return this._indicatorsSignal;
1887
+ }
1888
+ /** 子图信息信号 */
1889
+ get subPanes() {
1890
+ return this._subPanesSignal;
1891
+ }
1892
+ /** 当前绘图工具信号 */
1893
+ get drawingTool() {
1894
+ return this._drawingToolSignal;
1895
+ }
1896
+ /** 绘图对象列表信号 */
1897
+ get drawings() {
1898
+ return this._drawingsSignal;
1899
+ }
1900
+ /** 面板比例信号 */
1901
+ get paneRatios() {
1902
+ return this._paneRatiosSignal;
1903
+ }
1904
+ /** 交互状态信号 */
1905
+ get interactionState() {
1906
+ return this._interactionSignal;
1907
+ }
1908
+ // ---------- Data ----------
1909
+ /**
1910
+ * 设置数据(高层 API)
1911
+ * 内部调用 updateData,并更新 data signal
1912
+ */
1913
+ setData(data) {
1914
+ this.updateData(data);
1915
+ }
1916
+ /**
1917
+ * 追加数据(高层 API)
1918
+ * 合并现有数据并更新
1919
+ */
1920
+ appendData(newData) {
1921
+ const merged = [...this._internalData, ...newData];
1922
+ this.setData(merged);
1923
+ }
1924
+ // ---------- Theme ----------
1925
+ /**
1926
+ * 设置主题(高层 API)
1927
+ */
1928
+ setTheme(theme) {
1929
+ this._themeSignal.set(theme);
1930
+ this.scheduleDraw();
1931
+ }
1932
+ // ---------- Zoom ----------
1933
+ /**
1934
+ * 缩放到指定级别(高层 API)
1935
+ * 计算并应用新的 render state,更新 viewport signal
1936
+ */
1937
+ zoomToLevel(level, anchorX) {
1938
+ const clamped = Math.max(1, Math.min(this.zoomLevelCount, Math.round(level)));
1939
+ this.applyZoom(clamped, anchorX);
1940
+ }
1941
+ /**
1942
+ * 放大(高层 API)
1943
+ */
1944
+ zoomIn(anchorX) {
1945
+ this.zoomToLevel(this.currentZoomLevel + 1, anchorX);
1946
+ }
1947
+ /**
1948
+ * 缩小(高层 API)
1949
+ */
1950
+ zoomOut(anchorX) {
1951
+ this.zoomToLevel(this.currentZoomLevel - 1, anchorX);
1952
+ }
1953
+ /**
1954
+ * 内部缩放实现
1955
+ * 使用 computeZoom 纯函数计算精确的 scrollLeft
1956
+ */
1957
+ applyZoom(targetLevel, anchorViewportX) {
1958
+ if (targetLevel === this.currentZoomLevel)
1959
+ return;
1960
+ const delta = targetLevel - this.currentZoomLevel;
1961
+ const scrollLeft = this.getCachedScrollLeft();
1962
+ const dpr = this.getCurrentDpr();
1963
+ const result = computeZoom(delta, anchorViewportX ?? 0, scrollLeft, this.currentZoomLevel, this.opt.kWidth, this.opt.kGap, {
1964
+ minKWidth: this.opt.minKWidth,
1965
+ maxKWidth: this.opt.maxKWidth,
1966
+ zoomLevelCount: this.zoomLevelCount,
1967
+ dpr,
1968
+ });
1969
+ if (!result)
1970
+ return;
1971
+ // 应用 render state
1972
+ this.currentZoomLevel = result.targetLevel;
1973
+ this.applyRenderState(result.newKWidth, result.newKGap, result.targetLevel);
1974
+ // 更新 viewport signal
1975
+ this._viewportSignal.set({
1976
+ zoomLevel: result.targetLevel,
1977
+ plotWidth: this._internalViewport?.plotWidth ?? 0,
1978
+ plotHeight: this._internalViewport?.plotHeight ?? 0,
1979
+ dpr,
1980
+ visibleFrom: this.lastVisibleRange.start,
1981
+ visibleTo: this.lastVisibleRange.end,
1982
+ desiredScrollLeft: result.newScrollLeft,
1983
+ kWidth: result.newKWidth,
1984
+ kGap: result.newKGap,
1985
+ });
1986
+ }
1987
+ // ---------- Interaction (Zero-config unified entry) ----------
1988
+ /**
1989
+ * 统一指针事件处理(零配置)
1990
+ * 自动判断区域并分发给 interaction controller
1991
+ *
1992
+ * @param e 指针事件
1993
+ * @param drawingController 可选的绘图控制器,如果提供,会优先让绘图控制器处理事件
1994
+ * @returns 是否被处理(如果 drawingController 处理了返回 true,否则返回 false)
1995
+ */
1996
+ handlePointerEvent(e, drawingController) {
1997
+ // 判断事件目标是否在右轴区域
1998
+ const isRightAxis = this.dom.rightAxisLayer.contains(e.target);
1999
+ switch (e.type) {
2000
+ case 'pointerdown':
2001
+ // 优先让绘图控制器处理
2002
+ if (drawingController?.onPointerDown) {
2003
+ const handled = drawingController.onPointerDown(e, this.dom.container);
2004
+ if (handled)
2005
+ return true;
2006
+ }
2007
+ if (isRightAxis) {
2008
+ this.interaction.onRightAxisPointerDown(e);
2009
+ }
2010
+ else {
2011
+ this.interaction.onPointerDown(e);
2012
+ }
2013
+ return false;
2014
+ case 'pointermove':
2015
+ // 优先让绘图控制器处理
2016
+ if (drawingController?.onPointerMove) {
2017
+ const handled = drawingController.onPointerMove(e, this.dom.container);
2018
+ if (handled)
2019
+ return true;
2020
+ }
2021
+ if (isRightAxis) {
2022
+ this.interaction.onRightAxisPointerMove(e);
2023
+ }
2024
+ else {
2025
+ this.interaction.onPointerMove(e);
2026
+ }
2027
+ return false;
2028
+ case 'pointerup':
2029
+ // 优先让绘图控制器处理
2030
+ if (drawingController?.onPointerUp) {
2031
+ const handled = drawingController.onPointerUp(e, this.dom.container);
2032
+ if (handled)
2033
+ return true;
2034
+ }
2035
+ if (isRightAxis) {
2036
+ this.interaction.onRightAxisPointerUp(e);
2037
+ }
2038
+ else {
2039
+ this.interaction.onPointerUp(e);
2040
+ }
2041
+ return false;
2042
+ case 'pointerleave':
2043
+ // pointerleave 通常不用于绘图,直接交给 interaction
2044
+ if (isRightAxis) {
2045
+ this.interaction.onRightAxisPointerLeave(e);
2046
+ }
2047
+ else {
2048
+ this.interaction.onPointerLeave(e);
2049
+ }
2050
+ return false;
2051
+ default:
2052
+ return false;
2053
+ }
2054
+ }
2055
+ /**
2056
+ * 滚轮事件处理(高层 API)
2057
+ * 使用 computeZoom 计算精确的 scrollLeft,更新 viewport signal
2058
+ */
2059
+ handleWheelEvent(e) {
2060
+ const delta = e.deltaY > 0 ? -1 : 1;
2061
+ const targetLevel = Math.max(1, Math.min(this.zoomLevelCount, this.currentZoomLevel + delta));
2062
+ if (targetLevel === this.currentZoomLevel)
2063
+ return;
2064
+ // 获取鼠标在视口中的位置作为缩放锚点(视口局部坐标)
2065
+ const rect = this.dom.container.getBoundingClientRect();
2066
+ const mouseX = e.clientX - rect.left;
2067
+ this.applyZoom(targetLevel, mouseX);
2068
+ }
2069
+ /**
2070
+ * 滚动事件处理(高层 API)
2071
+ * 更新缓存的 scrollLeft 并触发交互 controller
2072
+ */
2073
+ handleScrollEvent() {
2074
+ this.interaction.onScroll();
2075
+ // 更新 viewport signal 中的 visible range
2076
+ this.updateViewportSignal();
2077
+ }
2078
+ /**
2079
+ * 双指捏合缩放处理(高层 API)
2080
+ * @param delta 缩放增量(+1 放大 / -1 缩小)
2081
+ * @param centerClientX 捏合中心在视口中的 X 坐标
2082
+ */
2083
+ handlePinchZoom(delta, centerClientX) {
2084
+ const targetLevel = Math.max(1, Math.min(this.zoomLevelCount, this.currentZoomLevel + delta));
2085
+ if (targetLevel === this.currentZoomLevel)
2086
+ return;
2087
+ // centerClientX 已经是视口局部坐标,直接使用
2088
+ this.applyZoom(targetLevel, centerClientX);
2089
+ }
2090
+ /**
2091
+ * 更新 viewport signal(用于滚动事件,不更新 desiredScrollLeft)
2092
+ */
2093
+ updateViewportSignal() {
2094
+ const vp = this._internalViewport;
2095
+ if (!vp)
2096
+ return;
2097
+ this._viewportSignal.set({
2098
+ zoomLevel: this.currentZoomLevel,
2099
+ plotWidth: vp.plotWidth,
2100
+ plotHeight: vp.plotHeight,
2101
+ dpr: vp.dpr,
2102
+ visibleFrom: this.lastVisibleRange.start,
2103
+ visibleTo: this.lastVisibleRange.end,
2104
+ // 滚动事件不设置 desiredScrollLeft
2105
+ desiredScrollLeft: undefined,
2106
+ kWidth: this.opt.kWidth,
2107
+ kGap: this.opt.kGap,
2108
+ });
2109
+ }
2110
+ // ---------- Indicators (Explicit role) ----------
2111
+ /**
2112
+ * 添加指标(高层 API,显式指定 role)
2113
+ * @param definitionId 指标定义 ID(如 'MA', 'MACD')
2114
+ * @param role 'main' 主图指标 或 'sub' 副图指标
2115
+ * @param params 指标参数
2116
+ * @returns 实例 ID(成功)或 null(失败)
2117
+ */
2118
+ addIndicator(definitionId, role, params) {
2119
+ if (role === 'main') {
2120
+ const success = this.enableMainIndicator(definitionId, params);
2121
+ if (!success)
2122
+ return null;
2123
+ // 更新 indicators signal
2124
+ this.syncIndicatorsSignal();
2125
+ return definitionId.toUpperCase();
2126
+ }
2127
+ else {
2128
+ // 副图指标
2129
+ const paneId = `${definitionId.toUpperCase()}_${Date.now()}`;
2130
+ const success = this.createSubPane(paneId, definitionId, params);
2131
+ if (!success)
2132
+ return null;
2133
+ // 更新 signals
2134
+ this.syncIndicatorsSignal();
2135
+ this.syncSubPanesSignal();
2136
+ return paneId;
2137
+ }
2138
+ }
2139
+ /**
2140
+ * 移除指标(高层 API)
2141
+ * @param instanceId 指标实例 ID
2142
+ * @returns 是否成功移除
2143
+ */
2144
+ removeIndicator(instanceId) {
2145
+ const id = instanceId.toUpperCase();
2146
+ // 先尝试作为主图指标移除(直接检查内部状态,不依赖 signal)
2147
+ if (this.activeMainIndicators.has(id)) {
2148
+ const success = this.disableMainIndicator(instanceId);
2149
+ if (success) {
2150
+ this.syncIndicatorsSignal();
2151
+ }
2152
+ return success;
2153
+ }
2154
+ // 再尝试作为副图指标移除(检查 sub pane 是否存在)
2155
+ const subPaneEntry = this.getSubPaneEntry(instanceId);
2156
+ if (subPaneEntry) {
2157
+ this.removeSubPane(instanceId);
2158
+ this.syncIndicatorsSignal();
2159
+ this.syncSubPanesSignal();
2160
+ return true;
2161
+ }
2162
+ // 都没找到,返回 false
2163
+ return false;
2164
+ }
2165
+ /**
2166
+ * 更新指标参数(高层 API)
2167
+ * @param instanceId 指标实例 ID
2168
+ * @param params 新参数
2169
+ * @returns 是否成功更新
2170
+ */
2171
+ updateIndicatorParams(instanceId, params) {
2172
+ const id = instanceId.toUpperCase();
2173
+ // 先尝试作为主图指标更新(直接检查内部状态)
2174
+ if (this.activeMainIndicators.has(id)) {
2175
+ this.updateMainIndicatorParams(instanceId, params);
2176
+ this.syncIndicatorsSignal();
2177
+ return true;
2178
+ }
2179
+ // 再尝试作为副图指标更新
2180
+ const subPaneEntry = this.getSubPaneEntry(instanceId);
2181
+ if (subPaneEntry) {
2182
+ this.updateSubPaneParams(instanceId, params);
2183
+ this.syncIndicatorsSignal();
2184
+ return true;
2185
+ }
2186
+ // 都没找到
2187
+ return false;
2188
+ }
2189
+ /**
2190
+ * 重新排序指标(高层 API)
2191
+ * @param orderedInstanceIds 排序后的指标实例 ID 数组
2192
+ * @returns 是否成功
2193
+ */
2194
+ reorderIndicators(orderedInstanceIds) {
2195
+ // TODO: 实现副图指标的重新排序
2196
+ // 需要调用 updatePaneLayout 来调整 pane 顺序
2197
+ console.warn('[Chart] reorderIndicators not fully implemented yet');
2198
+ return false;
2199
+ }
2200
+ /**
2201
+ * 同步 indicators signal
2202
+ */
2203
+ syncIndicatorsSignal() {
2204
+ const mainIndicators = this.getActiveMainIndicators().map(id => ({
2205
+ id,
2206
+ definitionId: id,
2207
+ label: id,
2208
+ name: id,
2209
+ role: 'main',
2210
+ params: this.getMainIndicatorParams(id) ?? {},
2211
+ }));
2212
+ const subIndicators = this.getSubPaneEntries().map(entry => ({
2213
+ id: entry.paneId,
2214
+ definitionId: entry.indicatorId,
2215
+ label: entry.indicatorId,
2216
+ name: entry.indicatorId,
2217
+ role: 'sub',
2218
+ paneId: entry.paneId,
2219
+ params: entry.params,
2220
+ }));
2221
+ this._indicatorsSignal.set([...mainIndicators, ...subIndicators]);
2222
+ }
2223
+ /**
2224
+ * 同步 sub panes signal
2225
+ */
2226
+ syncSubPanesSignal() {
2227
+ const entries = this.getSubPaneEntries();
2228
+ const subPanes = entries.map(entry => ({
2229
+ paneId: entry.paneId,
2230
+ indicatorId: entry.indicatorId,
2231
+ params: entry.params,
2232
+ ratio: this._internalPaneRatios.get(entry.paneId) ?? 1,
2233
+ }));
2234
+ this._subPanesSignal.set(subPanes);
2235
+ }
2236
+ // ---------- Sub Panes ----------
2237
+ /**
2238
+ * 调整子图大小(高层 API)
2239
+ * @param paneId 面板 ID
2240
+ * @param deltaY 垂直偏移量
2241
+ * @returns 是否成功
2242
+ */
2243
+ resizeSubPane(paneId, deltaY) {
2244
+ return this.resizePaneBoundary(paneId, deltaY);
2245
+ }
2246
+ // ---------- Drawings ----------
2247
+ /**
2248
+ * 设置当前绘图工具(高层 API)
2249
+ * @param tool 工具类型或 null 取消选择
2250
+ */
2251
+ setDrawingTool(tool) {
2252
+ this._drawingToolSignal.set(tool);
2253
+ // TODO: 当 Chart 支持绘图工具切换时,在这里调用相应方法
2254
+ }
2255
+ /**
2256
+ * 移除绘图(高层 API)
2257
+ * @param drawingId 绘图 ID
2258
+ */
2259
+ removeDrawing(drawingId) {
2260
+ // TODO: 实现绘图移除
2261
+ console.warn('[Chart] removeDrawing not fully implemented yet');
2262
+ }
2263
+ /**
2264
+ * 清除所有绘图(高层 API)
2265
+ */
2266
+ clearDrawings() {
2267
+ this.setDrawings([]);
2268
+ }
2269
+ // ---------- Settings ----------
2270
+ /**
2271
+ * 更新设置(高层 API)
2272
+ * 代理到现有的 updateSettings
2273
+ */
2274
+ updateSettingsFacade(settings) {
2275
+ this.updateSettings(settings);
2276
+ }
2277
+ /**
2278
+ * 更新选项(高层 API)
2279
+ * 代理到现有的 updateOptions
2280
+ */
2281
+ updateOptionsFacade(options) {
2282
+ this.updateOptions(options);
2283
+ }
2284
+ }
2285
+ //# sourceMappingURL=chart.js.map