@363045841yyt/klinechart-core 0.7.5 → 0.7.7

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 (235) hide show
  1. package/README.md +8 -8
  2. package/README.zh-CN.md +8 -8
  3. package/dist/config/chartSettings.d.ts +27 -2
  4. package/dist/config/chartSettings.d.ts.map +1 -1
  5. package/dist/config/chartSettings.js +6 -0
  6. package/dist/config/chartSettings.js.map +1 -1
  7. package/dist/controllers/createChartController.d.ts.map +1 -1
  8. package/dist/controllers/createChartController.js +145 -21
  9. package/dist/controllers/createChartController.js.map +1 -1
  10. package/dist/controllers/index.d.ts +9 -1
  11. package/dist/controllers/index.d.ts.map +1 -1
  12. package/dist/controllers/index.js +9 -0
  13. package/dist/controllers/index.js.map +1 -1
  14. package/dist/controllers/types.d.ts +65 -8
  15. package/dist/controllers/types.d.ts.map +1 -1
  16. package/dist/engine/chart.d.ts +2 -12
  17. package/dist/engine/chart.d.ts.map +1 -1
  18. package/dist/engine/chart.js +32 -31
  19. package/dist/engine/chart.js.map +1 -1
  20. package/dist/engine/controller/interaction.d.ts +1 -1
  21. package/dist/engine/controller/interaction.d.ts.map +1 -1
  22. package/dist/engine/controller/interaction.js +10 -2
  23. package/dist/engine/controller/interaction.js.map +1 -1
  24. package/dist/engine/draw/pixelAlign.d.ts.map +1 -1
  25. package/dist/engine/draw/pixelAlign.js.map +1 -1
  26. package/dist/engine/drawing/interaction.d.ts +3 -3
  27. package/dist/engine/drawing/interaction.d.ts.map +1 -1
  28. package/dist/engine/drawing/interaction.js +38 -46
  29. package/dist/engine/drawing/interaction.js.map +1 -1
  30. package/dist/engine/drawing/plugin.js +1 -1
  31. package/dist/engine/drawing/plugin.js.map +1 -1
  32. package/dist/engine/renderers/Indicator/atr.d.ts.map +1 -1
  33. package/dist/engine/renderers/Indicator/atr.js +7 -4
  34. package/dist/engine/renderers/Indicator/atr.js.map +1 -1
  35. package/dist/engine/renderers/Indicator/boll.js +12 -12
  36. package/dist/engine/renderers/Indicator/boll.js.map +1 -1
  37. package/dist/engine/renderers/Indicator/cci.d.ts +1 -2
  38. package/dist/engine/renderers/Indicator/cci.d.ts.map +1 -1
  39. package/dist/engine/renderers/Indicator/cci.js +9 -9
  40. package/dist/engine/renderers/Indicator/cci.js.map +1 -1
  41. package/dist/engine/renderers/Indicator/ene.js +12 -12
  42. package/dist/engine/renderers/Indicator/ene.js.map +1 -1
  43. package/dist/engine/renderers/Indicator/expma.js +6 -6
  44. package/dist/engine/renderers/Indicator/expma.js.map +1 -1
  45. package/dist/engine/renderers/Indicator/fastk.d.ts +1 -2
  46. package/dist/engine/renderers/Indicator/fastk.d.ts.map +1 -1
  47. package/dist/engine/renderers/Indicator/fastk.js +7 -7
  48. package/dist/engine/renderers/Indicator/fastk.js.map +1 -1
  49. package/dist/engine/renderers/Indicator/kst.d.ts +1 -2
  50. package/dist/engine/renderers/Indicator/kst.d.ts.map +1 -1
  51. package/dist/engine/renderers/Indicator/kst.js +10 -10
  52. package/dist/engine/renderers/Indicator/kst.js.map +1 -1
  53. package/dist/engine/renderers/Indicator/ma.js +5 -5
  54. package/dist/engine/renderers/Indicator/ma.js.map +1 -1
  55. package/dist/engine/renderers/Indicator/macd.d.ts +1 -2
  56. package/dist/engine/renderers/Indicator/macd.d.ts.map +1 -1
  57. package/dist/engine/renderers/Indicator/macd.js +24 -24
  58. package/dist/engine/renderers/Indicator/macd.js.map +1 -1
  59. package/dist/engine/renderers/Indicator/macdLegend.js +6 -6
  60. package/dist/engine/renderers/Indicator/macdLegend.js.map +1 -1
  61. package/dist/engine/renderers/Indicator/mainIndicatorLegend.js +16 -16
  62. package/dist/engine/renderers/Indicator/mainIndicatorLegend.js.map +1 -1
  63. package/dist/engine/renderers/Indicator/mom.d.ts +1 -2
  64. package/dist/engine/renderers/Indicator/mom.d.ts.map +1 -1
  65. package/dist/engine/renderers/Indicator/mom.js +8 -8
  66. package/dist/engine/renderers/Indicator/mom.js.map +1 -1
  67. package/dist/engine/renderers/Indicator/rsi.d.ts +2 -3
  68. package/dist/engine/renderers/Indicator/rsi.d.ts.map +1 -1
  69. package/dist/engine/renderers/Indicator/rsi.js +15 -15
  70. package/dist/engine/renderers/Indicator/rsi.js.map +1 -1
  71. package/dist/engine/renderers/Indicator/scale/indicator_scale.d.ts +1 -2
  72. package/dist/engine/renderers/Indicator/scale/indicator_scale.d.ts.map +1 -1
  73. package/dist/engine/renderers/Indicator/scale/indicator_scale.js +5 -5
  74. package/dist/engine/renderers/Indicator/scale/indicator_scale.js.map +1 -1
  75. package/dist/engine/renderers/Indicator/stoch.d.ts +1 -2
  76. package/dist/engine/renderers/Indicator/stoch.d.ts.map +1 -1
  77. package/dist/engine/renderers/Indicator/stoch.js +10 -10
  78. package/dist/engine/renderers/Indicator/stoch.js.map +1 -1
  79. package/dist/engine/renderers/Indicator/structure.js +5 -5
  80. package/dist/engine/renderers/Indicator/structure.js.map +1 -1
  81. package/dist/engine/renderers/Indicator/wmsr.d.ts +1 -2
  82. package/dist/engine/renderers/Indicator/wmsr.d.ts.map +1 -1
  83. package/dist/engine/renderers/Indicator/wmsr.js +10 -10
  84. package/dist/engine/renderers/Indicator/wmsr.js.map +1 -1
  85. package/dist/engine/renderers/Indicator/zones.js +6 -6
  86. package/dist/engine/renderers/Indicator/zones.js.map +1 -1
  87. package/dist/engine/renderers/candle.d.ts +1 -1
  88. package/dist/engine/renderers/candle.d.ts.map +1 -1
  89. package/dist/engine/renderers/candle.js +21 -21
  90. package/dist/engine/renderers/candle.js.map +1 -1
  91. package/dist/engine/renderers/crosshair.js +3 -3
  92. package/dist/engine/renderers/crosshair.js.map +1 -1
  93. package/dist/engine/renderers/extremaMarkers.d.ts.map +1 -1
  94. package/dist/engine/renderers/extremaMarkers.js +12 -12
  95. package/dist/engine/renderers/extremaMarkers.js.map +1 -1
  96. package/dist/engine/renderers/gridLines.js +3 -3
  97. package/dist/engine/renderers/gridLines.js.map +1 -1
  98. package/dist/engine/renderers/lastPrice.js +7 -7
  99. package/dist/engine/renderers/lastPrice.js.map +1 -1
  100. package/dist/engine/renderers/paneTitle.d.ts +5 -24
  101. package/dist/engine/renderers/paneTitle.d.ts.map +1 -1
  102. package/dist/engine/renderers/paneTitle.js +16 -11
  103. package/dist/engine/renderers/paneTitle.js.map +1 -1
  104. package/dist/engine/renderers/subVolume.d.ts.map +1 -1
  105. package/dist/engine/renderers/subVolume.js +23 -20
  106. package/dist/engine/renderers/subVolume.js.map +1 -1
  107. package/dist/engine/renderers/timeAxis.js +9 -9
  108. package/dist/engine/renderers/timeAxis.js.map +1 -1
  109. package/dist/engine/renderers/webgl/candleSurface.d.ts +4 -4
  110. package/dist/engine/renderers/webgl/candleSurface.d.ts.map +1 -1
  111. package/dist/engine/renderers/webgl/candleSurface.js +72 -60
  112. package/dist/engine/renderers/webgl/candleSurface.js.map +1 -1
  113. package/dist/engine/renderers/yAxis.d.ts.map +1 -1
  114. package/dist/engine/renderers/yAxis.js +5 -5
  115. package/dist/engine/renderers/yAxis.js.map +1 -1
  116. package/dist/engine/subPaneManager.d.ts +2 -0
  117. package/dist/engine/subPaneManager.d.ts.map +1 -1
  118. package/dist/engine/subPaneManager.js +25 -1
  119. package/dist/engine/subPaneManager.js.map +1 -1
  120. package/dist/index.d.ts +1 -0
  121. package/dist/index.d.ts.map +1 -1
  122. package/dist/index.js +1 -0
  123. package/dist/index.js.map +1 -1
  124. package/dist/plugin/types.d.ts +5 -1
  125. package/dist/plugin/types.d.ts.map +1 -1
  126. package/dist/plugin/types.js.map +1 -1
  127. package/dist/semantic/controller.d.ts +1 -2
  128. package/dist/semantic/controller.d.ts.map +1 -1
  129. package/dist/semantic/index.d.ts +1 -1
  130. package/dist/semantic/index.d.ts.map +1 -1
  131. package/dist/tokens/colorPresetSettings.d.ts +15 -0
  132. package/dist/tokens/colorPresetSettings.d.ts.map +1 -0
  133. package/dist/tokens/colorPresetSettings.js +65 -0
  134. package/dist/tokens/colorPresetSettings.js.map +1 -0
  135. package/dist/tokens/index.d.ts +17 -0
  136. package/dist/tokens/index.d.ts.map +1 -0
  137. package/dist/tokens/index.js +16 -0
  138. package/dist/tokens/index.js.map +1 -0
  139. package/dist/tokens/mergeTheme.d.ts +17 -0
  140. package/dist/tokens/mergeTheme.d.ts.map +1 -0
  141. package/dist/tokens/mergeTheme.js +43 -0
  142. package/dist/tokens/mergeTheme.js.map +1 -0
  143. package/dist/tokens/theme-china.d.ts +45 -0
  144. package/dist/tokens/theme-china.d.ts.map +1 -0
  145. package/dist/tokens/theme-china.js +116 -0
  146. package/dist/tokens/theme-china.js.map +1 -0
  147. package/dist/tokens/theme-dark.d.ts +21 -0
  148. package/dist/tokens/theme-dark.d.ts.map +1 -0
  149. package/dist/tokens/theme-dark.js +228 -0
  150. package/dist/tokens/theme-dark.js.map +1 -0
  151. package/dist/tokens/theme-light.d.ts +23 -0
  152. package/dist/tokens/theme-light.d.ts.map +1 -0
  153. package/dist/tokens/theme-light.js +234 -0
  154. package/dist/tokens/theme-light.js.map +1 -0
  155. package/dist/tokens/themeToCssVars.d.ts +74 -0
  156. package/dist/tokens/themeToCssVars.d.ts.map +1 -0
  157. package/dist/tokens/themeToCssVars.js +108 -0
  158. package/dist/tokens/themeToCssVars.js.map +1 -0
  159. package/dist/tokens/types.d.ts +335 -0
  160. package/dist/tokens/types.d.ts.map +1 -0
  161. package/dist/tokens/types.js +20 -0
  162. package/dist/tokens/types.js.map +1 -0
  163. package/dist/utils/kLineDraw/axis.d.ts +8 -7
  164. package/dist/utils/kLineDraw/axis.d.ts.map +1 -1
  165. package/dist/utils/kLineDraw/axis.js +24 -24
  166. package/dist/utils/kLineDraw/axis.js.map +1 -1
  167. package/dist/version.d.ts +1 -1
  168. package/dist/version.js +1 -1
  169. package/package.json +6 -6
  170. package/src/config/chartSettings.ts +11 -2
  171. package/src/controllers/createChartController.ts +158 -29
  172. package/src/controllers/index.ts +33 -0
  173. package/src/controllers/types.ts +79 -8
  174. package/src/engine/chart.ts +32 -37
  175. package/src/engine/controller/interaction.ts +9 -2
  176. package/src/engine/draw/pixelAlign.ts +0 -2
  177. package/src/engine/drawing/interaction.ts +38 -47
  178. package/src/engine/drawing/plugin.ts +1 -1
  179. package/src/engine/renderers/Indicator/atr.ts +7 -3
  180. package/src/engine/renderers/Indicator/boll.ts +12 -12
  181. package/src/engine/renderers/Indicator/cci.ts +11 -10
  182. package/src/engine/renderers/Indicator/ene.ts +12 -12
  183. package/src/engine/renderers/Indicator/expma.ts +6 -6
  184. package/src/engine/renderers/Indicator/fastk.ts +9 -8
  185. package/src/engine/renderers/Indicator/kst.ts +12 -11
  186. package/src/engine/renderers/Indicator/ma.ts +5 -5
  187. package/src/engine/renderers/Indicator/macd.ts +27 -25
  188. package/src/engine/renderers/Indicator/macdLegend.ts +6 -6
  189. package/src/engine/renderers/Indicator/mainIndicatorLegend.ts +16 -16
  190. package/src/engine/renderers/Indicator/mom.ts +11 -10
  191. package/src/engine/renderers/Indicator/rsi.ts +18 -15
  192. package/src/engine/renderers/Indicator/scale/indicator_scale.ts +6 -6
  193. package/src/engine/renderers/Indicator/stoch.ts +12 -11
  194. package/src/engine/renderers/Indicator/structure.ts +5 -5
  195. package/src/engine/renderers/Indicator/wmsr.ts +13 -12
  196. package/src/engine/renderers/Indicator/zones.ts +7 -7
  197. package/src/engine/renderers/candle.ts +21 -21
  198. package/src/engine/renderers/crosshair.ts +3 -3
  199. package/src/engine/renderers/extremaMarkers.ts +13 -12
  200. package/src/engine/renderers/gridLines.ts +3 -3
  201. package/src/engine/renderers/lastPrice.ts +7 -7
  202. package/src/engine/renderers/paneTitle.ts +22 -31
  203. package/src/engine/renderers/subVolume.ts +23 -20
  204. package/src/engine/renderers/timeAxis.ts +9 -9
  205. package/src/engine/renderers/webgl/candleSurface.ts +80 -60
  206. package/src/engine/renderers/yAxis.ts +6 -5
  207. package/src/engine/subPaneManager.ts +28 -1
  208. package/src/index.ts +1 -0
  209. package/src/plugin/types.ts +5 -1
  210. package/src/semantic/controller.ts +1 -1
  211. package/src/semantic/index.ts +1 -1
  212. package/src/tokens/__tests__/__snapshots__/baseline.test.ts.snap +393 -0
  213. package/src/tokens/__tests__/baseline.test.ts +183 -0
  214. package/src/tokens/__tests__/themeToCssVars.test.ts +175 -0
  215. package/src/tokens/__tests__/tokens.test.ts +215 -0
  216. package/src/tokens/colorPresetSettings.ts +128 -0
  217. package/src/tokens/index.ts +65 -0
  218. package/src/tokens/mergeTheme.ts +48 -0
  219. package/src/tokens/theme-china.ts +132 -0
  220. package/src/tokens/theme-dark.ts +244 -0
  221. package/src/tokens/theme-light.ts +250 -0
  222. package/src/tokens/themeToCssVars.ts +138 -0
  223. package/src/tokens/types.ts +394 -0
  224. package/src/utils/kLineDraw/axis.ts +31 -30
  225. package/src/version.ts +1 -1
  226. package/dist/engine/chart-store.d.ts +0 -75
  227. package/dist/engine/chart-store.d.ts.map +0 -1
  228. package/dist/engine/chart-store.js +0 -88
  229. package/dist/engine/chart-store.js.map +0 -1
  230. package/dist/engine/theme/colors.d.ts +0 -223
  231. package/dist/engine/theme/colors.d.ts.map +0 -1
  232. package/dist/engine/theme/colors.js +0 -375
  233. package/dist/engine/theme/colors.js.map +0 -1
  234. package/src/engine/chart-store.ts +0 -121
  235. package/src/engine/theme/colors.ts +0 -642
