@363045841yyt/klinechart-core 0.7.3 → 0.7.5-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (231) hide show
  1. package/README.md +201 -201
  2. package/README.zh-CN.md +201 -201
  3. package/dist/engine/renderers/webgl/candleSurface.js +47 -47
  4. package/dist/version.d.ts +1 -1
  5. package/dist/version.d.ts.map +1 -1
  6. package/dist/version.js +1 -2
  7. package/dist/version.js.map +1 -1
  8. package/package.json +129 -122
  9. package/src/__tests__/signal.test.ts +124 -124
  10. package/src/config/chartSettings.ts +66 -66
  11. package/src/controllers/__tests__/drawing.test.ts +214 -214
  12. package/src/controllers/__tests__/indicatorSelector.test.ts +481 -481
  13. package/src/controllers/__tests__/toolbar.test.ts +225 -225
  14. package/src/controllers/createChartController.ts +665 -665
  15. package/src/controllers/createDrawingController.ts +96 -96
  16. package/src/controllers/createIndicatorSelectorController.ts +307 -307
  17. package/src/controllers/createToolbarController.ts +146 -146
  18. package/src/controllers/index.ts +19 -19
  19. package/src/controllers/types.ts +284 -284
  20. package/src/engine/__tests__/chart.dpr.test.ts +401 -401
  21. package/src/engine/__tests__/paneRenderer.resize.test.ts +92 -92
  22. package/src/engine/chart-store.ts +121 -121
  23. package/src/engine/chart.d.ts +617 -617
  24. package/src/engine/chart.ts +2815 -2815
  25. package/src/engine/controller/__tests__/interaction.dpr.test.ts +259 -259
  26. package/src/engine/controller/interaction.ts +722 -722
  27. package/src/engine/controller/markerInteraction.ts +130 -130
  28. package/src/engine/controller/pinchTracker.ts +82 -82
  29. package/src/engine/controller/tooltipPosition.ts +48 -48
  30. package/src/engine/draw/__tests__/pixelAlign.spec.ts +176 -176
  31. package/src/engine/draw/pixelAlign.ts +259 -259
  32. package/src/engine/drawing/index.ts +655 -655
  33. package/src/engine/drawing/interaction.ts +842 -842
  34. package/src/engine/drawing/plugin.ts +343 -343
  35. package/src/engine/indicators/__tests__/__fixtures__/golden/atr.json +38 -38
  36. package/src/engine/indicators/__tests__/__fixtures__/golden/dema.json +14 -14
  37. package/src/engine/indicators/__tests__/__fixtures__/golden/hma.json +14 -14
  38. package/src/engine/indicators/__tests__/__fixtures__/golden/index.ts +55 -55
  39. package/src/engine/indicators/__tests__/__fixtures__/golden/kama.json +14 -14
  40. package/src/engine/indicators/__tests__/__fixtures__/golden/tema.json +14 -14
  41. package/src/engine/indicators/__tests__/__fixtures__/golden/wma.json +40 -40
  42. package/src/engine/indicators/__tests__/__fixtures__/synthetic.ts +65 -65
  43. package/src/engine/indicators/__tests__/_propertyAssertions.ts +76 -76
  44. package/src/engine/indicators/__tests__/atr.test.ts +153 -153
  45. package/src/engine/indicators/__tests__/calculators.test.ts +614 -614
  46. package/src/engine/indicators/__tests__/cmf-mfi.test.ts +100 -100
  47. package/src/engine/indicators/__tests__/dema.test.ts +73 -73
  48. package/src/engine/indicators/__tests__/donchian.test.ts +70 -70
  49. package/src/engine/indicators/__tests__/hma.test.ts +73 -73
  50. package/src/engine/indicators/__tests__/ichimoku.test.ts +105 -105
  51. package/src/engine/indicators/__tests__/kama.test.ts +80 -80
  52. package/src/engine/indicators/__tests__/keltner.test.ts +65 -65
  53. package/src/engine/indicators/__tests__/pivot-fib.test.ts +110 -110
  54. package/src/engine/indicators/__tests__/roc.test.ts +68 -68
  55. package/src/engine/indicators/__tests__/sar.test.ts +86 -86
  56. package/src/engine/indicators/__tests__/scheduler.test.ts +831 -831
  57. package/src/engine/indicators/__tests__/soa.test.ts +533 -533
  58. package/src/engine/indicators/__tests__/structure.test.ts +110 -110
  59. package/src/engine/indicators/__tests__/supertrend.test.ts +65 -65
  60. package/src/engine/indicators/__tests__/tema.test.ts +68 -68
  61. package/src/engine/indicators/__tests__/trix.test.ts +70 -70
  62. package/src/engine/indicators/__tests__/volatility.test.ts +117 -117
  63. package/src/engine/indicators/__tests__/volume.test.ts +115 -115
  64. package/src/engine/indicators/__tests__/volumeProfile.test.ts +74 -74
  65. package/src/engine/indicators/__tests__/vwap.test.ts +69 -69
  66. package/src/engine/indicators/__tests__/wma.test.ts +112 -112
  67. package/src/engine/indicators/__tests__/zones.test.ts +95 -95
  68. package/src/engine/indicators/atrState.ts +27 -27
  69. package/src/engine/indicators/bollState.ts +51 -51
  70. package/src/engine/indicators/calculators.ts +2593 -2593
  71. package/src/engine/indicators/cciState.ts +25 -25
  72. package/src/engine/indicators/chaikinVolState.ts +32 -32
  73. package/src/engine/indicators/cmfState.ts +27 -27
  74. package/src/engine/indicators/demaState.ts +27 -27
  75. package/src/engine/indicators/donchianState.ts +43 -43
  76. package/src/engine/indicators/eneState.ts +43 -43
  77. package/src/engine/indicators/expmaState.ts +43 -43
  78. package/src/engine/indicators/fastkState.ts +25 -25
  79. package/src/engine/indicators/fibState.ts +41 -41
  80. package/src/engine/indicators/hmaState.ts +27 -27
  81. package/src/engine/indicators/hvState.ts +28 -28
  82. package/src/engine/indicators/ichimokuState.ts +70 -70
  83. package/src/engine/indicators/indicator.worker.ts +169 -169
  84. package/src/engine/indicators/indicatorDefinitionRegistry.ts +62 -62
  85. package/src/engine/indicators/indicatorMetadata.ts +110 -110
  86. package/src/engine/indicators/indicatorRegistry.ts +106 -106
  87. package/src/engine/indicators/indicatorRuntime.ts +1548 -1548
  88. package/src/engine/indicators/kamaState.ts +34 -34
  89. package/src/engine/indicators/keltnerState.ts +49 -49
  90. package/src/engine/indicators/kstState.ts +42 -42
  91. package/src/engine/indicators/maState.ts +36 -36
  92. package/src/engine/indicators/macdState.ts +76 -76
  93. package/src/engine/indicators/mfiState.ts +27 -27
  94. package/src/engine/indicators/momState.ts +25 -25
  95. package/src/engine/indicators/obvState.ts +25 -25
  96. package/src/engine/indicators/parkinsonState.ts +28 -28
  97. package/src/engine/indicators/pivotState.ts +51 -51
  98. package/src/engine/indicators/pvtState.ts +25 -25
  99. package/src/engine/indicators/rocState.ts +27 -27
  100. package/src/engine/indicators/rsiState.ts +65 -65
  101. package/src/engine/indicators/sarState.ts +41 -41
  102. package/src/engine/indicators/scheduler.ts +1205 -1205
  103. package/src/engine/indicators/soa.ts +352 -352
  104. package/src/engine/indicators/stateComposer.ts +1262 -1262
  105. package/src/engine/indicators/stochState.ts +26 -26
  106. package/src/engine/indicators/structureState.ts +69 -69
  107. package/src/engine/indicators/supertrendState.ts +37 -37
  108. package/src/engine/indicators/temaState.ts +27 -27
  109. package/src/engine/indicators/trixState.ts +35 -35
  110. package/src/engine/indicators/vmaState.ts +27 -27
  111. package/src/engine/indicators/volumeProfileState.ts +63 -63
  112. package/src/engine/indicators/vwapState.ts +29 -29
  113. package/src/engine/indicators/wmaState.ts +27 -27
  114. package/src/engine/indicators/wmsrState.ts +25 -25
  115. package/src/engine/indicators/workerProtocol.ts +613 -613
  116. package/src/engine/indicators/zonesState.ts +47 -47
  117. package/src/engine/layout/pane.ts +161 -161
  118. package/src/engine/marker/registry.ts +265 -265
  119. package/src/engine/paneRenderer.ts +169 -169
  120. package/src/engine/renderers/Indicator/atr.ts +237 -237
  121. package/src/engine/renderers/Indicator/boll.ts +317 -317
  122. package/src/engine/renderers/Indicator/cci.ts +275 -275
  123. package/src/engine/renderers/Indicator/chaikinVol.ts +138 -138
  124. package/src/engine/renderers/Indicator/cmf.ts +137 -137
  125. package/src/engine/renderers/Indicator/dema.ts +136 -136
  126. package/src/engine/renderers/Indicator/donchian.ts +137 -137
  127. package/src/engine/renderers/Indicator/ene.ts +271 -271
  128. package/src/engine/renderers/Indicator/expma.ts +197 -197
  129. package/src/engine/renderers/Indicator/fastk.ts +316 -316
  130. package/src/engine/renderers/Indicator/fib.ts +141 -141
  131. package/src/engine/renderers/Indicator/hma.ts +136 -136
  132. package/src/engine/renderers/Indicator/hv.ts +124 -124
  133. package/src/engine/renderers/Indicator/ichimoku.ts +181 -181
  134. package/src/engine/renderers/Indicator/index.ts +241 -241
  135. package/src/engine/renderers/Indicator/indicatorData.ts +650 -650
  136. package/src/engine/renderers/Indicator/kama.ts +136 -136
  137. package/src/engine/renderers/Indicator/keltner.ts +137 -137
  138. package/src/engine/renderers/Indicator/kst.ts +302 -302
  139. package/src/engine/renderers/Indicator/ma.ts +200 -200
  140. package/src/engine/renderers/Indicator/macd.ts +477 -477
  141. package/src/engine/renderers/Indicator/macdLegend.ts +141 -141
  142. package/src/engine/renderers/Indicator/mainIndicatorLegend.ts +272 -272
  143. package/src/engine/renderers/Indicator/mfi.ts +142 -142
  144. package/src/engine/renderers/Indicator/mom.ts +311 -311
  145. package/src/engine/renderers/Indicator/obv.ts +123 -123
  146. package/src/engine/renderers/Indicator/parkinson.ts +124 -124
  147. package/src/engine/renderers/Indicator/pivot.ts +131 -131
  148. package/src/engine/renderers/Indicator/pvt.ts +123 -123
  149. package/src/engine/renderers/Indicator/roc.ts +143 -143
  150. package/src/engine/renderers/Indicator/rsi.ts +390 -390
  151. package/src/engine/renderers/Indicator/sar.ts +113 -113
  152. package/src/engine/renderers/Indicator/scale/atr_scale.ts +19 -19
  153. package/src/engine/renderers/Indicator/scale/cci_scale.ts +19 -19
  154. package/src/engine/renderers/Indicator/scale/fastk_scale.ts +19 -19
  155. package/src/engine/renderers/Indicator/scale/indicator_scale.ts +204 -204
  156. package/src/engine/renderers/Indicator/scale/kst_scale.ts +19 -19
  157. package/src/engine/renderers/Indicator/scale/macd_scale.ts +22 -22
  158. package/src/engine/renderers/Indicator/scale/mom_scale.ts +19 -19
  159. package/src/engine/renderers/Indicator/scale/rsi_scale.ts +19 -19
  160. package/src/engine/renderers/Indicator/scale/stoch_scale.ts +19 -19
  161. package/src/engine/renderers/Indicator/scale/volume_scale.ts +26 -26
  162. package/src/engine/renderers/Indicator/scale/wmsr_scale.ts +19 -19
  163. package/src/engine/renderers/Indicator/stoch.ts +359 -359
  164. package/src/engine/renderers/Indicator/structure.ts +126 -126
  165. package/src/engine/renderers/Indicator/subPaneConfig.ts +265 -265
  166. package/src/engine/renderers/Indicator/supertrend.ts +115 -115
  167. package/src/engine/renderers/Indicator/tema.ts +136 -136
  168. package/src/engine/renderers/Indicator/trix.ts +158 -158
  169. package/src/engine/renderers/Indicator/vma.ts +124 -124
  170. package/src/engine/renderers/Indicator/volumeProfile.ts +125 -125
  171. package/src/engine/renderers/Indicator/vwap.ts +123 -123
  172. package/src/engine/renderers/Indicator/wma.ts +136 -136
  173. package/src/engine/renderers/Indicator/wmsr.ts +328 -328
  174. package/src/engine/renderers/Indicator/zones.ts +104 -104
  175. package/src/engine/renderers/__tests__/boll.renderer.test.ts +314 -314
  176. package/src/engine/renderers/__tests__/ene.renderer.test.ts +305 -305
  177. package/src/engine/renderers/__tests__/expma.renderer.test.ts +279 -279
  178. package/src/engine/renderers/__tests__/ma.renderer.test.ts +426 -426
  179. package/src/engine/renderers/__tests__/mainIndicatorLegend.renderer.test.ts +502 -502
  180. package/src/engine/renderers/__tests__/yAxis.renderer.test.ts +173 -173
  181. package/src/engine/renderers/candle.ts +459 -459
  182. package/src/engine/renderers/crosshair.ts +69 -69
  183. package/src/engine/renderers/customMarkers.ts +162 -162
  184. package/src/engine/renderers/extremaMarkers.ts +246 -246
  185. package/src/engine/renderers/gridLines.ts +90 -90
  186. package/src/engine/renderers/lastPrice.ts +97 -97
  187. package/src/engine/renderers/paneTitle.ts +136 -136
  188. package/src/engine/renderers/subVolume.ts +236 -236
  189. package/src/engine/renderers/timeAxis.ts +121 -121
  190. package/src/engine/renderers/webgl/candleSurface.ts +955 -955
  191. package/src/engine/renderers/webgl/sharedWebGLSurface.ts +146 -146
  192. package/src/engine/renderers/yAxis.ts +105 -105
  193. package/src/engine/scale/__tests__/logFormula.spec.ts +148 -148
  194. package/src/engine/scale/logFormula.ts +130 -130
  195. package/src/engine/scale/price.ts +39 -39
  196. package/src/engine/scale/priceScale.ts +264 -264
  197. package/src/engine/subPaneManager.ts +427 -427
  198. package/src/engine/theme/colors.ts +642 -642
  199. package/src/engine/theme/fonts.ts +20 -20
  200. package/src/engine/utils/klineConfig.ts +49 -49
  201. package/src/engine/utils/tickCount.ts +11 -11
  202. package/src/engine/utils/tickPosition.ts +214 -214
  203. package/src/engine/utils/zoom.ts +83 -83
  204. package/src/engine/viewport/viewport.ts +67 -67
  205. package/src/index.ts +3 -3
  206. package/src/plugin/ConfigManager.ts +93 -93
  207. package/src/plugin/EventBus.ts +77 -77
  208. package/src/plugin/HookSystem.ts +106 -106
  209. package/src/plugin/PluginHost.ts +243 -243
  210. package/src/plugin/PluginRegistry.ts +92 -92
  211. package/src/plugin/StateStore.ts +73 -73
  212. package/src/plugin/index.ts +19 -19
  213. package/src/plugin/rendererPluginManager.ts +368 -368
  214. package/src/plugin/stateKeys.ts +8 -8
  215. package/src/plugin/types.ts +526 -526
  216. package/src/reactivity/index.ts +2 -2
  217. package/src/reactivity/signal.ts +119 -119
  218. package/src/semantic/controller.ts +251 -251
  219. package/src/semantic/drawShape.ts +260 -260
  220. package/src/semantic/index.ts +28 -28
  221. package/src/semantic/schema.json +256 -256
  222. package/src/semantic/types.ts +251 -251
  223. package/src/semantic/validator.ts +349 -349
  224. package/src/types/kLine.ts +13 -13
  225. package/src/types/price.ts +56 -56
  226. package/src/types/volumePrice.ts +33 -33
  227. package/src/utils/dateFormat.ts +208 -208
  228. package/src/utils/kLineDraw/axis.ts +562 -562
  229. package/src/utils/priceToY.ts +34 -34
  230. package/src/utils/volumePrice.ts +202 -202
  231. package/src/version.ts +1 -1
