@quantlife/qlchart 0.0.1

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 (321) hide show
  1. package/.idea/QLChart.iml +12 -0
  2. package/.idea/modules.xml +8 -0
  3. package/.idea/vcs.xml +6 -0
  4. package/README.md +75 -0
  5. package/demo/App.css +213 -0
  6. package/demo/App.tsx +46 -0
  7. package/demo/components/ControlPanel.tsx +13 -0
  8. package/demo/components/DemoNav.tsx +27 -0
  9. package/demo/index.html +16 -0
  10. package/demo/main.tsx +10 -0
  11. package/demo/pages/BasicChartDemo.tsx +61 -0
  12. package/demo/pages/DrawingDemo.tsx +22 -0
  13. package/demo/pages/IndicatorDemo.tsx +22 -0
  14. package/demo/pages/LayoutDemo.tsx +35 -0
  15. package/demo/pages/MultiPeriodDemo.tsx +31 -0
  16. package/demo/pages/ReplayDemo.tsx +195 -0
  17. package/demo/pages/SaveDemo.tsx +27 -0
  18. package/demo/pages/ThemeDemo.tsx +29 -0
  19. package/demo/standalone-demo.html +597 -0
  20. package/demo/vite.config.demo.ts +17 -0
  21. package/dist/index.d.ts +1973 -0
  22. package/dist/qlchart.js +23169 -0
  23. package/dist/style.css +1 -0
  24. package/doc/api/indicator-data-processor.md +35 -0
  25. package/doc/api-reference/.nojekyll +1 -0
  26. package/doc/api-reference/assets/hierarchy.js +1 -0
  27. package/doc/api-reference/assets/highlight.css +43 -0
  28. package/doc/api-reference/assets/icons.js +18 -0
  29. package/doc/api-reference/assets/icons.svg +1 -0
  30. package/doc/api-reference/assets/main.js +60 -0
  31. package/doc/api-reference/assets/navigation.js +1 -0
  32. package/doc/api-reference/assets/search.js +1 -0
  33. package/doc/api-reference/assets/style.css +1611 -0
  34. package/doc/api-reference/classes/ChartManager.html +16 -0
  35. package/doc/api-reference/classes/DataManager.html +13 -0
  36. package/doc/api-reference/classes/DrawingAdapter.html +64 -0
  37. package/doc/api-reference/classes/DrawingPersistence.html +21 -0
  38. package/doc/api-reference/classes/EventManager.html +12 -0
  39. package/doc/api-reference/classes/HollowCandlestickSeries.html +22 -0
  40. package/doc/api-reference/classes/IndicatorRenderer.html +20 -0
  41. package/doc/api-reference/classes/KlineReplay.html +31 -0
  42. package/doc/api-reference/classes/MockDataService.html +13 -0
  43. package/doc/api-reference/classes/MockIndicatorService.html +4 -0
  44. package/doc/api-reference/classes/OverlayIndicator.html +11 -0
  45. package/doc/api-reference/classes/PaneIndicator.html +16 -0
  46. package/doc/api-reference/classes/PaneManager.html +24 -0
  47. package/doc/api-reference/classes/RealtimeDataFeed.html +22 -0
  48. package/doc/api-reference/classes/RenkoSeries.html +22 -0
  49. package/doc/api-reference/classes/ScreenshotUtil.html +10 -0
  50. package/doc/api-reference/classes/SeriesManager.html +30 -0
  51. package/doc/api-reference/classes/ThemeManager.html +18 -0
  52. package/doc/api-reference/enums/ChartEvent.html +12 -0
  53. package/doc/api-reference/enums/IndicatorType.html +4 -0
  54. package/doc/api-reference/enums/SeriesType.html +13 -0
  55. package/doc/api-reference/functions/ChartFunctionMenu.html +1 -0
  56. package/doc/api-reference/functions/DrawingModule.html +8 -0
  57. package/doc/api-reference/functions/IndicatorPanel.html +2 -0
  58. package/doc/api-reference/functions/IndicatorTag.html +2 -0
  59. package/doc/api-reference/functions/KlineTypeSelector.html +1 -0
  60. package/doc/api-reference/functions/LayoutSwitcher.html +1 -0
  61. package/doc/api-reference/functions/PeriodSelector.html +1 -0
  62. package/doc/api-reference/functions/QLChartLayout.html +1 -0
  63. package/doc/api-reference/functions/QLChartPanel.html +10 -0
  64. package/doc/api-reference/functions/QLChartProvider.html +2 -0
  65. package/doc/api-reference/functions/QLToolbar.html +1 -0
  66. package/doc/api-reference/functions/ReplayController.html +1 -0
  67. package/doc/api-reference/functions/TimeBarModule.html +4 -0
  68. package/doc/api-reference/functions/TimeRangeSelector.html +1 -0
  69. package/doc/api-reference/functions/createIndicatorConfig.html +2 -0
  70. package/doc/api-reference/functions/getToolConfig.html +2 -0
  71. package/doc/api-reference/functions/getToolsByCategory.html +2 -0
  72. package/doc/api-reference/functions/getToolsByPriority.html +2 -0
  73. package/doc/api-reference/functions/mapLibTypeToOurs.html +2 -0
  74. package/doc/api-reference/functions/mapToolTypeToLib.html +3 -0
  75. package/doc/api-reference/functions/transformCandlestickData.html +3 -0
  76. package/doc/api-reference/functions/transformIndicatorData.html +2 -0
  77. package/doc/api-reference/functions/transformVolumeData.html +3 -0
  78. package/doc/api-reference/functions/useChart.html +4 -0
  79. package/doc/api-reference/functions/useChartStore.html +8 -0
  80. package/doc/api-reference/functions/useCrosshairSync.html +8 -0
  81. package/doc/api-reference/functions/useDrawingModule.html +1 -0
  82. package/doc/api-reference/functions/useDrawingStore.html +8 -0
  83. package/doc/api-reference/functions/useIndicatorStore.html +8 -0
  84. package/doc/api-reference/functions/useQLChartConfig.html +2 -0
  85. package/doc/api-reference/functions/useReplayStore.html +8 -0
  86. package/doc/api-reference/functions/useTheme.html +2 -0
  87. package/doc/api-reference/functions/useTimeBarStore.html +8 -0
  88. package/doc/api-reference/index.html +1 -0
  89. package/doc/api-reference/interfaces/CandlestickData.html +7 -0
  90. package/doc/api-reference/interfaces/CandlestickRawData.html +8 -0
  91. package/doc/api-reference/interfaces/ChartFunctionMenuProps.html +2 -0
  92. package/doc/api-reference/interfaces/ChartManagerCreateOptions.html +4 -0
  93. package/doc/api-reference/interfaces/ChartOptions.html +8 -0
  94. package/doc/api-reference/interfaces/ChartRequestParams.html +8 -0
  95. package/doc/api-reference/interfaces/ChartResponse.html +5 -0
  96. package/doc/api-reference/interfaces/ChartState.html +24 -0
  97. package/doc/api-reference/interfaces/ChartThemeOptions.html +5 -0
  98. package/doc/api-reference/interfaces/CrosshairData.html +5 -0
  99. package/doc/api-reference/interfaces/DrawingModuleProps.html +5 -0
  100. package/doc/api-reference/interfaces/DrawingState.html +48 -0
  101. package/doc/api-reference/interfaces/HistogramData.html +5 -0
  102. package/doc/api-reference/interfaces/HollowCandlestickData.html +14 -0
  103. package/doc/api-reference/interfaces/IndicatorConfig.html +11 -0
  104. package/doc/api-reference/interfaces/IndicatorDataPoint.html +4 -0
  105. package/doc/api-reference/interfaces/IndicatorDataResponse.html +5 -0
  106. package/doc/api-reference/interfaces/IndicatorDefinition.html +9 -0
  107. package/doc/api-reference/interfaces/IndicatorPanelProps.html +3 -0
  108. package/doc/api-reference/interfaces/IndicatorParamDef.html +8 -0
  109. package/doc/api-reference/interfaces/IndicatorRawData.html +4 -0
  110. package/doc/api-reference/interfaces/IndicatorState.html +19 -0
  111. package/doc/api-reference/interfaces/IndicatorTagProps.html +2 -0
  112. package/doc/api-reference/interfaces/KlineReplayOptions.html +4 -0
  113. package/doc/api-reference/interfaces/LayoutSwitcherProps.html +3 -0
  114. package/doc/api-reference/interfaces/LineData.html +4 -0
  115. package/doc/api-reference/interfaces/MockDataConfig.html +8 -0
  116. package/doc/api-reference/interfaces/MockIndicatorConfig.html +5 -0
  117. package/doc/api-reference/interfaces/PairInfo.html +6 -0
  118. package/doc/api-reference/interfaces/PaneInfo.html +6 -0
  119. package/doc/api-reference/interfaces/PanelConfig.html +9 -0
  120. package/doc/api-reference/interfaces/PersistenceConfig.html +12 -0
  121. package/doc/api-reference/interfaces/QLChartConfig.html +18 -0
  122. package/doc/api-reference/interfaces/QLChartLayoutProps.html +9 -0
  123. package/doc/api-reference/interfaces/QLChartPanelProps.html +13 -0
  124. package/doc/api-reference/interfaces/QLChartPanelRef.html +14 -0
  125. package/doc/api-reference/interfaces/QLToolbarProps.html +7 -0
  126. package/doc/api-reference/interfaces/RealtimeCandle.html +9 -0
  127. package/doc/api-reference/interfaces/RealtimeSubscribeFn.html +2 -0
  128. package/doc/api-reference/interfaces/RenkoData.html +16 -0
  129. package/doc/api-reference/interfaces/ReplayControllerProps.html +2 -0
  130. package/doc/api-reference/interfaces/ReplayState.html +19 -0
  131. package/doc/api-reference/interfaces/ThemeConfig.html +14 -0
  132. package/doc/api-reference/interfaces/TimeBarModuleProps.html +5 -0
  133. package/doc/api-reference/interfaces/TimeBarState.html +13 -0
  134. package/doc/api-reference/interfaces/UseChartReturn.html +4 -0
  135. package/doc/api-reference/interfaces/UseDrawingModuleOptions.html +11 -0
  136. package/doc/api-reference/interfaces/UseDrawingModuleReturn.html +6 -0
  137. package/doc/api-reference/interfaces/UseThemeReturn.html +5 -0
  138. package/doc/api-reference/types/EventHandler.html +2 -0
  139. package/doc/api-reference/types/FetchFn.html +2 -0
  140. package/doc/api-reference/types/LayoutMode.html +2 -0
  141. package/doc/api-reference/types/MarketTrend.html +2 -0
  142. package/doc/api-reference/types/ThemePreset.html +2 -0
  143. package/doc/api-reference/variables/BUILTIN_INDICATORS.html +2 -0
  144. package/doc/api-reference/variables/CATEGORY_LABELS.html +2 -0
  145. package/doc/api-reference/variables/DRAWING_TOOLS.html +3 -0
  146. package/doc/api-reference/variables/MARKET_PRESETS.html +1 -0
  147. package/doc/api-reference/variables/PAIR_PRESETS.html +1 -0
  148. package/doc/api-reference/variables/darkPreset.html +1 -0
  149. package/doc/api-reference/variables/lightPreset.html +1 -0
  150. package/doc/components/drawing-module.md +24 -0
  151. package/doc/components/indicator-list-panel.md +24 -0
  152. package/doc/components/indicator-panel.md +17 -0
  153. package/doc/components/pane-divider.md +25 -0
  154. package/doc/components/qlchart-layout.md +30 -0
  155. package/doc/components/qlchart-panel.md +93 -0
  156. package/doc/components/qlchart-provider.md +73 -0
  157. package/doc/components/qltoolbar.md +17 -0
  158. package/doc/components/replay-controller.md +23 -0
  159. package/doc/components/timebar-module.md +13 -0
  160. package/doc/core/chart-manager.md +14 -0
  161. package/doc/core/data-manager.md +33 -0
  162. package/doc/core/event-manager.md +26 -0
  163. package/doc/core/pane-manager.md +13 -0
  164. package/doc/core/series-manager.md +19 -0
  165. package/doc/core/theme-manager.md +21 -0
  166. package/doc/examples/basic-chart.md +24 -0
  167. package/doc/examples/data-format-guide.md +119 -0
  168. package/doc/examples/drawing-tools.md +30 -0
  169. package/doc/examples/indicator-properties.md +34 -0
  170. package/doc/examples/multi-pane.md +24 -0
  171. package/doc/examples/multi-panel.md +23 -0
  172. package/doc/examples/realtime-data.md +147 -0
  173. package/doc/examples/standalone-js.md +333 -0
  174. package/doc/guide/architecture.md +87 -0
  175. package/doc/guide/data-flow.md +310 -0
  176. package/doc/guide/deployment.md +59 -0
  177. package/doc/guide/drawing-properties.md +40 -0
  178. package/doc/guide/getting-started.md +94 -0
  179. package/doc/guide/pane-system.md +47 -0
  180. package/doc/guide/theme-switching.md +58 -0
  181. package/doc/hooks/use-chart.md +20 -0
  182. package/doc/hooks/use-crosshair-sync.md +14 -0
  183. package/doc/hooks/use-drawing-module.md +43 -0
  184. package/doc/hooks/use-theme.md +15 -0
  185. package/doc/index.md +33 -0
  186. package/doc/plugins/drawing/overview.md +36 -0
  187. package/doc/plugins/drawing/persistence.md +42 -0
  188. package/doc/plugins/drawing/tool-registry.md +29 -0
  189. package/doc/plugins/hollow-candlestick.md +18 -0
  190. package/doc/plugins/indicators.md +28 -0
  191. package/doc/plugins/renko.md +17 -0
  192. package/doc/plugins/replay.md +21 -0
  193. package/doc/plugins/screenshot.md +20 -0
  194. package/docs/api.md +94 -0
  195. package/package.json +54 -0
  196. package/python/qlchart/__init__.py +9 -0
  197. package/python/qlchart/__pycache__/__init__.cpython-311.pyc +0 -0
  198. package/python/qlchart/__pycache__/chart.cpython-311.pyc +0 -0
  199. package/python/qlchart/chart.py +333 -0
  200. package/python/qlchart/templates/chart_template.html +304 -0
  201. package/python/requirements.txt +1 -0
  202. package/python/setup.py +18 -0
  203. package/python/tests/__init__.py +1 -0
  204. package/python/tests/__pycache__/__init__.cpython-311.pyc +0 -0
  205. package/python/tests/__pycache__/test_chart.cpython-311-pytest-8.3.3.pyc +0 -0
  206. package/python/tests/test_chart.py +114 -0
  207. package/quantlife-qlchart-0.0.1.tgz +0 -0
  208. package/src/api/chartApi.ts +30 -0
  209. package/src/api/indicatorApi.ts +27 -0
  210. package/src/components/ChartFunctionMenu.tsx +64 -0
  211. package/src/components/PaneChartPanel.tsx +116 -0
  212. package/src/components/PaneDivider.tsx +66 -0
  213. package/src/components/QLChartLayout.tsx +151 -0
  214. package/src/components/QLChartPanel.tsx +560 -0
  215. package/src/components/QLChartProvider.tsx +90 -0
  216. package/src/components/context-menu/ChartContextMenu.tsx +139 -0
  217. package/src/components/context-menu/index.ts +2 -0
  218. package/src/components/drawing/DrawingModule.tsx +36 -0
  219. package/src/components/drawing/DrawingPropertyPanel.tsx +347 -0
  220. package/src/components/drawing/DrawingToolbar.tsx +305 -0
  221. package/src/components/drawing/index.ts +5 -0
  222. package/src/components/index.ts +43 -0
  223. package/src/components/indicator/IndicatorListPanel.tsx +94 -0
  224. package/src/components/indicator/IndicatorModal.tsx +171 -0
  225. package/src/components/indicator/IndicatorPanel.tsx +9 -0
  226. package/src/components/indicator/IndicatorPropertyPanel.tsx +130 -0
  227. package/src/components/indicator/IndicatorTag.tsx +173 -0
  228. package/src/components/indicator/index.ts +4 -0
  229. package/src/components/replay/ReplayController.css +97 -0
  230. package/src/components/replay/ReplayController.tsx +138 -0
  231. package/src/components/timebar/TimeBarModule.tsx +30 -0
  232. package/src/components/timebar/TimeRangeSelector.tsx +96 -0
  233. package/src/components/timebar/index.ts +3 -0
  234. package/src/components/toolbar/GlobalToolbar.tsx +58 -0
  235. package/src/components/toolbar/KlineTypeSelector.tsx +123 -0
  236. package/src/components/toolbar/LayoutSwitcher.tsx +45 -0
  237. package/src/components/toolbar/PeriodSelector.tsx +35 -0
  238. package/src/components/toolbar/QLToolbar.tsx +71 -0
  239. package/src/components/toolbar/TimeRangeSelector.tsx +89 -0
  240. package/src/components/ui/Modal.tsx +67 -0
  241. package/src/core/ChartManager.ts +95 -0
  242. package/src/core/DataManager.ts +427 -0
  243. package/src/core/EventManager.ts +63 -0
  244. package/src/core/IndicatorDataProcessor.ts +104 -0
  245. package/src/core/PaneManager.ts +121 -0
  246. package/src/core/RealtimeDataFeed.ts +110 -0
  247. package/src/core/SeriesManager.ts +210 -0
  248. package/src/core/ThemeManager.ts +59 -0
  249. package/src/core/index.ts +10 -0
  250. package/src/css.d.ts +4 -0
  251. package/src/hooks/useChart.ts +62 -0
  252. package/src/hooks/useCrosshairSync.ts +109 -0
  253. package/src/hooks/useDrawingModule.ts +475 -0
  254. package/src/hooks/useTheme.ts +31 -0
  255. package/src/index.ts +170 -0
  256. package/src/mock/MockDataService.ts +102 -0
  257. package/src/mock/MockIndicatorService.ts +40 -0
  258. package/src/mock/index.ts +5 -0
  259. package/src/mock/presets.ts +16 -0
  260. package/src/plugins/drawing/DrawingAdapter.ts +1762 -0
  261. package/src/plugins/drawing/DrawingPersistence.ts +273 -0
  262. package/src/plugins/drawing/DrawingPropertyTemplates.ts +327 -0
  263. package/src/plugins/drawing/DrawingSharedService.ts +125 -0
  264. package/src/plugins/drawing/DrawingToolRegistry.ts +684 -0
  265. package/src/plugins/drawing/TextLabelOverlay.ts +101 -0
  266. package/src/plugins/drawing/colorUtils.ts +53 -0
  267. package/src/plugins/drawing/index.ts +10 -0
  268. package/src/plugins/drawing/lineStyleMap.ts +46 -0
  269. package/src/plugins/drawing/migration.ts +105 -0
  270. package/src/plugins/drawing/patterns/PatternDefinitions.ts +57 -0
  271. package/src/plugins/drawing/patterns/index.ts +2 -0
  272. package/src/plugins/drawing/periodUtils.ts +51 -0
  273. package/src/plugins/indicators/AutoIndicatorRenderer.ts +204 -0
  274. package/src/plugins/indicators/IndicatorRenderer.ts +350 -0
  275. package/src/plugins/indicators/OverlayIndicator.ts +114 -0
  276. package/src/plugins/indicators/PaneIndicator.ts +137 -0
  277. package/src/plugins/indicators/index.ts +4 -0
  278. package/src/plugins/replay/KlineReplay.ts +163 -0
  279. package/src/plugins/replay/index.ts +2 -0
  280. package/src/plugins/screenshot/ScreenshotUtil.ts +123 -0
  281. package/src/plugins/screenshot/index.ts +1 -0
  282. package/src/plugins/series/HollowCandlestickSeries.ts +111 -0
  283. package/src/plugins/series/RenkoSeries.ts +104 -0
  284. package/src/plugins/series/VolumeCandlestickSeries.ts +127 -0
  285. package/src/plugins/series/index.ts +6 -0
  286. package/src/standalone.ts +386 -0
  287. package/src/store/useChartStore.ts +101 -0
  288. package/src/store/useDrawingStore.ts +135 -0
  289. package/src/store/useIndicatorStore.ts +100 -0
  290. package/src/store/usePanelRegistry.ts +50 -0
  291. package/src/store/useReplayStore.ts +42 -0
  292. package/src/store/useTimeBarStore.ts +34 -0
  293. package/src/styles/chart.css +312 -0
  294. package/src/styles/components.css +184 -0
  295. package/src/styles/context-menu.css +60 -0
  296. package/src/styles/drawing.css +524 -0
  297. package/src/styles/indicator-modal.css +216 -0
  298. package/src/styles/indicator-tag.css +210 -0
  299. package/src/styles/pane-chart.css +9 -0
  300. package/src/styles/responsive.css +71 -0
  301. package/src/styles/themes/dark.css +63 -0
  302. package/src/styles/themes/light.css +61 -0
  303. package/src/styles/toolbar.css +129 -0
  304. package/src/types/api.ts +36 -0
  305. package/src/types/chart.ts +44 -0
  306. package/src/types/drawing.ts +265 -0
  307. package/src/types/index.ts +40 -0
  308. package/src/types/indicator.ts +344 -0
  309. package/src/types/series.ts +53 -0
  310. package/src/types/theme.ts +48 -0
  311. package/src/utils/dataTransformer.ts +63 -0
  312. package/src/utils/heikinAshi.ts +41 -0
  313. package/src/utils/index.ts +3 -0
  314. package/src/utils/lineBreak.ts +88 -0
  315. package/src/utils/themePresets.ts +69 -0
  316. package/src/utils/timeFormatter.ts +29 -0
  317. package/src/utils/timeScaleUtils.ts +68 -0
  318. package/tsconfig.json +21 -0
  319. package/typedoc.json +10 -0
  320. package/vite.config.standalone.ts +31 -0
  321. package/vite.config.ts +24 -0
