@363045841yyt/klinechart-core 0.7.3 → 0.7.5

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 (247) hide show
  1. package/README.md +201 -201
  2. package/README.zh-CN.md +201 -201
  3. package/dist/controllers/index.d.ts +1 -0
  4. package/dist/controllers/index.d.ts.map +1 -1
  5. package/dist/controllers/index.js +1 -0
  6. package/dist/controllers/index.js.map +1 -1
  7. package/dist/engine/chart.d.ts +11 -19
  8. package/dist/engine/chart.d.ts.map +1 -1
  9. package/dist/engine/chart.js +92 -109
  10. package/dist/engine/chart.js.map +1 -1
  11. package/dist/engine/renderers/Indicator/indicatorData.d.ts +1 -0
  12. package/dist/engine/renderers/Indicator/indicatorData.d.ts.map +1 -1
  13. package/dist/engine/renderers/Indicator/indicatorData.js +1 -1
  14. package/dist/engine/renderers/Indicator/indicatorData.js.map +1 -1
  15. package/dist/engine/renderers/webgl/candleSurface.js +47 -47
  16. package/dist/engine/subPaneManager.d.ts +4 -0
  17. package/dist/engine/subPaneManager.d.ts.map +1 -1
  18. package/dist/engine/subPaneManager.js +13 -0
  19. package/dist/engine/subPaneManager.js.map +1 -1
  20. package/dist/version.d.ts +1 -1
  21. package/dist/version.d.ts.map +1 -1
  22. package/dist/version.js +1 -2
  23. package/dist/version.js.map +1 -1
  24. package/package.json +129 -122
  25. package/src/__tests__/signal.test.ts +124 -124
  26. package/src/config/chartSettings.ts +66 -66
  27. package/src/controllers/__tests__/drawing.test.ts +214 -214
  28. package/src/controllers/__tests__/indicatorSelector.test.ts +481 -481
  29. package/src/controllers/__tests__/toolbar.test.ts +225 -225
  30. package/src/controllers/createChartController.ts +665 -665
  31. package/src/controllers/createDrawingController.ts +96 -96
  32. package/src/controllers/createIndicatorSelectorController.ts +307 -307
  33. package/src/controllers/createToolbarController.ts +146 -146
  34. package/src/controllers/index.ts +20 -19
  35. package/src/controllers/types.ts +284 -284
  36. package/src/engine/__tests__/chart.dpr.test.ts +401 -401
  37. package/src/engine/__tests__/paneRenderer.resize.test.ts +92 -92
  38. package/src/engine/chart-store.ts +121 -121
  39. package/src/engine/chart.d.ts +617 -617
  40. package/src/engine/chart.ts +2803 -2815
  41. package/src/engine/controller/__tests__/interaction.dpr.test.ts +259 -259
  42. package/src/engine/controller/interaction.ts +722 -722
  43. package/src/engine/controller/markerInteraction.ts +130 -130
  44. package/src/engine/controller/pinchTracker.ts +82 -82
  45. package/src/engine/controller/tooltipPosition.ts +48 -48
  46. package/src/engine/draw/__tests__/pixelAlign.spec.ts +176 -176
  47. package/src/engine/draw/pixelAlign.ts +259 -259
  48. package/src/engine/drawing/index.ts +655 -655
  49. package/src/engine/drawing/interaction.ts +842 -842
  50. package/src/engine/drawing/plugin.ts +343 -343
  51. package/src/engine/indicators/__tests__/__fixtures__/golden/atr.json +38 -38
  52. package/src/engine/indicators/__tests__/__fixtures__/golden/dema.json +14 -14
  53. package/src/engine/indicators/__tests__/__fixtures__/golden/hma.json +14 -14
  54. package/src/engine/indicators/__tests__/__fixtures__/golden/index.ts +55 -55
  55. package/src/engine/indicators/__tests__/__fixtures__/golden/kama.json +14 -14
  56. package/src/engine/indicators/__tests__/__fixtures__/golden/tema.json +14 -14
  57. package/src/engine/indicators/__tests__/__fixtures__/golden/wma.json +40 -40
  58. package/src/engine/indicators/__tests__/__fixtures__/synthetic.ts +65 -65
  59. package/src/engine/indicators/__tests__/_propertyAssertions.ts +76 -76
  60. package/src/engine/indicators/__tests__/atr.test.ts +153 -153
  61. package/src/engine/indicators/__tests__/calculators.test.ts +614 -614
  62. package/src/engine/indicators/__tests__/cmf-mfi.test.ts +100 -100
  63. package/src/engine/indicators/__tests__/dema.test.ts +73 -73
  64. package/src/engine/indicators/__tests__/donchian.test.ts +70 -70
  65. package/src/engine/indicators/__tests__/hma.test.ts +73 -73
  66. package/src/engine/indicators/__tests__/ichimoku.test.ts +105 -105
  67. package/src/engine/indicators/__tests__/kama.test.ts +80 -80
  68. package/src/engine/indicators/__tests__/keltner.test.ts +65 -65
  69. package/src/engine/indicators/__tests__/pivot-fib.test.ts +110 -110
  70. package/src/engine/indicators/__tests__/roc.test.ts +68 -68
  71. package/src/engine/indicators/__tests__/sar.test.ts +86 -86
  72. package/src/engine/indicators/__tests__/scheduler.test.ts +831 -831
  73. package/src/engine/indicators/__tests__/soa.test.ts +533 -533
  74. package/src/engine/indicators/__tests__/structure.test.ts +110 -110
  75. package/src/engine/indicators/__tests__/supertrend.test.ts +65 -65
  76. package/src/engine/indicators/__tests__/tema.test.ts +68 -68
  77. package/src/engine/indicators/__tests__/trix.test.ts +70 -70
  78. package/src/engine/indicators/__tests__/volatility.test.ts +117 -117
  79. package/src/engine/indicators/__tests__/volume.test.ts +115 -115
  80. package/src/engine/indicators/__tests__/volumeProfile.test.ts +74 -74
  81. package/src/engine/indicators/__tests__/vwap.test.ts +69 -69
  82. package/src/engine/indicators/__tests__/wma.test.ts +112 -112
  83. package/src/engine/indicators/__tests__/zones.test.ts +95 -95
  84. package/src/engine/indicators/atrState.ts +27 -27
  85. package/src/engine/indicators/bollState.ts +51 -51
  86. package/src/engine/indicators/calculators.ts +2593 -2593
  87. package/src/engine/indicators/cciState.ts +25 -25
  88. package/src/engine/indicators/chaikinVolState.ts +32 -32
  89. package/src/engine/indicators/cmfState.ts +27 -27
  90. package/src/engine/indicators/demaState.ts +27 -27
  91. package/src/engine/indicators/donchianState.ts +43 -43
  92. package/src/engine/indicators/eneState.ts +43 -43
  93. package/src/engine/indicators/expmaState.ts +43 -43
  94. package/src/engine/indicators/fastkState.ts +25 -25
  95. package/src/engine/indicators/fibState.ts +41 -41
  96. package/src/engine/indicators/hmaState.ts +27 -27
  97. package/src/engine/indicators/hvState.ts +28 -28
  98. package/src/engine/indicators/ichimokuState.ts +70 -70
  99. package/src/engine/indicators/indicator.worker.ts +169 -169
  100. package/src/engine/indicators/indicatorDefinitionRegistry.ts +62 -62
  101. package/src/engine/indicators/indicatorMetadata.ts +110 -110
  102. package/src/engine/indicators/indicatorRegistry.ts +106 -106
  103. package/src/engine/indicators/indicatorRuntime.ts +1548 -1548
  104. package/src/engine/indicators/kamaState.ts +34 -34
  105. package/src/engine/indicators/keltnerState.ts +49 -49
  106. package/src/engine/indicators/kstState.ts +42 -42
  107. package/src/engine/indicators/maState.ts +36 -36
  108. package/src/engine/indicators/macdState.ts +76 -76
  109. package/src/engine/indicators/mfiState.ts +27 -27
  110. package/src/engine/indicators/momState.ts +25 -25
  111. package/src/engine/indicators/obvState.ts +25 -25
  112. package/src/engine/indicators/parkinsonState.ts +28 -28
  113. package/src/engine/indicators/pivotState.ts +51 -51
  114. package/src/engine/indicators/pvtState.ts +25 -25
  115. package/src/engine/indicators/rocState.ts +27 -27
  116. package/src/engine/indicators/rsiState.ts +65 -65
  117. package/src/engine/indicators/sarState.ts +41 -41
  118. package/src/engine/indicators/scheduler.ts +1205 -1205
  119. package/src/engine/indicators/soa.ts +352 -352
  120. package/src/engine/indicators/stateComposer.ts +1262 -1262
  121. package/src/engine/indicators/stochState.ts +26 -26
  122. package/src/engine/indicators/structureState.ts +69 -69
  123. package/src/engine/indicators/supertrendState.ts +37 -37
  124. package/src/engine/indicators/temaState.ts +27 -27
  125. package/src/engine/indicators/trixState.ts +35 -35
  126. package/src/engine/indicators/vmaState.ts +27 -27
  127. package/src/engine/indicators/volumeProfileState.ts +63 -63
  128. package/src/engine/indicators/vwapState.ts +29 -29
  129. package/src/engine/indicators/wmaState.ts +27 -27
  130. package/src/engine/indicators/wmsrState.ts +25 -25
  131. package/src/engine/indicators/workerProtocol.ts +613 -613
  132. package/src/engine/indicators/zonesState.ts +47 -47
  133. package/src/engine/layout/pane.ts +161 -161
  134. package/src/engine/marker/registry.ts +265 -265
  135. package/src/engine/paneRenderer.ts +169 -169
  136. package/src/engine/renderers/Indicator/atr.ts +237 -237
  137. package/src/engine/renderers/Indicator/boll.ts +317 -317
  138. package/src/engine/renderers/Indicator/cci.ts +275 -275
  139. package/src/engine/renderers/Indicator/chaikinVol.ts +138 -138
  140. package/src/engine/renderers/Indicator/cmf.ts +137 -137
  141. package/src/engine/renderers/Indicator/dema.ts +136 -136
  142. package/src/engine/renderers/Indicator/donchian.ts +137 -137
  143. package/src/engine/renderers/Indicator/ene.ts +271 -271
  144. package/src/engine/renderers/Indicator/expma.ts +197 -197
  145. package/src/engine/renderers/Indicator/fastk.ts +316 -316
  146. package/src/engine/renderers/Indicator/fib.ts +141 -141
  147. package/src/engine/renderers/Indicator/hma.ts +136 -136
  148. package/src/engine/renderers/Indicator/hv.ts +124 -124
  149. package/src/engine/renderers/Indicator/ichimoku.ts +181 -181
  150. package/src/engine/renderers/Indicator/index.ts +241 -241
  151. package/src/engine/renderers/Indicator/indicatorData.ts +650 -650
  152. package/src/engine/renderers/Indicator/kama.ts +136 -136
  153. package/src/engine/renderers/Indicator/keltner.ts +137 -137
  154. package/src/engine/renderers/Indicator/kst.ts +302 -302
  155. package/src/engine/renderers/Indicator/ma.ts +200 -200
  156. package/src/engine/renderers/Indicator/macd.ts +477 -477
  157. package/src/engine/renderers/Indicator/macdLegend.ts +141 -141
  158. package/src/engine/renderers/Indicator/mainIndicatorLegend.ts +272 -272
  159. package/src/engine/renderers/Indicator/mfi.ts +142 -142
  160. package/src/engine/renderers/Indicator/mom.ts +311 -311
  161. package/src/engine/renderers/Indicator/obv.ts +123 -123
  162. package/src/engine/renderers/Indicator/parkinson.ts +124 -124
  163. package/src/engine/renderers/Indicator/pivot.ts +131 -131
  164. package/src/engine/renderers/Indicator/pvt.ts +123 -123
  165. package/src/engine/renderers/Indicator/roc.ts +143 -143
  166. package/src/engine/renderers/Indicator/rsi.ts +390 -390
  167. package/src/engine/renderers/Indicator/sar.ts +113 -113
  168. package/src/engine/renderers/Indicator/scale/atr_scale.ts +19 -19
  169. package/src/engine/renderers/Indicator/scale/cci_scale.ts +19 -19
  170. package/src/engine/renderers/Indicator/scale/fastk_scale.ts +19 -19
  171. package/src/engine/renderers/Indicator/scale/indicator_scale.ts +204 -204
  172. package/src/engine/renderers/Indicator/scale/kst_scale.ts +19 -19
  173. package/src/engine/renderers/Indicator/scale/macd_scale.ts +22 -22
  174. package/src/engine/renderers/Indicator/scale/mom_scale.ts +19 -19
  175. package/src/engine/renderers/Indicator/scale/rsi_scale.ts +19 -19
  176. package/src/engine/renderers/Indicator/scale/stoch_scale.ts +19 -19
  177. package/src/engine/renderers/Indicator/scale/volume_scale.ts +26 -26
  178. package/src/engine/renderers/Indicator/scale/wmsr_scale.ts +19 -19
  179. package/src/engine/renderers/Indicator/stoch.ts +359 -359
  180. package/src/engine/renderers/Indicator/structure.ts +126 -126
  181. package/src/engine/renderers/Indicator/subPaneConfig.ts +265 -265
  182. package/src/engine/renderers/Indicator/supertrend.ts +115 -115
  183. package/src/engine/renderers/Indicator/tema.ts +136 -136
  184. package/src/engine/renderers/Indicator/trix.ts +158 -158
  185. package/src/engine/renderers/Indicator/vma.ts +124 -124
  186. package/src/engine/renderers/Indicator/volumeProfile.ts +125 -125
  187. package/src/engine/renderers/Indicator/vwap.ts +123 -123
  188. package/src/engine/renderers/Indicator/wma.ts +136 -136
  189. package/src/engine/renderers/Indicator/wmsr.ts +328 -328
  190. package/src/engine/renderers/Indicator/zones.ts +104 -104
  191. package/src/engine/renderers/__tests__/boll.renderer.test.ts +314 -314
  192. package/src/engine/renderers/__tests__/ene.renderer.test.ts +305 -305
  193. package/src/engine/renderers/__tests__/expma.renderer.test.ts +279 -279
  194. package/src/engine/renderers/__tests__/ma.renderer.test.ts +426 -426
  195. package/src/engine/renderers/__tests__/mainIndicatorLegend.renderer.test.ts +502 -502
  196. package/src/engine/renderers/__tests__/yAxis.renderer.test.ts +173 -173
  197. package/src/engine/renderers/candle.ts +459 -459
  198. package/src/engine/renderers/crosshair.ts +69 -69
  199. package/src/engine/renderers/customMarkers.ts +162 -162
  200. package/src/engine/renderers/extremaMarkers.ts +246 -246
  201. package/src/engine/renderers/gridLines.ts +90 -90
  202. package/src/engine/renderers/lastPrice.ts +97 -97
  203. package/src/engine/renderers/paneTitle.ts +136 -136
  204. package/src/engine/renderers/subVolume.ts +236 -236
  205. package/src/engine/renderers/timeAxis.ts +121 -121
  206. package/src/engine/renderers/webgl/candleSurface.ts +955 -955
  207. package/src/engine/renderers/webgl/sharedWebGLSurface.ts +146 -146
  208. package/src/engine/renderers/yAxis.ts +105 -105
  209. package/src/engine/scale/__tests__/logFormula.spec.ts +148 -148
  210. package/src/engine/scale/logFormula.ts +130 -130
  211. package/src/engine/scale/price.ts +39 -39
  212. package/src/engine/scale/priceScale.ts +264 -264
  213. package/src/engine/subPaneManager.ts +442 -427
  214. package/src/engine/theme/colors.ts +642 -642
  215. package/src/engine/theme/fonts.ts +20 -20
  216. package/src/engine/utils/klineConfig.ts +49 -49
  217. package/src/engine/utils/tickCount.ts +11 -11
  218. package/src/engine/utils/tickPosition.ts +214 -214
  219. package/src/engine/utils/zoom.ts +83 -83
  220. package/src/engine/viewport/viewport.ts +67 -67
  221. package/src/index.ts +3 -3
  222. package/src/plugin/ConfigManager.ts +93 -93
  223. package/src/plugin/EventBus.ts +77 -77
  224. package/src/plugin/HookSystem.ts +106 -106
  225. package/src/plugin/PluginHost.ts +243 -243
  226. package/src/plugin/PluginRegistry.ts +92 -92
  227. package/src/plugin/StateStore.ts +73 -73
  228. package/src/plugin/index.ts +19 -19
  229. package/src/plugin/rendererPluginManager.ts +368 -368
  230. package/src/plugin/stateKeys.ts +8 -8
  231. package/src/plugin/types.ts +526 -526
  232. package/src/reactivity/index.ts +2 -2
  233. package/src/reactivity/signal.ts +119 -119
  234. package/src/semantic/controller.ts +251 -251
  235. package/src/semantic/drawShape.ts +260 -260
  236. package/src/semantic/index.ts +28 -28
  237. package/src/semantic/schema.json +256 -256
  238. package/src/semantic/types.ts +251 -251
  239. package/src/semantic/validator.ts +349 -349
  240. package/src/types/kLine.ts +13 -13
  241. package/src/types/price.ts +56 -56
  242. package/src/types/volumePrice.ts +33 -33
  243. package/src/utils/dateFormat.ts +208 -208
  244. package/src/utils/kLineDraw/axis.ts +562 -562
  245. package/src/utils/priceToY.ts +34 -34
  246. package/src/utils/volumePrice.ts +202 -202
  247. package/src/version.ts +1 -1