@@ -1,83 +1,83 @@
1
- import { getPhysicalKLineConfig } from './klineConfig'
2
-
3
- /**
4
- * 缩放计算纯函数
5
- * 无副作用、无 DOM 访问,供 Vue 层直接调用
6
- */
7
-
8
- export interface ZoomConfig {
9
- minKWidth: number
10
- maxKWidth: number
11
- zoomLevelCount: number
12
- dpr: number
13
- }
14
-
15
- export interface ZoomResult {
16
- targetLevel: number
17
- newKWidth: number
18
- newKGap: number
19
- newScrollLeft: number
20
- }
21
-
22
- const PHYS_K_GAP_MAX = 3
23
-
24
- /** 将缩放级别转换为 K 线宽度(逻辑像素) */
25
- export function zoomLevelToKWidth(level: number, config: ZoomConfig): number {
26
- const t = (level - 1) / (config.zoomLevelCount - 1)
27
- return config.minKWidth + t * (config.maxKWidth - config.minKWidth)
28
- }
29
-
30
- /** 根据K线宽度和DPR推导间隙(逻辑像素),K线越窄间距越小 */
31
- export function kGapFromKWidth(kWidth: number, dpr: number): number {
32
- const kWidthPx = Math.round(kWidth * dpr)
33
- const kGapPx = Math.max(1, Math.min(PHYS_K_GAP_MAX, Math.round(kWidthPx * 0.6)))
34
- return kGapPx / dpr
35
- }
36
-
37
- /**
38
- * 缩放一级(+1 放大 / -1 缩小)
39
- * 返回新状态或 null(已达边界)
40
- */
41
- export function computeZoom(
42
- delta: number,
43
- mouseX: number,
44
- scrollLeft: number,
45
- currentLevel: number,
46
- currentKWidth: number,
47
- currentKGap: number,
48
- config: ZoomConfig,
49
- ): ZoomResult | null {
50
- const targetLevel = Math.max(1, Math.min(config.zoomLevelCount, currentLevel + delta))
51
- if (targetLevel === currentLevel) return null
52
-
53
- const newKWidth = zoomLevelToKWidth(targetLevel, config)
54
- const newKGap = kGapFromKWidth(newKWidth, config.dpr)
55
-
56
- const oldConfig = getPhysicalKLineConfig(currentKWidth, currentKGap, config.dpr)
57
- const newConfig = getPhysicalKLineConfig(newKWidth, newKGap, config.dpr)
58
- const anchorWorldPx = Math.round((scrollLeft + mouseX) * config.dpr)
59
- const anchorSlotFloat = (anchorWorldPx - oldConfig.startXPx) / oldConfig.unitPx
60
- const newAnchorWorldPx = newConfig.startXPx + anchorSlotFloat * newConfig.unitPx
61
- const newScrollLeft = newAnchorWorldPx / config.dpr - mouseX
62
-
63
- return { targetLevel, newKWidth, newKGap, newScrollLeft }
64
- }
65
-
66
- /**
67
- * 缩放到指定级别
68
- * 返回新状态或 null(级别不变或无效)
69
- */
70
- export function computeZoomToLevel(
71
- targetLevel: number,
72
- anchorX: number,
73
- scrollLeft: number,
74
- currentLevel: number,
75
- currentKWidth: number,
76
- currentKGap: number,
77
- config: ZoomConfig,
78
- ): ZoomResult | null {
79
- const clamped = Math.max(1, Math.min(config.zoomLevelCount, Math.round(targetLevel)))
80
- const delta = clamped - currentLevel
81
- if (delta === 0) return null
82
- return computeZoom(delta, anchorX, scrollLeft, currentLevel, currentKWidth, currentKGap, config)
83
- }
1
+ import { getPhysicalKLineConfig } from './klineConfig'
2
+
3
+ /**
4
+ * 缩放计算纯函数
5
+ * 无副作用、无 DOM 访问,供 Vue 层直接调用
6
+ */
7
+
8
+ export interface ZoomConfig {
9
+ minKWidth: number
10
+ maxKWidth: number
11
+ zoomLevelCount: number
12
+ dpr: number
13
+ }
14
+
15
+ export interface ZoomResult {
16
+ targetLevel: number
17
+ newKWidth: number
18
+ newKGap: number
19
+ newScrollLeft: number
20
+ }
21
+
22
+ const PHYS_K_GAP_MAX = 3
23
+
24
+ /** 将缩放级别转换为 K 线宽度(逻辑像素) */
25
+ export function zoomLevelToKWidth(level: number, config: ZoomConfig): number {
26
+ const t = (level - 1) / (config.zoomLevelCount - 1)
27
+ return config.minKWidth + t * (config.maxKWidth - config.minKWidth)
28
+ }
29
+
30
+ /** 根据K线宽度和DPR推导间隙(逻辑像素),K线越窄间距越小 */
31
+ export function kGapFromKWidth(kWidth: number, dpr: number): number {
32
+ const kWidthPx = Math.round(kWidth * dpr)
33
+ const kGapPx = Math.max(1, Math.min(PHYS_K_GAP_MAX, Math.round(kWidthPx * 0.6)))
34
+ return kGapPx / dpr
35
+ }
36
+
37
+ /**
38
+ * 缩放一级(+1 放大 / -1 缩小)
39
+ * 返回新状态或 null(已达边界)
40
+ */
41
+ export function computeZoom(
42
+ delta: number,
43
+ mouseX: number,
44
+ scrollLeft: number,
45
+ currentLevel: number,
46
+ currentKWidth: number,
47
+ currentKGap: number,
48
+ config: ZoomConfig,
49
+ ): ZoomResult | null {
50
+ const targetLevel = Math.max(1, Math.min(config.zoomLevelCount, currentLevel + delta))
51
+ if (targetLevel === currentLevel) return null
52
+
53
+ const newKWidth = zoomLevelToKWidth(targetLevel, config)
54
+ const newKGap = kGapFromKWidth(newKWidth, config.dpr)
55
+
56
+ const oldConfig = getPhysicalKLineConfig(currentKWidth, currentKGap, config.dpr)
57
+ const newConfig = getPhysicalKLineConfig(newKWidth, newKGap, config.dpr)
58
+ const anchorWorldPx = Math.round((scrollLeft + mouseX) * config.dpr)
59
+ const anchorSlotFloat = (anchorWorldPx - oldConfig.startXPx) / oldConfig.unitPx
60
+ const newAnchorWorldPx = newConfig.startXPx + anchorSlotFloat * newConfig.unitPx
61
+ const newScrollLeft = newAnchorWorldPx / config.dpr - mouseX
62
+
63
+ return { targetLevel, newKWidth, newKGap, newScrollLeft }
64
+ }
65
+
66
+ /**
67
+ * 缩放到指定级别
68
+ * 返回新状态或 null(级别不变或无效)
69
+ */
70
+ export function computeZoomToLevel(
71
+ targetLevel: number,
72
+ anchorX: number,
73
+ scrollLeft: number,
74
+ currentLevel: number,
75
+ currentKWidth: number,
76
+ currentKGap: number,
77
+ config: ZoomConfig,
78
+ ): ZoomResult | null {
79
+ const clamped = Math.max(1, Math.min(config.zoomLevelCount, Math.round(targetLevel)))
80
+ const delta = clamped - currentLevel
81
+ if (delta === 0) return null
82
+ return computeZoom(delta, anchorX, scrollLeft, currentLevel, currentKWidth, currentKGap, config)
83
+ }
@@ -1,67 +1,67 @@
1
- import type { KLineData } from '../../types/price'
2
- import type { PriceRange } from '../scale/price'
3
- import { getPhysicalKLineConfig } from '../utils/klineConfig'
4
-
5
- /**
6
- * 计算当前视口可见的 K 线索引范围(使用物理像素对齐)。
7
- *
8
- * - 所有计算在物理像素空间进行,确保与 calcKLinePositions 一致
9
- * - 会额外在左右各扩展 1 根(start-1/end+1),用于避免边缘裁剪带来的”断线/缺一根”观感
10
- *
11
- * @param scrollLeft 容器当前横向滚动量(逻辑像素)
12
- * @param viewWidth 绘图区域宽度(plotWidth,逻辑像素,不含右侧 yAxis)
13
- * @param kWidth 单根 K 线宽度(逻辑像素)
14
- * @param kGap K 线间距(逻辑像素)
15
- * @param totalDataCount 数据总条数
16
- * @param dpr 设备像素比
17
- */
18
- export function getVisibleRange(
19
- scrollLeft: number,
20
- viewWidth: number,
21
- kWidth: number,
22
- kGap: number,
23
- totalDataCount: number,
24
- dpr: number = 1
25
- ): { start: number; end: number } {
26
- // 使用统一的物理像素配置,确保与 calcKLinePositions 完全一致
27
- const { unitPx, startXPx } = getPhysicalKLineConfig(kWidth, kGap, dpr)
28
-
29
- // scrollLeft 和 viewWidth 转换到物理像素空间
30
- const scrollLeftPx = scrollLeft * dpr
31
- const viewWidthPx = viewWidth * dpr
32
-
33
- // 计算可见范围(物理像素空间整数运算)
34
- const start = Math.max(0, Math.floor((scrollLeftPx - startXPx) / unitPx) - 1)
35
- const end = Math.min(totalDataCount, Math.ceil((scrollLeftPx + viewWidthPx - startXPx) / unitPx) + 1)
36
-
37
- return { start, end }
38
- }
39
-
40
- /**
41
- * 计算指定索引区间内的价格范围(max/min)。
42
- *
43
- * 主要用途:
44
- * - 为 pane 的 y 轴缩放与刻度提供 priceRange
45
- * - 为渲染器(网格线、极值标注等)提供可视区参考范围
46
- *
47
- * 注意:
48
- * - `endIndex` 为开区间(不包含)
49
- * - 若区间内无有效数据,会返回兜底范围 `{ maxPrice: 100, minPrice: 0 }`
50
- */
51
- export function getVisiblePriceRange(data: KLineData[], startIndex: number, endIndex: number): PriceRange {
52
- let maxPrice = -Infinity
53
- let minPrice = Infinity
54
-
55
- for (let i = startIndex; i < endIndex && i < data.length; i++) {
56
- const e = data[i]
57
- if (!e) continue
58
- if (e.high > maxPrice) maxPrice = e.high
59
- if (e.low < minPrice) minPrice = e.low
60
- }
61
-
62
- if (!Number.isFinite(maxPrice) || !Number.isFinite(minPrice)) {
63
- return { maxPrice: 100, minPrice: 0 }
64
- }
65
-
66
- return { maxPrice, minPrice }
67
- }
1
+ import type { KLineData } from '../../types/price'
2
+ import type { PriceRange } from '../scale/price'
3
+ import { getPhysicalKLineConfig } from '../utils/klineConfig'
4
+
5
+ /**
6
+ * 计算当前视口可见的 K 线索引范围(使用物理像素对齐)。
7
+ *
8
+ * - 所有计算在物理像素空间进行,确保与 calcKLinePositions 一致
9
+ * - 会额外在左右各扩展 1 根(start-1/end+1),用于避免边缘裁剪带来的”断线/缺一根”观感
10
+ *
11
+ * @param scrollLeft 容器当前横向滚动量(逻辑像素)
12
+ * @param viewWidth 绘图区域宽度(plotWidth,逻辑像素,不含右侧 yAxis)
13
+ * @param kWidth 单根 K 线宽度(逻辑像素)
14
+ * @param kGap K 线间距(逻辑像素)
15
+ * @param totalDataCount 数据总条数
16
+ * @param dpr 设备像素比
17
+ */
18
+ export function getVisibleRange(
19
+ scrollLeft: number,
20
+ viewWidth: number,
21
+ kWidth: number,
22
+ kGap: number,
23
+ totalDataCount: number,
24
+ dpr: number = 1
25
+ ): { start: number; end: number } {
26
+ // 使用统一的物理像素配置,确保与 calcKLinePositions 完全一致
27
+ const { unitPx, startXPx } = getPhysicalKLineConfig(kWidth, kGap, dpr)
28
+
29
+ // scrollLeft 和 viewWidth 转换到物理像素空间
30
+ const scrollLeftPx = scrollLeft * dpr
31
+ const viewWidthPx = viewWidth * dpr
32
+
33
+ // 计算可见范围(物理像素空间整数运算)
34
+ const start = Math.max(0, Math.floor((scrollLeftPx - startXPx) / unitPx) - 1)
35
+ const end = Math.min(totalDataCount, Math.ceil((scrollLeftPx + viewWidthPx - startXPx) / unitPx) + 1)
36
+
37
+ return { start, end }
38
+ }
39
+
40
+ /**
41
+ * 计算指定索引区间内的价格范围(max/min)。
42
+ *
43
+ * 主要用途:
44
+ * - 为 pane 的 y 轴缩放与刻度提供 priceRange
45
+ * - 为渲染器(网格线、极值标注等)提供可视区参考范围
46
+ *
47
+ * 注意:
48
+ * - `endIndex` 为开区间(不包含)
49
+ * - 若区间内无有效数据,会返回兜底范围 `{ maxPrice: 100, minPrice: 0 }`
50
+ */
51
+ export function getVisiblePriceRange(data: KLineData[], startIndex: number, endIndex: number): PriceRange {
52
+ let maxPrice = -Infinity
53
+ let minPrice = Infinity
54
+
55
+ for (let i = startIndex; i < endIndex && i < data.length; i++) {
56
+ const e = data[i]
57
+ if (!e) continue
58
+ if (e.high > maxPrice) maxPrice = e.high
59
+ if (e.low < minPrice) minPrice = e.low
60
+ }
61
+
62
+ if (!Number.isFinite(maxPrice) || !Number.isFinite(minPrice)) {
63
+ return { maxPrice: 100, minPrice: 0 }
64
+ }
65
+
66
+ return { maxPrice, minPrice }
67
+ }
package/src/index.ts CHANGED
@@ -1,3 +1,3 @@
1
- export * from './reactivity'
2
- export * from './controllers'
3
- export { VERSION } from './version'
1
+ export * from './reactivity'
2
+ export * from './controllers'
3
+ export { VERSION } from './version'
@@ -1,93 +1,93 @@
1
- /**
2
- * 配置管理器
3
- */
4
-
5
- type ConfigStore = Map<string, Map<string, unknown>>
6
-
7
- export class ConfigManager {
8
- private configs: ConfigStore = new Map()
9
- private defaults: Map<string, Record<string, unknown>> = new Map()
10
-
11
- /**
12
- * 注册插件的默认配置
13
- */
14
- registerDefaults(pluginName: string, defaults: Record<string, unknown>): void {
15
- this.defaults.set(pluginName, { ...defaults })
16
-
17
- // 初始化配置
18
- if (!this.configs.has(pluginName)) {
19
- this.configs.set(pluginName, new Map())
20
- }
21
-
22
- // 应用默认值
23
- const config = this.configs.get(pluginName)!
24
- for (const [key, value] of Object.entries(defaults)) {
25
- if (!config.has(key)) {
26
- config.set(key, value)
27
- }
28
- }
29
- }
30
-
31
- /**
32
- * 获取配置
33
- */
34
- get<K = unknown>(pluginName: string, key: string, defaultValue?: K): K {
35
- const pluginConfig = this.configs.get(pluginName)
36
- if (pluginConfig?.has(key)) {
37
- return pluginConfig.get(key) as K
38
- }
39
-
40
- // 尝试默认值
41
- const defaults = this.defaults.get(pluginName)
42
- if (defaults && key in defaults) {
43
- return defaults[key] as K
44
- }
45
-
46
- return defaultValue as K
47
- }
48
-
49
- /**
50
- * 设置配置
51
- */
52
- set(pluginName: string, key: string, value: unknown): void {
53
- if (!this.configs.has(pluginName)) {
54
- this.configs.set(pluginName, new Map())
55
- }
56
- this.configs.get(pluginName)!.set(key, value)
57
- }
58
-
59
- /**
60
- * 批量设置配置
61
- */
62
- setAll(pluginName: string, config: Record<string, unknown>): void {
63
- for (const [key, value] of Object.entries(config)) {
64
- this.set(pluginName, key, value)
65
- }
66
- }
67
-
68
- /**
69
- * 获取插件所有配置
70
- */
71
- getAll(pluginName: string): Record<string, unknown> {
72
- const config = this.configs.get(pluginName)
73
- const defaults = this.defaults.get(pluginName) || {}
74
-
75
- return {
76
- ...defaults,
77
- ...(config ? Object.fromEntries(config) : {}),
78
- }
79
- }
80
-
81
- /**
82
- * 清除插件配置
83
- */
84
- clear(pluginName?: string): void {
85
- if (pluginName) {
86
- this.configs.delete(pluginName)
87
- this.defaults.delete(pluginName)
88
- } else {
89
- this.configs.clear()
90
- this.defaults.clear()
91
- }
92
- }
93
- }
1
+ /**
2
+ * 配置管理器
3
+ */
4
+
5
+ type ConfigStore = Map<string, Map<string, unknown>>
6
+
7
+ export class ConfigManager {
8
+ private configs: ConfigStore = new Map()
9
+ private defaults: Map<string, Record<string, unknown>> = new Map()
10
+
11
+ /**
12
+ * 注册插件的默认配置
13
+ */
14
+ registerDefaults(pluginName: string, defaults: Record<string, unknown>): void {
15
+ this.defaults.set(pluginName, { ...defaults })
16
+
17
+ // 初始化配置
18
+ if (!this.configs.has(pluginName)) {
19
+ this.configs.set(pluginName, new Map())
20
+ }
21
+
22
+ // 应用默认值
23
+ const config = this.configs.get(pluginName)!
24
+ for (const [key, value] of Object.entries(defaults)) {
25
+ if (!config.has(key)) {
26
+ config.set(key, value)
27
+ }
28
+ }
29
+ }
30
+
31
+ /**
32
+ * 获取配置
33
+ */
34
+ get<K = unknown>(pluginName: string, key: string, defaultValue?: K): K {
35
+ const pluginConfig = this.configs.get(pluginName)
36
+ if (pluginConfig?.has(key)) {
37
+ return pluginConfig.get(key) as K
38
+ }
39
+
40
+ // 尝试默认值
41
+ const defaults = this.defaults.get(pluginName)
42
+ if (defaults && key in defaults) {
43
+ return defaults[key] as K
44
+ }
45
+
46
+ return defaultValue as K
47
+ }
48
+
49
+ /**
50
+ * 设置配置
51
+ */
52
+ set(pluginName: string, key: string, value: unknown): void {
53
+ if (!this.configs.has(pluginName)) {
54
+ this.configs.set(pluginName, new Map())
55
+ }
56
+ this.configs.get(pluginName)!.set(key, value)
57
+ }
58
+
59
+ /**
60
+ * 批量设置配置
61
+ */
62
+ setAll(pluginName: string, config: Record<string, unknown>): void {
63
+ for (const [key, value] of Object.entries(config)) {
64
+ this.set(pluginName, key, value)
65
+ }
66
+ }
67
+
68
+ /**
69
+ * 获取插件所有配置
70
+ */
71
+ getAll(pluginName: string): Record<string, unknown> {
72
+ const config = this.configs.get(pluginName)
73
+ const defaults = this.defaults.get(pluginName) || {}
74
+
75
+ return {
76
+ ...defaults,
77
+ ...(config ? Object.fromEntries(config) : {}),
78
+ }
79
+ }
80
+
81
+ /**
82
+ * 清除插件配置
83
+ */
84
+ clear(pluginName?: string): void {
85
+ if (pluginName) {
86
+ this.configs.delete(pluginName)
87
+ this.defaults.delete(pluginName)
88
+ } else {
89
+ this.configs.clear()
90
+ this.defaults.clear()
91
+ }
92
+ }
93
+ }
@@ -1,77 +1,77 @@
1
- /**
2
- * 事件总线实现
3
- */
4
- import type { EventHandler } from './types'
5
-
6
- type EventMap = Map<string, Set<EventHandler>>
7
-
8
- export class EventBus {
9
- private listeners: EventMap = new Map()
10
-
11
- /**
12
- * 订阅事件
13
- */
14
- on<T = unknown>(event: string, handler: EventHandler<T>): void {
15
- if (!this.listeners.has(event)) {
16
- this.listeners.set(event, new Set())
17
- }
18
- this.listeners.get(event)!.add(handler as EventHandler)
19
- }
20
-
21
- /**
22
- * 取消订阅
23
- */
24
- off<T = unknown>(event: string, handler: EventHandler<T>): void {
25
- const handlers = this.listeners.get(event)
26
- if (handlers) {
27
- handlers.delete(handler as EventHandler)
28
- }
29
- }
30
-
31
- /**
32
- * 发布事件
33
- */
34
- emit<T = unknown>(event: string, data: T): void {
35
- const handlers = this.listeners.get(event)
36
- if (handlers) {
37
- handlers.forEach((handler) => {
38
- try {
39
- handler(data)
40
- } catch (error) {
41
- console.error(`[EventBus] Error in handler for "${event}":`, error)
42
- }
43
- })
44
- }
45
- }
46
-
47
- /**
48
- * 订阅一次性事件
49
- *
50
- * 注册一个仅在事件首次触发时执行的回调。回调执行后会自动从监听队列中移除,
51
- * 确保后续相同事件的 emit 不会再触发该逻辑。
52
- *
53
- * @param event - 事件名称
54
- * @param handler - 待执行的回调函数
55
- */
56
- once<T = unknown>(event: string, handler: EventHandler<T>): void {
57
- const wrapper: EventHandler<T> = (data) => {
58
- this.off(event, wrapper)
59
- handler(data)
60
- }
61
- this.on(event, wrapper)
62
- }
63
-
64
- /**
65
- * 清除所有事件监听
66
- */
67
- clear(): void {
68
- this.listeners.clear()
69
- }
70
-
71
- /**
72
- * 获取事件的监听器数量
73
- */
74
- listenerCount(event: string): number {
75
- return this.listeners.get(event)?.size ?? 0
76
- }
77
- }
1
+ /**
2
+ * 事件总线实现
3
+ */
4
+ import type { EventHandler } from './types'
5
+
6
+ type EventMap = Map<string, Set<EventHandler>>
7
+
8
+ export class EventBus {
9
+ private listeners: EventMap = new Map()
10
+
11
+ /**
12
+ * 订阅事件
13
+ */
14
+ on<T = unknown>(event: string, handler: EventHandler<T>): void {
15
+ if (!this.listeners.has(event)) {
16
+ this.listeners.set(event, new Set())
17
+ }
18
+ this.listeners.get(event)!.add(handler as EventHandler)
19
+ }
20
+
21
+ /**
22
+ * 取消订阅
23
+ */
24
+ off<T = unknown>(event: string, handler: EventHandler<T>): void {
25
+ const handlers = this.listeners.get(event)
26
+ if (handlers) {
27
+ handlers.delete(handler as EventHandler)
28
+ }
29
+ }
30
+
31
+ /**
32
+ * 发布事件
33
+ */
34
+ emit<T = unknown>(event: string, data: T): void {
35
+ const handlers = this.listeners.get(event)
36
+ if (handlers) {
37
+ handlers.forEach((handler) => {
38
+ try {
39
+ handler(data)
40
+ } catch (error) {
41
+ console.error(`[EventBus] Error in handler for "${event}":`, error)
42
+ }
43
+ })
44
+ }
45
+ }
46
+
47
+ /**
48
+ * 订阅一次性事件
49
+ *
50
+ * 注册一个仅在事件首次触发时执行的回调。回调执行后会自动从监听队列中移除,
51
+ * 确保后续相同事件的 emit 不会再触发该逻辑。
52
+ *
53
+ * @param event - 事件名称
54
+ * @param handler - 待执行的回调函数
55
+ */
56
+ once<T = unknown>(event: string, handler: EventHandler<T>): void {
57
+ const wrapper: EventHandler<T> = (data) => {
58
+ this.off(event, wrapper)
59
+ handler(data)
60
+ }
61
+ this.on(event, wrapper)
62
+ }
63
+
64
+ /**
65
+ * 清除所有事件监听
66
+ */
67
+ clear(): void {
68
+ this.listeners.clear()
69
+ }
70
+
71
+ /**
72
+ * 获取事件的监听器数量
73
+ */
74
+ listenerCount(event: string): number {
75
+ return this.listeners.get(event)?.size ?? 0
76
+ }
77
+ }