@@ -0,0 +1,386 @@
1
+ /**
2
+ * QLChart Standalone API
3
+ *
4
+ * 在纯HTML/JS环境中使用,无需React。
5
+ *
6
+ * @example
7
+ * ```html
8
+ * <script src="qlchart.standalone.js"></script>
9
+ * <script>
10
+ * const chart = QLChart.create('container', { theme: 'dark' });
11
+ * chart.setData(klineData);
12
+ * chart.update(realtimeCandle);
13
+ * </script>
14
+ * ```
15
+ */
16
+
17
+ // CSS 内联(打包时自动注入到 <style> 标签)
18
+ import './styles/chart.css';
19
+ import './styles/toolbar.css';
20
+ import './styles/drawing.css';
21
+ import './styles/context-menu.css';
22
+ import './styles/indicator-tag.css';
23
+ import './styles/indicator-modal.css';
24
+ import './styles/themes/dark.css';
25
+ import './styles/themes/light.css';
26
+ import './styles/responsive.css';
27
+ import './styles/pane-chart.css';
28
+ import './styles/components.css';
29
+
30
+ // 核心依赖
31
+ import {
32
+ createChart,
33
+ CandlestickSeries,
34
+ HistogramSeries,
35
+ LineSeries,
36
+ AreaSeries,
37
+ BarSeries,
38
+ type IChartApi,
39
+ type ISeriesApi,
40
+ type SeriesType as LWCSeriesType,
41
+ type UTCTimestamp,
42
+ } from 'lightweight-charts';
43
+
44
+ // 工具函数
45
+ import { transformCandlestickData, transformVolumeData } from './utils/dataTransformer.js';
46
+ import { generateFutureWhitespace, getPeriodInterval } from './utils/timeScaleUtils.js';
47
+ import { darkPreset, lightPreset } from './utils/themePresets.js';
48
+ import { SeriesType } from './types/index.js';
49
+ import type { CandlestickRawData } from './types/index.js';
50
+ import { RealtimeDataFeed, type RealtimeCandle } from './core/RealtimeDataFeed.js';
51
+ import { DrawingAdapter } from './plugins/drawing/DrawingAdapter.js';
52
+ import type { DrawingToolType, DrawingPersistData } from './types/index.js';
53
+ import type { CandlestickData } from 'lightweight-charts';
54
+ import {
55
+ DRAWING_TOOLS,
56
+ CATEGORY_LABELS,
57
+ getToolsByCategory,
58
+ } from './plugins/drawing/DrawingToolRegistry.js';
59
+
60
+ // ── 类型定义 ──
61
+
62
+ export interface StandaloneChartOptions {
63
+ width?: number | string;
64
+ height?: number | string;
65
+ theme?: 'dark' | 'light';
66
+ seriesType?: 'candlestick' | 'line' | 'area' | 'bar';
67
+ showVolume?: boolean;
68
+ enableDrawing?: boolean;
69
+ visibleBars?: number;
70
+ /** 初始周期,默认 '1h' */
71
+ period?: string;
72
+ /** 周期切换时的数据加载回调 */
73
+ onDataReload?: (period: string) => void;
74
+ }
75
+
76
+ /**
77
+ * Standalone绘图工具API
78
+ * 仅在 enableDrawing: true 时可用
79
+ */
80
+ export interface StandaloneDrawingApi {
81
+ /** 设置当前绘图工具 */
82
+ setDrawingTool(tool: DrawingToolType): void;
83
+ /** 获取当前工具 */
84
+ getDrawingTool(): string | null;
85
+ /** 清空所有绘图 */
86
+ clearDrawings(): void;
87
+ /** 获取所有绘图数据(持久化) */
88
+ exportDrawings(): DrawingPersistData[];
89
+ /** 导入绘图数据(恢复) */
90
+ importDrawings(data: DrawingPersistData[]): void;
91
+ /** 设置K线数据(磁铁吸附用) */
92
+ setCandleData(data: CandlestickData[]): void;
93
+ /** 销毁绘图模块 */
94
+ destroyDrawing(): void;
95
+ /** 绘图创建事件回调 */
96
+ onCreated(callback: () => void): void;
97
+ /** 绘图修改事件回调 */
98
+ onModified(callback: () => void): void;
99
+ /** 绘图删除事件回调 */
100
+ onRemoved(callback: () => void): void;
101
+ }
102
+
103
+ export interface StandaloneChart {
104
+ setData(data: CandlestickRawData[]): void;
105
+ update(data: RealtimeCandle): void;
106
+ updateBatch(data: RealtimeCandle[]): void;
107
+ getChart(): IChartApi;
108
+ getMainSeries(): ISeriesApi<LWCSeriesType> | null;
109
+ setTheme(theme: 'dark' | 'light'): void;
110
+ screenshot(): string | null;
111
+ destroy(): void;
112
+ /** 绘图API(enableDrawing:true时可用,否则为null) */
113
+ readonly drawing: StandaloneDrawingApi | null;
114
+ /** 切换周期 */
115
+ setPeriod(period: string): void;
116
+ /** 获取当前周期 */
117
+ getPeriod(): string;
118
+ }
119
+
120
+ // ── 辅助常量 ──
121
+
122
+ const SERIES_TYPE_MAP: Record<string, unknown> = {
123
+ candlestick: CandlestickSeries,
124
+ line: LineSeries,
125
+ area: AreaSeries,
126
+ bar: BarSeries,
127
+ };
128
+
129
+ // ── 工厂函数 ──
130
+
131
+ export function create(
132
+ container: HTMLElement | string,
133
+ options: StandaloneChartOptions = {},
134
+ ): StandaloneChart {
135
+ const el = typeof container === 'string'
136
+ ? document.getElementById(container)
137
+ : container;
138
+ if (!el) throw new Error(`[QLChart] Container not found: ${container}`);
139
+
140
+ const {
141
+ width = '100%',
142
+ height = 400,
143
+ theme = 'dark',
144
+ seriesType = 'candlestick',
145
+ showVolume = true,
146
+ enableDrawing = false,
147
+ period = '1h',
148
+ onDataReload,
149
+ visibleBars = 80,
150
+ } = options;
151
+
152
+ const themePreset = theme === 'dark' ? darkPreset : lightPreset;
153
+
154
+ // ★ 修复:应用完整 themePreset.chart(含 grid/crosshair)
155
+ const chart = createChart(el, {
156
+ ...themePreset.chart,
157
+ width: typeof width === 'number' ? width : undefined,
158
+ height: typeof height === 'number' ? height : undefined,
159
+ autoSize: typeof width === 'string' || typeof height === 'string',
160
+ });
161
+
162
+ if (typeof width === 'string' && width.includes('%')) {
163
+ el.style.width = width;
164
+ }
165
+ if (typeof height === 'string' && height.includes('%')) {
166
+ el.style.height = height;
167
+ }
168
+
169
+ // 创建主序列
170
+ const seriesDef = SERIES_TYPE_MAP[seriesType] ?? SERIES_TYPE_MAP.candlestick;
171
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
172
+ const mainSeries = chart.addSeries(seriesDef as any, {
173
+ upColor: themePreset.upColor ?? '#26a69a',
174
+ downColor: themePreset.downColor ?? '#ef5350',
175
+ borderUpColor: themePreset.upColor ?? '#26a69a',
176
+ borderDownColor: themePreset.downColor ?? '#ef5350',
177
+ wickUpColor: themePreset.upColor ?? '#26a69a',
178
+ wickDownColor: themePreset.downColor ?? '#ef5350',
179
+ });
180
+
181
+ // 成交量序列
182
+ let volumeSeries: ISeriesApi<LWCSeriesType> | null = null;
183
+ if (showVolume) {
184
+ volumeSeries = chart.addSeries(HistogramSeries, {
185
+ priceFormat: { type: 'volume' },
186
+ priceScaleId: 'volume',
187
+ color: 'rgba(38, 166, 154, 0.35)',
188
+ });
189
+ chart.priceScale('volume').applyOptions({
190
+ scaleMargins: { top: 0.8, bottom: 0 },
191
+ });
192
+ }
193
+
194
+ // 实时数据馈送
195
+ const realtimeFeed = new RealtimeDataFeed();
196
+ realtimeFeed.attach(mainSeries, volumeSeries);
197
+
198
+ // ── period 内部状态 ──
199
+ let currentPeriod = period;
200
+
201
+ // ── 绘图模块初始化 ──
202
+ let drawingAdapter: DrawingAdapter | null = null;
203
+ let drawingApi: StandaloneDrawingApi | null = null;
204
+
205
+ if (enableDrawing) {
206
+ drawingAdapter = new DrawingAdapter();
207
+ drawingAdapter.attach(chart, mainSeries, el);
208
+
209
+ // ★ V3新增:事件回调转发
210
+ let createdCb: (() => void) | null = null;
211
+ let modifiedCb: (() => void) | null = null;
212
+ let removedCb: (() => void) | null = null;
213
+
214
+ drawingAdapter.onDrawingCreated(() => createdCb?.());
215
+ drawingAdapter.onDrawingModified(() => modifiedCb?.());
216
+ drawingAdapter.onDrawingRemoved(() => removedCb?.());
217
+
218
+ drawingApi = {
219
+ setDrawingTool(tool: DrawingToolType) {
220
+ drawingAdapter!.setActiveTool(tool);
221
+ },
222
+ getDrawingTool() {
223
+ return drawingAdapter!.getActiveTool();
224
+ },
225
+ clearDrawings() {
226
+ drawingAdapter!.clearAll();
227
+ },
228
+ exportDrawings() {
229
+ return drawingAdapter!.exportDrawings();
230
+ },
231
+ importDrawings(data: DrawingPersistData[]) {
232
+ drawingAdapter!.importDrawings(data);
233
+ },
234
+ setCandleData(data: CandlestickData[]) {
235
+ drawingAdapter!.setCandleData(data);
236
+ },
237
+ destroyDrawing() {
238
+ drawingAdapter?.dispose();
239
+ drawingAdapter = null;
240
+ drawingApi = null;
241
+ },
242
+ onCreated(callback: () => void) { createdCb = callback; },
243
+ onModified(callback: () => void) { modifiedCb = callback; },
244
+ onRemoved(callback: () => void) { removedCb = callback; },
245
+ };
246
+ }
247
+
248
+ return {
249
+ setData(data: CandlestickRawData[]) {
250
+ const candlestickData = transformCandlestickData(data);
251
+ const volumeData = transformVolumeData(data);
252
+
253
+ if (candlestickData.length > 0) {
254
+ const lastTime = candlestickData[candlestickData.length - 1].time as number;
255
+ // ★ 修复:使用 currentPeriod 替代硬编码 '1h'
256
+ const futureWhitespace = generateFutureWhitespace(lastTime, currentPeriod, 100);
257
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
258
+ mainSeries.setData([...candlestickData, ...futureWhitespace] as any);
259
+ }
260
+
261
+ if (volumeSeries && volumeData.length > 0) {
262
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
263
+ volumeSeries.setData(volumeData as any);
264
+ }
265
+
266
+ // 同步K线数据到绘图模块(磁铁吸附用)
267
+ drawingAdapter?.setCandleData(candlestickData as CandlestickData[]);
268
+ // 同步period给绘图模块(测量器标签用)
269
+ drawingAdapter?.setPeriod(currentPeriod);
270
+
271
+ const total = candlestickData.length;
272
+ chart.timeScale().setVisibleLogicalRange({
273
+ from: Math.max(0, total - visibleBars),
274
+ to: total + 15,
275
+ });
276
+ },
277
+
278
+ update(data: RealtimeCandle) {
279
+ realtimeFeed.push(data);
280
+ },
281
+
282
+ updateBatch(datas: RealtimeCandle[]) {
283
+ realtimeFeed.pushBatch(datas);
284
+ },
285
+
286
+ getChart() {
287
+ return chart;
288
+ },
289
+
290
+ getMainSeries() {
291
+ return mainSeries;
292
+ },
293
+
294
+ setTheme(newTheme: 'dark' | 'light') {
295
+ const preset = newTheme === 'dark' ? darkPreset : lightPreset;
296
+ // ★ 修复:应用完整 preset.chart(含 grid/crosshair)
297
+ chart.applyOptions({
298
+ ...preset.chart,
299
+ });
300
+ mainSeries.applyOptions({
301
+ upColor: preset.upColor ?? '#26a69a',
302
+ downColor: preset.downColor ?? '#ef5350',
303
+ });
304
+ // ★ 同步 data-theme 属性(CSS变量联动)
305
+ el.setAttribute('data-theme', newTheme);
306
+ },
307
+
308
+ screenshot(): string | null {
309
+ try {
310
+ return chart.takeScreenshot().toDataURL('image/png');
311
+ } catch {
312
+ return null;
313
+ }
314
+ },
315
+
316
+ get drawing() {
317
+ return drawingApi;
318
+ },
319
+
320
+ setPeriod(newPeriod: string) {
321
+ currentPeriod = newPeriod;
322
+ drawingAdapter?.setPeriod(newPeriod);
323
+ if (onDataReload) {
324
+ onDataReload(newPeriod);
325
+ }
326
+ },
327
+
328
+ getPeriod() {
329
+ return currentPeriod;
330
+ },
331
+
332
+ destroy() {
333
+ drawingAdapter?.dispose();
334
+ drawingAdapter = null;
335
+ drawingApi = null;
336
+ realtimeFeed.detach();
337
+ chart.remove();
338
+ },
339
+ };
340
+ }
341
+
342
+ // ── Mock 数据生成 ──
343
+
344
+ export function generateMockData(
345
+ count = 500,
346
+ startPrice = 42000,
347
+ period: string = '1h',
348
+ ): CandlestickRawData[] {
349
+ const intervalMs = getPeriodInterval(period) * 1000; // 秒→毫秒
350
+ const now = Date.now();
351
+ const result: CandlestickRawData[] = [];
352
+ let prevClose = startPrice;
353
+
354
+ // 根据周期调整波动幅度(更大周期 = 更大波动)
355
+ const volatilityMultiplier = Math.sqrt(intervalMs / 3_600_000); // 相对于1h的倍数
356
+
357
+ for (let i = 0; i < count; i++) {
358
+ const time = now - (count - i) * intervalMs;
359
+ const change = (Math.random() - 0.48) * prevClose * 0.02 * volatilityMultiplier;
360
+ const open = prevClose;
361
+ const close = open + change;
362
+ const high = Math.max(open, close) * (1 + Math.random() * 0.01);
363
+ const low = Math.min(open, close) * (1 - Math.random() * 0.01);
364
+ const volume = Math.floor(500 + Math.random() * 4500 * volatilityMultiplier);
365
+ result.push({ time, open, high, low, close, volume });
366
+ prevClose = close;
367
+ }
368
+ return result;
369
+ }
370
+
371
+ // ── 绘图工具注册表导出 ──
372
+
373
+ export const drawingTools = DRAWING_TOOLS;
374
+ export const drawingCategories = CATEGORY_LABELS;
375
+ export function getDrawingToolsByCategory() {
376
+ return getToolsByCategory();
377
+ }
378
+
379
+ // 导出全局命名空间
380
+ export default {
381
+ create,
382
+ generateMockData,
383
+ drawingTools: DRAWING_TOOLS,
384
+ drawingCategories: CATEGORY_LABELS,
385
+ getDrawingToolsByCategory,
386
+ };
@@ -0,0 +1,101 @@
1
+ import { create } from 'zustand';
2
+ import type { LayoutMode, PanelConfig } from '../types/index.js';
3
+ import { SeriesType } from '../types/index.js';
4
+
5
+ export interface ChartState {
6
+ activePairId: string | null;
7
+ activeProduct: string | null;
8
+ activePeriod: string;
9
+ activeSeriesType: SeriesType;
10
+ activeTheme: 'dark' | 'light';
11
+ layoutMode: LayoutMode;
12
+ panels: PanelConfig[];
13
+ /** 当前活跃面板 ID(全局工具栏操作的目标) */
14
+ activePanelId: string | null;
15
+
16
+ /** 每个面板的独立周期状态:panelId → period */
17
+ panelPeriods: Record<string, string>;
18
+
19
+ setPair: (pairId: string, product: string) => void;
20
+ setPeriod: (period: string) => void;
21
+ setSeriesType: (type: SeriesType) => void;
22
+ setTheme: (theme: 'dark' | 'light') => void;
23
+ setLayoutMode: (mode: LayoutMode) => void;
24
+ updatePanel: (index: number, config: Partial<PanelConfig>) => void;
25
+ /** 设置活跃面板 */
26
+ setActivePanel: (panelId: string) => void;
27
+
28
+ /** 设置当前活跃面板的周期(多面板写入panelPeriods,单面板fallback全局) */
29
+ setActivePanelPeriod: (period: string) => void;
30
+ /** 设置指定面板的周期 */
31
+ setPanelPeriod: (panelId: string, period: string) => void;
32
+ }
33
+
34
+ // ── 独立 Selector 函数(避免内联函数导致不必要的重渲染) ──
35
+
36
+ /** 获取指定面板的周期(面板级 fallback 全局) */
37
+ export const selectPanelPeriod = (panelId?: string) =>
38
+ (s: ChartState): string =>
39
+ panelId ? (s.panelPeriods[panelId] ?? s.activePeriod) : s.activePeriod;
40
+
41
+ /** 获取活跃面板的周期(用于 GlobalToolbar 高亮) */
42
+ export const selectActivePanelPeriod = (s: ChartState): string =>
43
+ s.activePanelId
44
+ ? (s.panelPeriods[s.activePanelId] ?? s.activePeriod)
45
+ : s.activePeriod;
46
+
47
+ export const useChartStore = create<ChartState>((set) => ({
48
+ activePairId: null,
49
+ activeProduct: null,
50
+ activePeriod: '1h',
51
+ activeSeriesType: SeriesType.Candlestick,
52
+ activeTheme: 'dark',
53
+ layoutMode: '1' as LayoutMode,
54
+ panels: [],
55
+ activePanelId: null,
56
+ panelPeriods: {},
57
+
58
+ setPair: (pairId, product) =>
59
+ set({ activePairId: pairId, activeProduct: product }),
60
+
61
+ setPeriod: (period) => set({ activePeriod: period }),
62
+
63
+ setSeriesType: (type) => set({ activeSeriesType: type }),
64
+
65
+ setTheme: (theme) => set({ activeTheme: theme }),
66
+
67
+ setLayoutMode: (mode) => set({ layoutMode: mode }),
68
+
69
+ updatePanel: (index, config) =>
70
+ set((state) => {
71
+ const panels = [...state.panels];
72
+ if (panels[index]) {
73
+ panels[index] = { ...panels[index], ...config };
74
+ }
75
+ return { panels };
76
+ }),
77
+
78
+ setActivePanel: (panelId) => set({ activePanelId: panelId }),
79
+
80
+ /**
81
+ * 设置当前活跃面板的周期
82
+ * - 有 activePanelId:写入 panelPeriods[activePanelId]
83
+ * - 无 activePanelId:fallback 到全局 activePeriod(单面板兼容)
84
+ * - 同时更新 activePeriod(保证 GlobalToolbar 高亮正确)
85
+ */
86
+ setActivePanelPeriod: (period) => set((state) => {
87
+ const panelId = state.activePanelId;
88
+ if (!panelId) {
89
+ return { activePeriod: period };
90
+ }
91
+ return {
92
+ panelPeriods: { ...state.panelPeriods, [panelId]: period },
93
+ activePeriod: period,
94
+ };
95
+ }),
96
+
97
+ /** 设置指定面板的周期 */
98
+ setPanelPeriod: (panelId, period) => set((state) => ({
99
+ panelPeriods: { ...state.panelPeriods, [panelId]: period },
100
+ })),
101
+ }));
@@ -0,0 +1,135 @@
1
+ import { create } from 'zustand';
2
+ import type { DrawingToolType, DrawingStyleConfig, DrawingToolConfig } from '../types/index.js';
3
+ import type { IDrawing } from 'lightweight-charts-drawing';
4
+ import { DrawingToolCategory } from '../types/index.js';
5
+
6
+ export interface DrawingState {
7
+ /** 当前激活的绘图工具 */
8
+ activeTool: DrawingToolType;
9
+ /** 绘图数量(用于显示 badge) */
10
+ drawingCount: number;
11
+ /** 当前选中的绘图 ID */
12
+ selectedDrawingId: string | null;
13
+ /** 当前选中的绘图类型 */
14
+ selectedDrawingType: string | null;
15
+ /** 磁铁吸附开关 */
16
+ magnetEnabled: boolean;
17
+ /** 是否正在绘图 */
18
+ isDrawing: boolean;
19
+ /** 显示属性面板 */
20
+ showPropertyPanel: boolean;
21
+ /** 属性面板是否被双击锁定打开 */
22
+ isPropertyPanelPinned: boolean;
23
+ /** 工具栏方向 */
24
+ toolbarOrientation: 'vertical' | 'horizontal';
25
+ /** 工具栏自定义位置 */
26
+ toolbarPosition: { x: number; y: number } | null;
27
+ /** 工具栏是否正在拖拽 */
28
+ isToolbarDragging: boolean;
29
+ /** 选中绘图的样式快照(用于属性面板编辑) */
30
+ selectedStyle: DrawingStyleConfig | null;
31
+ /** 绘图工具栏是否展开 */
32
+ drawingToolbarOpen: boolean;
33
+ /** 每分类的展开状态 */
34
+ expandedCategory: DrawingToolCategory | null;
35
+ /** 每分类当前选中的工具(用于显示分类行的 icon) */
36
+ categoryActiveTools: Partial<Record<DrawingToolCategory, DrawingToolType>>;
37
+ /** ★ V2: 当前绘图目标 pane index(0 = 主图) */
38
+ currentPaneIndex: number;
39
+
40
+ // Actions
41
+ setActiveTool: (tool: DrawingToolType) => void;
42
+ setDrawingCount: (count: number) => void;
43
+ selectDrawing: (id: string | null, style?: DrawingStyleConfig | null, type?: string | null) => void;
44
+ setMagnetEnabled: (enabled: boolean) => void;
45
+ setIsDrawing: (drawing: boolean) => void;
46
+ setShowPropertyPanel: (show: boolean) => void;
47
+ setIsPropertyPanelPinned: (pinned: boolean) => void;
48
+ setToolbarOrientation: (o: 'vertical' | 'horizontal') => void;
49
+ setToolbarPosition: (pos: { x: number; y: number } | null) => void;
50
+ setIsToolbarDragging: (dragging: boolean) => void;
51
+ setSelectedStyle: (style: DrawingStyleConfig | null) => void;
52
+ setDrawingToolbarOpen: (open: boolean) => void;
53
+ /** 设置展开的分类 */
54
+ setExpandedCategory: (category: DrawingToolCategory | null) => void;
55
+ /** 设置分类当前工具 */
56
+ setCategoryActiveTool: (category: DrawingToolCategory, tool: DrawingToolType) => void;
57
+ /** ★ V2: 设置当前 pane index */
58
+ setCurrentPaneIndex: (index: number) => void;
59
+ clearAll: () => void;
60
+ }
61
+
62
+ export const useDrawingStore = create<DrawingState>((set, get) => ({
63
+ activeTool: 'cursor',
64
+ drawingCount: 0,
65
+ selectedDrawingId: null,
66
+ selectedDrawingType: null,
67
+ magnetEnabled: true,
68
+ isDrawing: false,
69
+ showPropertyPanel: false,
70
+ isPropertyPanelPinned: false,
71
+ toolbarOrientation: 'vertical',
72
+ toolbarPosition: null,
73
+ isToolbarDragging: false,
74
+ selectedStyle: null,
75
+ drawingToolbarOpen: true,
76
+ expandedCategory: null,
77
+ categoryActiveTools: {},
78
+ currentPaneIndex: 0,
79
+
80
+ setActiveTool: (tool) =>
81
+ set({ activeTool: tool }),
82
+
83
+ setDrawingCount: (count) =>
84
+ set({ drawingCount: count }),
85
+
86
+ selectDrawing: (id, style, type) =>
87
+ set({
88
+ selectedDrawingId: id,
89
+ selectedDrawingType: type ?? null,
90
+ showPropertyPanel: id !== null ? (get().isPropertyPanelPinned ?? false) : false,
91
+ selectedStyle: style ?? null,
92
+ }),
93
+
94
+ setMagnetEnabled: (enabled) =>
95
+ set({ magnetEnabled: enabled }),
96
+
97
+ setIsDrawing: (drawing) =>
98
+ set({ isDrawing: drawing }),
99
+
100
+ setShowPropertyPanel: (show) =>
101
+ set({ showPropertyPanel: show }),
102
+
103
+ setIsPropertyPanelPinned: (pinned) => set({ isPropertyPanelPinned: pinned }),
104
+ setToolbarOrientation: (o) => set({ toolbarOrientation: o }),
105
+ setToolbarPosition: (pos) => set({ toolbarPosition: pos }),
106
+ setIsToolbarDragging: (dragging) => set({ isToolbarDragging: dragging }),
107
+
108
+ setSelectedStyle: (style) =>
109
+ set({ selectedStyle: style }),
110
+
111
+ setDrawingToolbarOpen: (open) =>
112
+ set({ drawingToolbarOpen: open }),
113
+
114
+ setExpandedCategory: (category) => set({ expandedCategory: category }),
115
+
116
+ setCategoryActiveTool: (category, tool) =>
117
+ set((state) => ({
118
+ categoryActiveTools: { ...state.categoryActiveTools, [category]: tool },
119
+ })),
120
+
121
+ setCurrentPaneIndex: (index) => set({ currentPaneIndex: index }),
122
+
123
+ clearAll: () =>
124
+ set({
125
+ activeTool: 'cursor',
126
+ drawingCount: 0,
127
+ selectedDrawingId: null,
128
+ selectedDrawingType: null,
129
+ isDrawing: false,
130
+ showPropertyPanel: false,
131
+ isPropertyPanelPinned: false,
132
+ selectedStyle: null,
133
+ currentPaneIndex: 0,
134
+ }),
135
+ }));