@@ -1,260 +1,260 @@
1
- /**
2
- * 像素对齐工具函数 - 逻辑像素空间(配合 ctx.scale(dpr) 使用)
3
- */
4
-
5
- import { getColors } from '../theme/colors'
6
-
7
- /**
8
- * 将逻辑坐标对齐到物理像素边界(用于矩形填充)
9
- * @param value - 逻辑坐标值
10
- * @param dpr - 设备像素比
11
- * @returns 对齐后的逻辑坐标
12
- */
13
- export function roundToPhysicalPixel(value: number, dpr: number, theme?: 'light' | 'dark'): number {
14
- return Math.round(value * dpr) / dpr
15
- }
16
-
17
- /**
18
- * 将逻辑坐标对齐到物理像素中心(用于 1px 线条)
19
- * @param value - 逻辑坐标值
20
- * @param dpr - 设备像素比
21
- * @returns 对齐后的逻辑坐标
22
- */
23
- export function alignToPhysicalPixelCenter(value: number, dpr: number, theme?: 'light' | 'dark'): number {
24
- return (Math.floor(value * dpr) + 0.5) / dpr
25
- }
26
-
27
- /**
28
- * 对齐矩形到物理像素边界
29
- * @param x - 矩形左边界 X 坐标
30
- * @param y - 矩形顶部 Y 坐标
31
- * @param width - 矩形宽度
32
- * @param height - 矩形高度
33
- * @param dpr - 设备像素比
34
- * @returns 对齐后的矩形信息
35
- */
36
- export function alignRect(
37
- x: number,
38
- y: number,
39
- width: number,
40
- height: number,
41
- dpr: number,
42
- theme?: 'light' | 'dark'
43
- ): { x: number; y: number; width: number; height: number } {
44
- const alignedX = roundToPhysicalPixel(x, dpr)
45
- const alignedY = roundToPhysicalPixel(y, dpr)
46
- const alignedEndX = roundToPhysicalPixel(x + width, dpr)
47
- const alignedEndY = roundToPhysicalPixel(y + height, dpr)
48
-
49
- return {
50
- x: alignedX,
51
- y: alignedY,
52
- width: Math.max(1 / dpr, alignedEndX - alignedX),
53
- height: Math.max(1 / dpr, alignedEndY - alignedY),
54
- }
55
- }
56
-
57
- /**
58
- * 创建用于绘制垂直线的矩形(1 物理像素宽)
59
- * @param centerX - 垂直线中心 X 坐标
60
- * @param y1 - 垂直线起始点 Y 坐标
61
- * @param y2 - 垂直线结束点 Y 坐标
62
- * @param dpr - 设备像素比
63
- * @returns 对齐到物理像素的矩形信息,如果 y1 和 y2 相等则返回 null
64
- */
65
- export function createVerticalLineRect(
66
- centerX: number,
67
- y1: number,
68
- y2: number,
69
- dpr: number,
70
- theme?: 'light' | 'dark'
71
- ): { x: number; y: number; width: number; height: number } | null {
72
- if (y1 === y2) return null
73
-
74
- const top = Math.min(y1, y2)
75
- const bottom = Math.max(y1, y2)
76
-
77
- // 转换到物理像素空间取整,再转回逻辑像素
78
- const physX = Math.round(centerX * dpr)
79
- const physTop = Math.round(top * dpr)
80
- const physBottom = Math.round(bottom * dpr)
81
-
82
- return {
83
- x: physX / dpr,
84
- y: physTop / dpr,
85
- width: 1 / dpr,
86
- height: Math.max(1, physBottom - physTop) / dpr,
87
- }
88
- }
89
-
90
- /**
91
- * 创建用于绘制水平线的矩形(1 物理像素高)
92
- * @param x1 - 水平线起始点的 X 坐标
93
- * @param x2 - 水平线结束点的 X 坐标
94
- * @param centerY - 水平线中心 Y 坐标
95
- * @param dpr - 设备像素比
96
- * @returns 对齐到物理像素的矩形信息,如果 x1 和 x2 相等则返回 null
97
- */
98
- export function createHorizontalLineRect(
99
- x1: number,
100
- x2: number,
101
- centerY: number,
102
- dpr: number,
103
- theme?: 'light' | 'dark'
104
- ): { x: number; y: number; width: number; height: number } | null {
105
- if (x1 === x2) return null
106
-
107
- const left = Math.min(x1, x2)
108
- const right = Math.max(x1, x2)
109
-
110
- const physLeft = Math.round(left * dpr)
111
- const physRight = Math.round(right * dpr)
112
- const physY = Math.round(centerY * dpr)
113
-
114
- return {
115
- x: physLeft / dpr,
116
- y: physY / dpr,
117
- width: Math.max(1, physRight - physLeft) / dpr,
118
- height: 1 / dpr,
119
- }
120
- }
121
-
122
- /**
123
- * 创建对齐的K线实体和影线
124
- * @param rectX - 实体左边界 X 坐标(逻辑像素)
125
- * @param rectY - 实体顶部 Y 坐标(逻辑像素)
126
- * @param kWidth - 实体宽度(逻辑像素)
127
- * @param height - 实体高度(逻辑像素)
128
- * @param dpr - 设备像素比
129
- * @returns 对齐后的实体和影线信息
130
- */
131
- export function createAlignedKLine(
132
- rectX: number,
133
- rectY: number,
134
- kWidth: number,
135
- height: number,
136
- dpr: number,
137
- theme?: 'light' | 'dark'
138
- ): {
139
- bodyRect: { x: number; y: number; width: number; height: number }
140
- physBodyLeft: number
141
- physBodyRight: number
142
- physBodyWidth: number
143
- physBodyCenter: number
144
- physWickX: number
145
- wickRect: { x: number; width: number }
146
- isPerfectlyAligned: boolean
147
- } {
148
- // 1. 统一在物理像素空间计算,避免二次round
149
-
150
- // 1.1 左边界:round到整数像素列
151
- const leftPx = Math.round(rectX * dpr)
152
-
153
- // 1.2 宽度:round到整数,并确保是奇数
154
- let widthPx = Math.round(kWidth * dpr)
155
- if (widthPx % 2 === 0) {
156
- widthPx += 1
157
- }
158
- widthPx = Math.max(1, widthPx)
159
-
160
- // 1.3 右边界:由左边界+宽度决定
161
- const rightPx = leftPx + widthPx
162
-
163
- // 1.4 物理宽度
164
- const physBodyWidth = widthPx
165
-
166
- // 2. Y轴对齐
167
- const topPx = Math.round(rectY * dpr)
168
- const bottomPx = Math.round((rectY + height) * dpr)
169
- const heightPx = Math.max(1, bottomPx - topPx)
170
-
171
- // 3. 计算物理中心和影线位置
172
- const physWickX = leftPx + (widthPx - 1) / 2
173
- const physBodyCenter = physWickX
174
- const isPerfectlyAligned = physBodyWidth % 2 === 1
175
-
176
- // 4. 返回逻辑像素坐标
177
- return {
178
- bodyRect: {
179
- x: leftPx / dpr,
180
- y: topPx / dpr,
181
- width: widthPx / dpr,
182
- height: heightPx / dpr,
183
- },
184
- physBodyLeft: leftPx,
185
- physBodyRight: rightPx,
186
- physBodyWidth,
187
- physBodyCenter,
188
- physWickX,
189
- wickRect: {
190
- x: physWickX / dpr,
191
- width: 1 / dpr,
192
- },
193
- isPerfectlyAligned,
194
- }
195
- }
196
-
197
- /**
198
- * 创建对齐的K线实体和影线(物理像素直接版)
199
- * @param leftPx - 实体左边界物理像素坐标(整数)
200
- * @param rectY - 实体顶部 Y 坐标(逻辑像素)
201
- * @param widthPx - 实体宽度物理像素(奇数)
202
- * @param height - 实体高度(逻辑像素)
203
- * @param dpr - 设备像素比
204
- * @returns 对齐后的实体和影线信息
205
- */
206
- export function createAlignedKLineFromPx(
207
- leftPx: number,
208
- rectY: number,
209
- widthPx: number,
210
- height: number,
211
- dpr: number,
212
- theme?: 'light' | 'dark'
213
- ): {
214
- bodyRect: { x: number; y: number; width: number; height: number }
215
- physBodyLeft: number
216
- physBodyRight: number
217
- physBodyWidth: number
218
- physBodyCenter: number
219
- physWickX: number
220
- wickRect: { x: number; width: number }
221
- isPerfectlyAligned: boolean
222
- } {
223
- // 1. 物理像素空间计算
224
-
225
- // 1.1 左边界直接使用传入的整数
226
- // 1.2 宽度直接使用传入的奇数
227
- // 1.3 右边界由左边界+宽度决定
228
- const rightPx = leftPx + widthPx
229
- const physBodyWidth = widthPx
230
-
231
- // 2. Y轴对齐
232
- const topPx = Math.round(rectY * dpr)
233
- const bottomPx = Math.round((rectY + height) * dpr)
234
- const heightPx = Math.max(1, bottomPx - topPx)
235
-
236
- // 3. 计算影线位置
237
- const physWickX = leftPx + (widthPx - 1) / 2
238
- const physBodyCenter = physWickX
239
- const isPerfectlyAligned = physBodyWidth % 2 === 1
240
-
241
- // 4. 返回逻辑像素坐标
242
- return {
243
- bodyRect: {
244
- x: leftPx / dpr,
245
- y: topPx / dpr,
246
- width: widthPx / dpr,
247
- height: heightPx / dpr,
248
- },
249
- physBodyLeft: leftPx,
250
- physBodyRight: rightPx,
251
- physBodyWidth,
252
- physBodyCenter,
253
- physWickX,
254
- wickRect: {
255
- x: physWickX / dpr,
256
- width: 1 / dpr,
257
- },
258
- isPerfectlyAligned,
259
- }
1
+ /**
2
+ * 像素对齐工具函数 - 逻辑像素空间(配合 ctx.scale(dpr) 使用)
3
+ */
4
+
5
+ import { getColors } from '../theme/colors'
6
+
7
+ /**
8
+ * 将逻辑坐标对齐到物理像素边界(用于矩形填充)
9
+ * @param value - 逻辑坐标值
10
+ * @param dpr - 设备像素比
11
+ * @returns 对齐后的逻辑坐标
12
+ */
13
+ export function roundToPhysicalPixel(value: number, dpr: number, theme?: 'light' | 'dark'): number {
14
+ return Math.round(value * dpr) / dpr
15
+ }
16
+
17
+ /**
18
+ * 将逻辑坐标对齐到物理像素中心(用于 1px 线条)
19
+ * @param value - 逻辑坐标值
20
+ * @param dpr - 设备像素比
21
+ * @returns 对齐后的逻辑坐标
22
+ */
23
+ export function alignToPhysicalPixelCenter(value: number, dpr: number, theme?: 'light' | 'dark'): number {
24
+ return (Math.floor(value * dpr) + 0.5) / dpr
25
+ }
26
+
27
+ /**
28
+ * 对齐矩形到物理像素边界
29
+ * @param x - 矩形左边界 X 坐标
30
+ * @param y - 矩形顶部 Y 坐标
31
+ * @param width - 矩形宽度
32
+ * @param height - 矩形高度
33
+ * @param dpr - 设备像素比
34
+ * @returns 对齐后的矩形信息
35
+ */
36
+ export function alignRect(
37
+ x: number,
38
+ y: number,
39
+ width: number,
40
+ height: number,
41
+ dpr: number,
42
+ theme?: 'light' | 'dark'
43
+ ): { x: number; y: number; width: number; height: number } {
44
+ const alignedX = roundToPhysicalPixel(x, dpr)
45
+ const alignedY = roundToPhysicalPixel(y, dpr)
46
+ const alignedEndX = roundToPhysicalPixel(x + width, dpr)
47
+ const alignedEndY = roundToPhysicalPixel(y + height, dpr)
48
+
49
+ return {
50
+ x: alignedX,
51
+ y: alignedY,
52
+ width: Math.max(1 / dpr, alignedEndX - alignedX),
53
+ height: Math.max(1 / dpr, alignedEndY - alignedY),
54
+ }
55
+ }
56
+
57
+ /**
58
+ * 创建用于绘制垂直线的矩形(1 物理像素宽)
59
+ * @param centerX - 垂直线中心 X 坐标
60
+ * @param y1 - 垂直线起始点 Y 坐标
61
+ * @param y2 - 垂直线结束点 Y 坐标
62
+ * @param dpr - 设备像素比
63
+ * @returns 对齐到物理像素的矩形信息,如果 y1 和 y2 相等则返回 null
64
+ */
65
+ export function createVerticalLineRect(
66
+ centerX: number,
67
+ y1: number,
68
+ y2: number,
69
+ dpr: number,
70
+ theme?: 'light' | 'dark'
71
+ ): { x: number; y: number; width: number; height: number } | null {
72
+ if (y1 === y2) return null
73
+
74
+ const top = Math.min(y1, y2)
75
+ const bottom = Math.max(y1, y2)
76
+
77
+ // 转换到物理像素空间取整,再转回逻辑像素
78
+ const physX = Math.round(centerX * dpr)
79
+ const physTop = Math.round(top * dpr)
80
+ const physBottom = Math.round(bottom * dpr)
81
+
82
+ return {
83
+ x: physX / dpr,
84
+ y: physTop / dpr,
85
+ width: 1 / dpr,
86
+ height: Math.max(1, physBottom - physTop) / dpr,
87
+ }
88
+ }
89
+
90
+ /**
91
+ * 创建用于绘制水平线的矩形(1 物理像素高)
92
+ * @param x1 - 水平线起始点的 X 坐标
93
+ * @param x2 - 水平线结束点的 X 坐标
94
+ * @param centerY - 水平线中心 Y 坐标
95
+ * @param dpr - 设备像素比
96
+ * @returns 对齐到物理像素的矩形信息,如果 x1 和 x2 相等则返回 null
97
+ */
98
+ export function createHorizontalLineRect(
99
+ x1: number,
100
+ x2: number,
101
+ centerY: number,
102
+ dpr: number,
103
+ theme?: 'light' | 'dark'
104
+ ): { x: number; y: number; width: number; height: number } | null {
105
+ if (x1 === x2) return null
106
+
107
+ const left = Math.min(x1, x2)
108
+ const right = Math.max(x1, x2)
109
+
110
+ const physLeft = Math.round(left * dpr)
111
+ const physRight = Math.round(right * dpr)
112
+ const physY = Math.round(centerY * dpr)
113
+
114
+ return {
115
+ x: physLeft / dpr,
116
+ y: physY / dpr,
117
+ width: Math.max(1, physRight - physLeft) / dpr,
118
+ height: 1 / dpr,
119
+ }
120
+ }
121
+
122
+ /**
123
+ * 创建对齐的K线实体和影线
124
+ * @param rectX - 实体左边界 X 坐标(逻辑像素)
125
+ * @param rectY - 实体顶部 Y 坐标(逻辑像素)
126
+ * @param kWidth - 实体宽度(逻辑像素)
127
+ * @param height - 实体高度(逻辑像素)
128
+ * @param dpr - 设备像素比
129
+ * @returns 对齐后的实体和影线信息
130
+ */
131
+ export function createAlignedKLine(
132
+ rectX: number,
133
+ rectY: number,
134
+ kWidth: number,
135
+ height: number,
136
+ dpr: number,
137
+ theme?: 'light' | 'dark'
138
+ ): {
139
+ bodyRect: { x: number; y: number; width: number; height: number }
140
+ physBodyLeft: number
141
+ physBodyRight: number
142
+ physBodyWidth: number
143
+ physBodyCenter: number
144
+ physWickX: number
145
+ wickRect: { x: number; width: number }
146
+ isPerfectlyAligned: boolean
147
+ } {
148
+ // 1. 统一在物理像素空间计算,避免二次round
149
+
150
+ // 1.1 左边界:round到整数像素列
151
+ const leftPx = Math.round(rectX * dpr)
152
+
153
+ // 1.2 宽度:round到整数,并确保是奇数
154
+ let widthPx = Math.round(kWidth * dpr)
155
+ if (widthPx % 2 === 0) {
156
+ widthPx += 1
157
+ }
158
+ widthPx = Math.max(1, widthPx)
159
+
160
+ // 1.3 右边界:由左边界+宽度决定
161
+ const rightPx = leftPx + widthPx
162
+
163
+ // 1.4 物理宽度
164
+ const physBodyWidth = widthPx
165
+
166
+ // 2. Y轴对齐
167
+ const topPx = Math.round(rectY * dpr)
168
+ const bottomPx = Math.round((rectY + height) * dpr)
169
+ const heightPx = Math.max(1, bottomPx - topPx)
170
+
171
+ // 3. 计算物理中心和影线位置
172
+ const physWickX = leftPx + (widthPx - 1) / 2
173
+ const physBodyCenter = physWickX
174
+ const isPerfectlyAligned = physBodyWidth % 2 === 1
175
+
176
+ // 4. 返回逻辑像素坐标
177
+ return {
178
+ bodyRect: {
179
+ x: leftPx / dpr,
180
+ y: topPx / dpr,
181
+ width: widthPx / dpr,
182
+ height: heightPx / dpr,
183
+ },
184
+ physBodyLeft: leftPx,
185
+ physBodyRight: rightPx,
186
+ physBodyWidth,
187
+ physBodyCenter,
188
+ physWickX,
189
+ wickRect: {
190
+ x: physWickX / dpr,
191
+ width: 1 / dpr,
192
+ },
193
+ isPerfectlyAligned,
194
+ }
195
+ }
196
+
197
+ /**
198
+ * 创建对齐的K线实体和影线(物理像素直接版)
199
+ * @param leftPx - 实体左边界物理像素坐标(整数)
200
+ * @param rectY - 实体顶部 Y 坐标(逻辑像素)
201
+ * @param widthPx - 实体宽度物理像素(奇数)
202
+ * @param height - 实体高度(逻辑像素)
203
+ * @param dpr - 设备像素比
204
+ * @returns 对齐后的实体和影线信息
205
+ */
206
+ export function createAlignedKLineFromPx(
207
+ leftPx: number,
208
+ rectY: number,
209
+ widthPx: number,
210
+ height: number,
211
+ dpr: number,
212
+ theme?: 'light' | 'dark'
213
+ ): {
214
+ bodyRect: { x: number; y: number; width: number; height: number }
215
+ physBodyLeft: number
216
+ physBodyRight: number
217
+ physBodyWidth: number
218
+ physBodyCenter: number
219
+ physWickX: number
220
+ wickRect: { x: number; width: number }
221
+ isPerfectlyAligned: boolean
222
+ } {
223
+ // 1. 物理像素空间计算
224
+
225
+ // 1.1 左边界直接使用传入的整数
226
+ // 1.2 宽度直接使用传入的奇数
227
+ // 1.3 右边界由左边界+宽度决定
228
+ const rightPx = leftPx + widthPx
229
+ const physBodyWidth = widthPx
230
+
231
+ // 2. Y轴对齐
232
+ const topPx = Math.round(rectY * dpr)
233
+ const bottomPx = Math.round((rectY + height) * dpr)
234
+ const heightPx = Math.max(1, bottomPx - topPx)
235
+
236
+ // 3. 计算影线位置
237
+ const physWickX = leftPx + (widthPx - 1) / 2
238
+ const physBodyCenter = physWickX
239
+ const isPerfectlyAligned = physBodyWidth % 2 === 1
240
+
241
+ // 4. 返回逻辑像素坐标
242
+ return {
243
+ bodyRect: {
244
+ x: leftPx / dpr,
245
+ y: topPx / dpr,
246
+ width: widthPx / dpr,
247
+ height: heightPx / dpr,
248
+ },
249
+ physBodyLeft: leftPx,
250
+ physBodyRight: rightPx,
251
+ physBodyWidth,
252
+ physBodyCenter,
253
+ physWickX,
254
+ wickRect: {
255
+ x: physWickX / dpr,
256
+ width: 1 / dpr,
257
+ },
258
+ isPerfectlyAligned,
259
+ }
260
260
  }