@@ -9,7 +9,8 @@
9
9
  */
10
10
 
11
11
  import type { Signal } from '../reactivity'
12
- import type { CustomMarkerEntity } from '../engine/marker/registry'
12
+ import type { CustomMarkerEntity, MarkerEntity } from '../engine/marker/registry'
13
+ import type { PaneSpec } from '../engine/chart'
13
14
 
14
15
  // Controller-owned public surface. Legacy engine types may mirror these
15
16
  // shapes internally, but adapters depend only on core-defined contracts.
@@ -73,6 +74,8 @@ export interface KLineData {
73
74
  turnoverRate?: number
74
75
  }
75
76
 
77
+ export type { PaneSpec }
78
+
76
79
  // ---------------------------------------------------------------------------
77
80
  // Indicator metadata
78
81
  // ---------------------------------------------------------------------------
@@ -109,8 +112,8 @@ export interface InteractionSnapshot {
109
112
  activePaneId: string | null
110
113
  tooltipPos: { x: number; y: number }
111
114
  tooltipAnchorPlacement: 'right-bottom' | 'left-bottom'
112
- hoveredMarkerData: Record<string, unknown> | null
113
- hoveredCustomMarker: Record<string, unknown> | null
115
+ hoveredMarkerData: MarkerEntity | null
116
+ hoveredCustomMarker: CustomMarkerEntity | null
114
117
  isDragging: boolean
115
118
  isResizingPaneBoundary: boolean
116
119
  isHoveringPaneBoundary: boolean
@@ -118,6 +121,51 @@ export interface InteractionSnapshot {
118
121
  isHoveringRightAxis: boolean
119
122
  }
120
123
 
124
+ // ---------------------------------------------------------------------------
125
+ // Pane info (read-only pane metadata for DrawingChartAdapter)
126
+ // ---------------------------------------------------------------------------
127
+
128
+ export interface PaneInfo {
129
+ paneId: string
130
+ top: number
131
+ height: number
132
+ }
133
+
134
+ // ---------------------------------------------------------------------------
135
+ // Drawing adapter — narrow interface for DrawingInteractionController
136
+ // ---------------------------------------------------------------------------
137
+
138
+ export interface DrawingChartViewport {
139
+ scrollLeft: number
140
+ plotWidth: number
141
+ plotHeight: number
142
+ }
143
+
144
+ export interface DrawingChartAdapter {
145
+ /** persist full drawing list to the chart engine */
146
+ setDrawings(drawings: any[]): void
147
+ /** highlight a drawing by ID */
148
+ setSelectedDrawingId(id: string | null): void
149
+ /** current viewport (nullable if chart not ready) */
150
+ getViewport(): DrawingChartViewport | null
151
+ /** resolved chart options (kWidth, kGap) */
152
+ getKWidthKGap(): { kWidth: number; kGap: number }
153
+ /** device pixel ratio */
154
+ getCurrentDpr(): number
155
+ /** raw K-line data */
156
+ getData(): ReadonlyArray<KLineData>
157
+ /** screen-x → logical bar index */
158
+ getLogicalIndexAtX(mouseX: number): number | null
159
+ /** logical index → unix timestamp (ms) */
160
+ getTimestampAtLogicalIndex(index: number): number | null
161
+ /** price → Y within the given pane */
162
+ priceToY(paneId: string, price: number): number
163
+ /** Y within the given pane → price */
164
+ yToPrice(paneId: string, y: number): number
165
+ /** read-only pane metadata by pane ID */
166
+ getPaneInfo(paneId: string): PaneInfo | undefined
167
+ }
168
+
121
169
  // ---------------------------------------------------------------------------
122
170
  // Drawing controller callback type (passed to handlePointerEvent)
123
171
  // ---------------------------------------------------------------------------
@@ -138,9 +186,22 @@ export interface ChartMountOptions {
138
186
  initialZoomLevel?: number
139
187
  zoomLevels?: number
140
188
  theme?: 'light' | 'dark'
189
+
190
+ // Pre-existing DOM elements (skip buildDom when provided)
191
+ canvasLayer?: HTMLElement
192
+ rightAxisLayer?: HTMLElement
193
+ xAxisCanvas?: HTMLCanvasElement
194
+
195
+ // Chart options overrides
196
+ yPaddingPx?: number
197
+ rightAxisWidth?: number
198
+ bottomAxisHeight?: number
199
+ priceLabelWidth?: number
200
+ minKWidth?: number
201
+ maxKWidth?: number
141
202
  }
142
203
 
143
- export interface ChartController {
204
+ export interface ChartController extends DrawingChartAdapter {
144
205
  // ---- Signals ----
145
206
  readonly viewport: Signal<ChartViewport>
146
207
  readonly data: Signal<ReadonlyArray<KLineData>>
@@ -150,6 +211,7 @@ export interface ChartController {
150
211
  readonly drawingTool: Signal<DrawingToolType | null>
151
212
  readonly drawings: Signal<ReadonlyArray<DrawingObject>>
152
213
  readonly paneRatios: Signal<Readonly<Record<string, number>>>
214
+ readonly paneLayout: Signal<ReadonlyArray<PaneSpec>>
153
215
  readonly interactionState: Signal<InteractionSnapshot>
154
216
 
155
217
  // indicator catalog (static — adapters use for picker UI)
@@ -159,6 +221,8 @@ export interface ChartController {
159
221
  setData(next: ReadonlyArray<KLineData>): void
160
222
  appendData(next: ReadonlyArray<KLineData>): void
161
223
  updateData(next: ReadonlyArray<KLineData>): void
224
+ getData(): ReadonlyArray<KLineData>
225
+ getZoomLevelCount(): number
162
226
 
163
227
  // ---- Theme ----
164
228
  setTheme(theme: 'light' | 'dark'): void
@@ -193,11 +257,22 @@ export interface ChartController {
193
257
  resizeSubPane(paneId: string, deltaY: number): boolean
194
258
  createSubPane(paneId: string, indicatorId: string, params?: Record<string, unknown>): boolean
195
259
  clearSubPanes(): void
260
+ replaceSubPaneIndicator(paneId: string, indicatorId: string, params?: Record<string, unknown>): boolean
261
+ updatePaneLayout(panes: PaneSpec[]): void
196
262
 
197
263
  // ---- Drawing / Markers ----
198
264
  updateCustomMarkers(markers: ReadonlyArray<CustomMarkerEntity>): void
199
265
  clearCustomMarkers(): void
200
266
 
267
+ // ---- Interaction sub-methods ----
268
+ setTooltipSize(size: { width: number; height: number }): void
269
+ setTooltipAnchorPositioning(enabled: boolean): void
270
+
271
+ // ---- Narrow queries ----
272
+ getIndicatorTitle(instanceId: string): string | undefined
273
+ /** total scrollable content width (replaces direct computeContentWidth imports) */
274
+ getContentWidth(): number
275
+
201
276
  // ---- Settings ----
202
277
  updateSettingsFacade(settings: Record<string, unknown>): void
203
278
  updateOptionsFacade(options: Record<string, unknown>): void
@@ -218,7 +293,6 @@ export type ChartControllerFactory = (opts: ChartMountOptions) => ChartControlle
218
293
  // Legacy type aliases (deprecated — kept for internal sub-controller tests)
219
294
  // ---------------------------------------------------------------------------
220
295
 
221
- /** @deprecated Use `IndicatorInstance` instead. Kept for createIndicatorSelectorController tests. */
222
296
  export interface ActiveIndicator {
223
297
  id: string
224
298
  definitionId: string
@@ -228,7 +302,6 @@ export interface ActiveIndicator {
228
302
  params: Readonly<Record<string, number | string | boolean>>
229
303
  }
230
304
 
231
- /** @deprecated Flattened into ChartController. Kept for createIndicatorSelectorController tests. */
232
305
  export interface IndicatorSelectorController {
233
306
  readonly catalog: Signal<ReadonlyArray<IndicatorDefinition>>
234
307
  readonly active: Signal<ReadonlyArray<ActiveIndicator>>
@@ -258,7 +331,6 @@ export interface ToolDefinition {
258
331
  disabled?: boolean
259
332
  }
260
333
 
261
- /** @deprecated Flattened into ChartController. Kept for createToolbarController tests. */
262
334
  export interface ToolbarController {
263
335
  readonly tools: Signal<ReadonlyArray<ToolDefinition>>
264
336
  readonly activeTool: Signal<ToolId | null>
@@ -274,7 +346,6 @@ export interface DrawingState {
274
346
  readonly drawingCount: number
275
347
  }
276
348
 
277
- /** @deprecated Flattened into ChartController. Kept for createDrawingController tests. */
278
349
  export interface DrawingController {
279
350
  readonly state: Signal<DrawingState>
280
351
  setActiveTool(tool: DrawingToolType | null): void
@@ -9,7 +9,6 @@ import { PaneRenderer } from './paneRenderer'
9
9
  import { SharedWebGLSurface } from './renderers/webgl/sharedWebGLSurface'
10
10
  import { MarkerManager, type CustomMarkerEntity } from './marker/registry'
11
11
  import { getPhysicalKLineConfig, calcKWidthPx } from './utils/klineConfig'
12
- import { computeContentWidth } from './chart-store'
13
12
  import { computeZoom, computeZoomToLevel, type ZoomConfig } from './utils/zoom'
14
13
  import { IndicatorScheduler } from './indicators/scheduler'
15
14
  import { getRegisteredIndicatorDefinitions } from './indicators/indicatorDefinitionRegistry'
@@ -214,21 +213,12 @@ export class Chart {
214
213
  /** pane ratio 状态(按 paneId 维护,sum=1 仅对可见 pane) */
215
214
  private _internalPaneRatios: Map<string, number> = new Map()
216
215
 
217
- /** 视口变化回调(供外部同步 DPR/尺寸) */
218
- private onViewportChange?: (viewport: Viewport) => void
219
-
220
216
  /** 共享 X 轴上下文缓存 */
221
217
  private xAxisCtx: CanvasRenderingContext2D | null = null
222
218
 
223
219
  /** Chart 级共享 WebGL canvas/context */
224
220
  private sharedWebGLSurface: SharedWebGLSurface
225
221
 
226
- /** pane 布局回流回调(Chart -> UI 单向) */
227
- private onPaneLayoutChange?: (panes: PaneSpec[]) => void
228
-
229
- /** 数据变化回调(供外部同步 dataLength) */
230
- private onDataChange?: (data: KLineData[]) => void
231
-
232
222
  /** 当前缩放级别(1 ~ zoomLevelCount) */
233
223
  private currentZoomLevel: number = 1
234
224
 
@@ -1126,6 +1116,8 @@ export class Chart {
1126
1116
  yAxisRanges: sharedYAxisRanges,
1127
1117
  xAxisRanges: sharedXAxisRanges,
1128
1118
  theme: this._themeSignal.peek(),
1119
+ isAsiaMarket: this.settings.isAsiaMarket as boolean,
1120
+ colorPresetSettings: this.settings.colorPresetSettings,
1129
1121
  }
1130
1122
 
1131
1123
  if (shouldUpdateMain || shouldUpdateOverlay) {
@@ -1203,6 +1195,8 @@ export class Chart {
1203
1195
  xAxisLabels: sharedXAxisLabels,
1204
1196
  xAxisRanges: sharedXAxisRanges,
1205
1197
  theme: this._themeSignal.peek(),
1198
+ isAsiaMarket: this.settings.isAsiaMarket as boolean,
1199
+ colorPresetSettings: this.settings.colorPresetSettings,
1206
1200
  }
1207
1201
  const errors = this.rendererPluginManager.renderPlugin('timeAxis', timeAxisContext)
1208
1202
  if (errors.length > 0) {
@@ -1243,21 +1237,6 @@ export class Chart {
1243
1237
  return this.zoomLevelCount
1244
1238
  }
1245
1239
 
1246
- /** 注册视口变化回调 */
1247
- setOnViewportChange(cb: (viewport: Viewport) => void) {
1248
- this.onViewportChange = cb
1249
- }
1250
-
1251
- /** 注册 pane 布局回流回调 */
1252
- setOnPaneLayoutChange(cb: (panes: PaneSpec[]) => void) {
1253
- this.onPaneLayoutChange = cb
1254
- }
1255
-
1256
- /** 注册数据变化回调 */
1257
- setOnDataChange(cb: (data: KLineData[]) => void) {
1258
- this.onDataChange = cb
1259
- }
1260
-
1261
1240
  /** 获取所有 PaneRenderer */
1262
1241
  getPaneRenderers(): PaneRenderer[] {
1263
1242
  return this.paneRenderers
@@ -1436,7 +1415,7 @@ export class Chart {
1436
1415
  })
1437
1416
  this._paneRatiosSignal.set(ratios)
1438
1417
 
1439
- this.onPaneLayoutChange?.(this.getPaneLayoutSpecs())
1418
+ this._paneLayoutSignal.set(this.getPaneLayoutSpecs())
1440
1419
  }
1441
1420
 
1442
1421
  private applyPaneLayoutSpecs(panes: PaneSpec[]): void {
@@ -1781,7 +1760,6 @@ export class Chart {
1781
1760
  updateData(data: KLineData[]) {
1782
1761
  this._internalData = data ?? []
1783
1762
  this._dataSignal.set([...this._internalData])
1784
- this.onDataChange?.(this._internalData)
1785
1763
 
1786
1764
  // 重算 DOM scrollLeft 状态, 防止左右滚动超出数据长度范围
1787
1765
  const container = this.dom.container
@@ -1848,13 +1826,16 @@ export class Chart {
1848
1826
 
1849
1827
  /** 获取内容总宽度(用于外部 scroll-content 撑开 scrollWidth) */
1850
1828
  getContentWidth(): number {
1851
- return computeContentWidth({
1852
- dataLength: this._internalData.length,
1853
- kWidth: this.opt.kWidth,
1854
- kGap: this.opt.kGap,
1855
- viewWidth: this._internalViewport?.plotWidth ?? 0,
1856
- viewportDpr: this.getEffectiveDpr(),
1857
- })
1829
+ const dataLength = this._internalData.length
1830
+ if (dataLength === 0) return 0
1831
+ const kWidth = this.opt.kWidth
1832
+ const kGap = this.opt.kGap
1833
+ const viewWidth = this._internalViewport?.plotWidth ?? 0
1834
+ const dpr = this.getEffectiveDpr()
1835
+ const TRAILING_DRAWING_SLOTS = 24
1836
+ const { startXPx, unitPx } = getPhysicalKLineConfig(kWidth, kGap, dpr)
1837
+ const dataPlotWidth = (startXPx + (dataLength + TRAILING_DRAWING_SLOTS) * unitPx) / dpr
1838
+ return Math.max(dataPlotWidth, viewWidth)
1858
1839
  }
1859
1840
 
1860
1841
 
@@ -1936,8 +1917,6 @@ export class Chart {
1936
1917
  // 清理渲染器插件管理器(会调用所有 onUninstall)
1937
1918
  this.rendererPluginManager.clear()
1938
1919
 
1939
- this.onViewportChange = undefined
1940
- this.onPaneLayoutChange = undefined
1941
1920
  this.indicatorScheduler.destroy()
1942
1921
  await this.pluginHost.destroy()
1943
1922
  }
@@ -2255,7 +2234,18 @@ export class Chart {
2255
2234
 
2256
2235
  this._internalViewport = vp
2257
2236
  if (viewportChanged) {
2258
- this.onViewportChange?.(vp)
2237
+ const current = this._viewportSignal.peek()
2238
+ this._viewportSignal.set({
2239
+ zoomLevel: current.zoomLevel,
2240
+ plotWidth: vp.plotWidth,
2241
+ plotHeight: vp.plotHeight,
2242
+ dpr: vp.dpr > 0 ? vp.dpr : current.dpr,
2243
+ visibleFrom: current.visibleFrom,
2244
+ visibleTo: current.visibleTo,
2245
+ desiredScrollLeft: current.desiredScrollLeft,
2246
+ kWidth: current.kWidth,
2247
+ kGap: current.kGap,
2248
+ })
2259
2249
  }
2260
2250
  return vp
2261
2251
  }
@@ -2280,6 +2270,7 @@ export class Chart {
2280
2270
  private _drawingToolSignal = createSignal<DrawingToolType | null>(null)
2281
2271
  private _drawingsSignal = createSignal<ReadonlyArray<import('../plugin').DrawingObject>>([])
2282
2272
  private _paneRatiosSignal = createSignal<Readonly<Record<string, number>>>({})
2273
+ private _paneLayoutSignal = createSignal<PaneSpec[]>([])
2283
2274
  private _interactionSignal = createSignal<InteractionSnapshot>({
2284
2275
  crosshairPos: null,
2285
2276
  crosshairIndex: null,
@@ -2369,6 +2360,10 @@ export class Chart {
2369
2360
  return this._paneRatiosSignal
2370
2361
  }
2371
2362
 
2363
+ get paneLayout(): Signal<PaneSpec[]> {
2364
+ return this._paneLayoutSignal
2365
+ }
2366
+
2372
2367
  /** 交互状态信号 */
2373
2368
  get interactionState(): Signal<InteractionSnapshot> {
2374
2369
  return this._interactionSignal
@@ -102,10 +102,17 @@ export class InteractionController {
102
102
 
103
103
  constructor(chart: Chart) {
104
104
  this.chart = chart
105
+ this.setupPinchZoom()
105
106
  }
106
107
 
107
- setOnPinchZoom(callback: (delta: number, centerX: number) => void) {
108
- this.pinchTracker.setOnPinchZoom(callback)
108
+ private setupPinchZoom(): void {
109
+ this.pinchTracker.setOnPinchZoom((delta, centerClientX) => {
110
+ const container = this.chart.getDom().container
111
+ if (!container) return
112
+ const rect = container.getBoundingClientRect()
113
+ const centerX = centerClientX - rect.left
114
+ this.chart.handlePinchZoom(delta, centerX)
115
+ })
109
116
  }
110
117
 
111
118
  /** 更新用户设置 */
@@ -2,8 +2,6 @@
2
2
  * 像素对齐工具函数 - 逻辑像素空间(配合 ctx.scale(dpr) 使用)
3
3
  */
4
4
 
5
- import { getColors } from '../theme/colors'
6
-
7
5
  /**
8
6
  * 将逻辑坐标对齐到物理像素边界(用于矩形填充)
9
7
  * @param value - 逻辑坐标值
@@ -1,5 +1,5 @@
1
1
  import type { DrawingObject, DrawingKind, DrawingAnchor, DrawingStyle } from '../../plugin'
2
- import type { Chart } from '../chart'
2
+ import type { DrawingChartAdapter } from '../../controllers/types'
3
3
  import { getPhysicalKLineConfig } from '../utils/klineConfig'
4
4
  import { computeLinearRegression } from './index'
5
5
 
@@ -55,7 +55,7 @@ const LINE_HIT_RADIUS = 6
55
55
  * 封装绘图工具的交互逻辑,与 Vue 组件解耦
56
56
  */
57
57
  export class DrawingInteractionController {
58
- private chart: Chart
58
+ private adapter: DrawingChartAdapter
59
59
  private activeTool: DrawingToolId = 'cursor'
60
60
  private pendingAnchors: DrawingAnchorInput[] = []
61
61
  private drawings: DrawingObject[] = []
@@ -87,8 +87,8 @@ export class DrawingInteractionController {
87
87
  'disjoint-channel',
88
88
  ]
89
89
 
90
- constructor(chart: Chart) {
91
- this.chart = chart
90
+ constructor(adapter: DrawingChartAdapter) {
91
+ this.adapter = adapter
92
92
  }
93
93
 
94
94
  setCallbacks(callbacks: DrawingInteractionCallbacks) {
@@ -114,7 +114,7 @@ export class DrawingInteractionController {
114
114
 
115
115
  setDrawings(drawings: DrawingObject[]) {
116
116
  this.drawings = drawings
117
- this.chart.setDrawings(drawings)
117
+ this.adapter.setDrawings(drawings)
118
118
  }
119
119
 
120
120
  clear() {
@@ -133,7 +133,7 @@ export class DrawingInteractionController {
133
133
  this.drawings = this.drawings.map((d) =>
134
134
  d.id === drawingId ? { ...d, style: { ...d.style, ...style } } : d
135
135
  )
136
- this.chart.setDrawings(this.drawings)
136
+ this.adapter.setDrawings(this.drawings)
137
137
  }
138
138
 
139
139
  removeDrawing(drawingId: string): void {
@@ -141,7 +141,7 @@ export class DrawingInteractionController {
141
141
  if (this.selectedDrawingId === drawingId) {
142
142
  this.setSelected(null)
143
143
  }
144
- this.chart.setDrawings(this.drawings)
144
+ this.adapter.setDrawings(this.drawings)
145
145
  }
146
146
 
147
147
  /**
@@ -287,7 +287,7 @@ export class DrawingInteractionController {
287
287
  }
288
288
  }
289
289
 
290
- this.chart.setDrawings([...this.drawings])
290
+ this.adapter.setDrawings([...this.drawings])
291
291
  return true
292
292
  }
293
293
 
@@ -400,7 +400,7 @@ export class DrawingInteractionController {
400
400
 
401
401
  this.drawings = this.drawings.filter((d) => d.id !== this.previewDrawingId)
402
402
  this.drawings = [...this.drawings, preview]
403
- this.chart.setDrawings(this.drawings)
403
+ this.adapter.setDrawings(this.drawings)
404
404
  return true
405
405
  }
406
406
 
@@ -446,7 +446,7 @@ export class DrawingInteractionController {
446
446
  drawing: DrawingObject,
447
447
  regressionGeometryCache?: Map<string, RegressionChannelGeometry | null>,
448
448
  ): LineSegment[] {
449
- const viewport = this.chart.getViewport()
449
+ const viewport = this.adapter.getViewport()
450
450
  if (!viewport) return []
451
451
 
452
452
  if (drawing.kind === 'regression-channel') {
@@ -458,12 +458,11 @@ export class DrawingInteractionController {
458
458
  const screen = this.anchorToScreen(drawing.anchors[0]!)
459
459
  if (!screen) return []
460
460
 
461
- const paneRenderer = this.chart.getPaneRenderers().find((item) => item.getPane().id === 'main')
462
- const pane = paneRenderer?.getPane()
463
- if (!pane) return []
461
+ const paneInfo = this.adapter.getPaneInfo('main')
462
+ if (!paneInfo) return []
464
463
 
465
464
  const right = viewport.plotWidth
466
- const bottom = pane.height
465
+ const bottom = paneInfo.height
467
466
 
468
467
  switch (drawing.kind) {
469
468
  case 'horizontal-line':
@@ -582,7 +581,7 @@ export class DrawingInteractionController {
582
581
  const cached = regressionGeometryCache?.get(drawing.id)
583
582
  if (cached !== undefined) return cached
584
583
 
585
- const data = this.chart.getData()
584
+ const data = this.adapter.getData()
586
585
  if (data.length === 0 || drawing.anchors.length < 2) {
587
586
  regressionGeometryCache?.set(drawing.id, null)
588
587
  return null
@@ -645,21 +644,17 @@ export class DrawingInteractionController {
645
644
  // ============ 坐标转换 ============
646
645
 
647
646
  private anchorToScreen(anchor: DrawingAnchor): { x: number; y: number } | null {
648
- const viewport = this.chart.getViewport()
647
+ const viewport = this.adapter.getViewport()
649
648
  if (!viewport) return null
650
649
 
651
- const opt = this.chart.getOption()
652
- const dpr = this.chart.getCurrentDpr()
653
- const { startXPx, unitPx } = getPhysicalKLineConfig(opt.kWidth, opt.kGap, dpr)
650
+ const { kWidth, kGap } = this.adapter.getKWidthKGap()
651
+ const dpr = this.adapter.getCurrentDpr()
652
+ const { startXPx, unitPx } = getPhysicalKLineConfig(kWidth, kGap, dpr)
654
653
  if (!Number.isFinite(anchor.index)) return null
655
654
 
656
655
  const x = (startXPx + anchor.index * unitPx + (unitPx - 1) / 2) / dpr - viewport.scrollLeft
657
656
 
658
- const paneRenderer = this.chart.getPaneRenderers().find((item) => item.getPane().id === 'main')
659
- const pane = paneRenderer?.getPane()
660
- if (!pane) return null
661
-
662
- const y = pane.yAxis.priceToY(anchor.price)
657
+ const y = this.adapter.priceToY('main', anchor.price)
663
658
  return { x, y }
664
659
  }
665
660
 
@@ -667,23 +662,22 @@ export class DrawingInteractionController {
667
662
  screenX: number,
668
663
  screenY: number
669
664
  ): DrawingAnchorInput | null {
670
- const data = this.chart.getData()
671
- const viewport = this.chart.getViewport()
665
+ const data = this.adapter.getData()
666
+ const viewport = this.adapter.getViewport()
672
667
  if (!viewport || data.length === 0) return null
673
668
 
674
- const logicalIndex = this.chart.getLogicalIndexAtX(screenX)
669
+ const logicalIndex = this.adapter.getLogicalIndexAtX(screenX)
675
670
  if (logicalIndex === null) return null
676
671
 
677
- const paneRenderer = this.chart.getPaneRenderers().find((item) => item.getPane().id === 'main')
678
- const pane = paneRenderer?.getPane()
679
- if (!pane) return null
672
+ const paneInfo = this.adapter.getPaneInfo('main')
673
+ if (!paneInfo) return null
680
674
 
681
- const timestamp = this.chart.getTimestampAtLogicalIndex(logicalIndex) ?? undefined
675
+ const timestamp = this.adapter.getTimestampAtLogicalIndex(logicalIndex) ?? undefined
682
676
 
683
677
  return {
684
678
  index: logicalIndex,
685
679
  time: timestamp ?? undefined,
686
- price: pane.yAxis.yToPrice(screenY - pane.top),
680
+ price: this.adapter.yToPrice('main', screenY - paneInfo.top),
687
681
  }
688
682
  }
689
683
 
@@ -693,22 +687,22 @@ export class DrawingInteractionController {
693
687
  const newId = drawing?.id ?? null
694
688
  if (this.selectedDrawingId === newId) return
695
689
  this.selectedDrawingId = newId
696
- this.chart.setSelectedDrawingId(newId)
690
+ this.adapter.setSelectedDrawingId(newId)
697
691
  this.callbacks.onDrawingSelected?.(drawing)
698
692
  }
699
693
 
700
694
  private removePreview() {
701
695
  if (!this.drawings.some((d) => d.id === this.previewDrawingId)) return
702
696
  this.drawings = this.drawings.filter((d) => d.id !== this.previewDrawingId)
703
- this.chart.setDrawings(this.drawings)
697
+ this.adapter.setDrawings(this.drawings)
704
698
  }
705
699
 
706
700
  private resolveAnchorFromPointer(
707
701
  e: PointerEvent,
708
702
  container: HTMLElement
709
703
  ): DrawingAnchorInput | null {
710
- const data = this.chart.getData()
711
- const viewport = this.chart.getViewport()
704
+ const data = this.adapter.getData()
705
+ const viewport = this.adapter.getViewport()
712
706
  if (!viewport || data.length === 0) return null
713
707
 
714
708
  const rect = container.getBoundingClientRect()
@@ -718,21 +712,18 @@ export class DrawingInteractionController {
718
712
  return null
719
713
  }
720
714
 
721
- const paneRenderer = this.chart.getPaneRenderers().find((item) => {
722
- const pane = item.getPane()
723
- return pane.id === 'main' && mouseY >= pane.top && mouseY <= pane.top + pane.height
724
- })
725
- const pane = paneRenderer?.getPane()
726
- if (!pane) return null
715
+ const paneInfo = this.adapter.getPaneInfo('main')
716
+ if (!paneInfo) return null
717
+ if (mouseY < paneInfo.top || mouseY > paneInfo.top + paneInfo.height) return null
727
718
 
728
- const logicalIndex = this.chart.getLogicalIndexAtX(mouseX)
719
+ const logicalIndex = this.adapter.getLogicalIndexAtX(mouseX)
729
720
  if (logicalIndex === null) return null
730
- const timestamp = this.chart.getTimestampAtLogicalIndex(logicalIndex) ?? undefined
721
+ const timestamp = this.adapter.getTimestampAtLogicalIndex(logicalIndex) ?? undefined
731
722
 
732
723
  return {
733
724
  index: logicalIndex,
734
725
  time: timestamp ?? undefined,
735
- price: pane.yAxis.yToPrice(mouseY - pane.top),
726
+ price: this.adapter.yToPrice('main', mouseY - paneInfo.top),
736
727
  }
737
728
  }
738
729
 
@@ -754,7 +745,7 @@ export class DrawingInteractionController {
754
745
  }
755
746
 
756
747
  this.drawings = [...this.drawings, drawing]
757
- this.chart.setDrawings(this.drawings)
748
+ this.adapter.setDrawings(this.drawings)
758
749
  this.callbacks.onDrawingCreated?.(drawing)
759
750
  this.activeTool = 'cursor'
760
751
  this.callbacks.onToolChange?.('cursor')
@@ -801,7 +792,7 @@ export class DrawingInteractionController {
801
792
  }
802
793
 
803
794
  this.drawings = [...this.drawings, drawing]
804
- this.chart.setDrawings(this.drawings)
795
+ this.adapter.setDrawings(this.drawings)
805
796
  this.callbacks.onDrawingCreated?.(drawing)
806
797
  this.activeTool = 'cursor'
807
798
  this.callbacks.onToolChange?.('cursor')
@@ -190,7 +190,7 @@ export function createDrawingRendererPlugin(options: {
190
190
  description: '绘图渲染器(仅负责绘制形状)',
191
191
  debugName: '绘图层',
192
192
  paneId: options.paneId ?? 'main',
193
- priority: -25,
193
+ priority: 55,
194
194
  draw(context: RenderContext) {
195
195
  const { ctx, pane, data, range, dpr, paneWidth, kLinePositions, kLineCenters, kBarRects, kWidth, kGap } = context
196
196
  const viewport = context.viewport ?? {
@@ -1,5 +1,6 @@
1
1
  import type { RendererPluginWithHost, RenderContext, PluginHost } from '../../../plugin'
2
2
  import { RENDERER_PRIORITY } from '../../../plugin'
3
+ import { resolveThemeColors } from '../../../tokens'
3
4
  import type { ATRRenderState } from '../../indicators/atrState'
4
5
  import { createATRStateKey } from '../../indicators/atrState'
5
6
  import { Indicator } from '../../indicators/indicatorDefinitionRegistry'
@@ -88,6 +89,8 @@ export function createATRRendererPlugin(options: ATRRendererOptions = {}): Rende
88
89
 
89
90
  draw(context: RenderContext) {
90
91
  const { ctx, pane, range, scrollLeft, kLineCenters, lineWebGLSurface } = context
92
+ const colors = resolveThemeColors(context.theme, context.isAsiaMarket, context.colorPresetSettings)
93
+ const atrColor = colors.palette?.indicatorAtr ?? ATR_COLOR
91
94
 
92
95
  const stateKey = resolveKey()
93
96
  if (!stateKey) return
@@ -147,7 +150,7 @@ export function createATRRendererPlugin(options: ATRRendererOptions = {}): Rende
147
150
  if (enableWebGL && lineWebGLSurface?.isAvailable()) {
148
151
  if (cachedPoints.length >= 2) {
149
152
  const ok = lineWebGLSurface.drawLineStrips(
150
- [{ points: cachedPoints, width: 1, color: ATR_COLOR }],
153
+ [{ points: cachedPoints, width: 1, color: atrColor }],
151
154
  scrollLeft,
152
155
  )
153
156
  if (ok) {
@@ -158,7 +161,7 @@ export function createATRRendererPlugin(options: ATRRendererOptions = {}): Rende
158
161
  }
159
162
 
160
163
  if (!usedWebGL) {
161
- drawWithCanvas2D(ctx, scrollLeft, cachedPoints)
164
+ drawWithCanvas2D(ctx, scrollLeft, cachedPoints, atrColor)
162
165
  }
163
166
  },
164
167
 
@@ -179,11 +182,12 @@ function drawWithCanvas2D(
179
182
  ctx: CanvasRenderingContext2D,
180
183
  scrollLeft: number,
181
184
  points: LinePoint[],
185
+ atrColor: string,
182
186
  ): void {
183
187
  if (points.length < 2) return
184
188
  ctx.save()
185
189
  ctx.translate(-scrollLeft, 0)
186
- ctx.strokeStyle = ATR_COLOR
190
+ ctx.strokeStyle = atrColor
187
191
  ctx.lineWidth = 1
188
192
  ctx.lineJoin = 'round'
189
193
  ctx.lineCap = 'round'