@363045841yyt/klinechart-core 0.9.0-alpha.2 → 0.9.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/controllers/createChartController.d.ts.map +1 -1
- package/dist/controllers/createChartController.js +9 -8
- package/dist/controllers/createChartController.js.map +1 -1
- package/dist/controllers/index.d.ts +1 -0
- package/dist/controllers/index.d.ts.map +1 -1
- package/dist/controllers/index.js.map +1 -1
- package/dist/controllers/types.d.ts +5 -0
- package/dist/controllers/types.d.ts.map +1 -1
- package/dist/data/binance.d.ts +1 -1
- package/dist/data/binance.d.ts.map +1 -1
- package/dist/data/binance.js +1 -1
- package/dist/data/binance.js.map +1 -1
- package/dist/engine/chart.d.ts +9 -9
- package/dist/engine/chart.d.ts.map +1 -1
- package/dist/engine/chart.js +69 -96
- package/dist/engine/chart.js.map +1 -1
- package/dist/engine/chartTypes.d.ts +5 -0
- package/dist/engine/chartTypes.d.ts.map +1 -1
- package/dist/engine/controller/interaction.d.ts +4 -2
- package/dist/engine/controller/interaction.d.ts.map +1 -1
- package/dist/engine/controller/interaction.js +18 -10
- package/dist/engine/controller/interaction.js.map +1 -1
- package/dist/engine/data/chartDataManager.d.ts +12 -18
- package/dist/engine/data/chartDataManager.d.ts.map +1 -1
- package/dist/engine/data/chartDataManager.js +46 -37
- package/dist/engine/data/chartDataManager.js.map +1 -1
- package/dist/engine/data/incrementalLoadHint.d.ts +2 -4
- package/dist/engine/data/incrementalLoadHint.d.ts.map +1 -1
- package/dist/engine/data/incrementalLoadHint.js +5 -2
- package/dist/engine/data/incrementalLoadHint.js.map +1 -1
- package/dist/engine/data/scrollCompensator.d.ts +3 -13
- package/dist/engine/data/scrollCompensator.d.ts.map +1 -1
- package/dist/engine/data/scrollCompensator.js +13 -14
- package/dist/engine/data/scrollCompensator.js.map +1 -1
- package/dist/engine/indicators/chartIndicatorManager.d.ts +16 -17
- package/dist/engine/indicators/chartIndicatorManager.d.ts.map +1 -1
- package/dist/engine/indicators/chartIndicatorManager.js +37 -37
- package/dist/engine/indicators/chartIndicatorManager.js.map +1 -1
- package/dist/engine/layout/chartPaneLayout.d.ts +11 -7
- package/dist/engine/layout/chartPaneLayout.d.ts.map +1 -1
- package/dist/engine/layout/chartPaneLayout.js +58 -16
- package/dist/engine/layout/chartPaneLayout.js.map +1 -1
- package/dist/engine/paneRenderer.d.ts +2 -0
- package/dist/engine/paneRenderer.d.ts.map +1 -1
- package/dist/engine/paneRenderer.js +15 -5
- package/dist/engine/paneRenderer.js.map +1 -1
- package/dist/engine/render/chartRenderer.d.ts +28 -22
- package/dist/engine/render/chartRenderer.d.ts.map +1 -1
- package/dist/engine/render/chartRenderer.js +117 -69
- package/dist/engine/render/chartRenderer.js.map +1 -1
- package/dist/engine/render/layers/leftYAxisLayer.d.ts +9 -2
- package/dist/engine/render/layers/leftYAxisLayer.d.ts.map +1 -1
- package/dist/engine/render/layers/leftYAxisLayer.js +11 -2
- package/dist/engine/render/layers/leftYAxisLayer.js.map +1 -1
- package/dist/engine/render/layers/mainIndicatorLegendLayer.d.ts +6 -4
- package/dist/engine/render/layers/mainIndicatorLegendLayer.d.ts.map +1 -1
- package/dist/engine/render/layers/mainIndicatorLegendLayer.js +6 -9
- package/dist/engine/render/layers/mainIndicatorLegendLayer.js.map +1 -1
- package/dist/engine/render/layers/mainIndicatorLegendLayer.test.d.ts +2 -0
- package/dist/engine/render/layers/mainIndicatorLegendLayer.test.d.ts.map +1 -0
- package/dist/engine/render/layers/mainIndicatorLegendLayer.test.js +19 -0
- package/dist/engine/render/layers/mainIndicatorLegendLayer.test.js.map +1 -0
- package/dist/engine/render/layers/yAxisLayer.d.ts +9 -2
- package/dist/engine/render/layers/yAxisLayer.d.ts.map +1 -1
- package/dist/engine/render/layers/yAxisLayer.js +11 -2
- package/dist/engine/render/layers/yAxisLayer.js.map +1 -1
- package/dist/engine/renderers/Indicator/mainIndicatorLegend.d.ts +7 -3
- package/dist/engine/renderers/Indicator/mainIndicatorLegend.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/mainIndicatorLegend.js +234 -330
- package/dist/engine/renderers/Indicator/mainIndicatorLegend.js.map +1 -1
- package/dist/engine/renderers/Indicator/mainIndicatorLegendContext.d.ts +72 -0
- package/dist/engine/renderers/Indicator/mainIndicatorLegendContext.d.ts.map +1 -0
- package/dist/engine/renderers/Indicator/mainIndicatorLegendContext.js +177 -0
- package/dist/engine/renderers/Indicator/mainIndicatorLegendContext.js.map +1 -0
- package/dist/engine/renderers/leftYAxis.d.ts +15 -2
- package/dist/engine/renderers/leftYAxis.d.ts.map +1 -1
- package/dist/engine/renderers/leftYAxis.js +56 -16
- package/dist/engine/renderers/leftYAxis.js.map +1 -1
- package/dist/engine/renderers/yAxis.d.ts +16 -6
- package/dist/engine/renderers/yAxis.d.ts.map +1 -1
- package/dist/engine/renderers/yAxis.js +49 -16
- package/dist/engine/renderers/yAxis.js.map +1 -1
- package/dist/engine/state/viewportState.d.ts +4 -1
- package/dist/engine/state/viewportState.d.ts.map +1 -1
- package/dist/engine/state/viewportState.js +40 -8
- package/dist/engine/state/viewportState.js.map +1 -1
- package/dist/engine/subPaneManager.d.ts +5 -3
- package/dist/engine/subPaneManager.d.ts.map +1 -1
- package/dist/engine/subPaneManager.js +3 -2
- package/dist/engine/subPaneManager.js.map +1 -1
- package/dist/engine/utils/chartZoomController.d.ts +9 -7
- package/dist/engine/utils/chartZoomController.d.ts.map +1 -1
- package/dist/engine/utils/chartZoomController.js +13 -12
- package/dist/engine/utils/chartZoomController.js.map +1 -1
- package/dist/engine/viewport/chartViewportManager.d.ts +5 -16
- package/dist/engine/viewport/chartViewportManager.d.ts.map +1 -1
- package/dist/engine/viewport/chartViewportManager.js +7 -48
- package/dist/engine/viewport/chartViewportManager.js.map +1 -1
- package/dist/engine/viewport/viewport.d.ts +14 -0
- package/dist/engine/viewport/viewport.d.ts.map +1 -1
- package/dist/engine/viewport/viewport.js +10 -0
- package/dist/engine/viewport/viewport.js.map +1 -1
- package/dist/foundation/plugin/rendererPluginManager.test.js +15 -0
- package/dist/foundation/plugin/rendererPluginManager.test.js.map +1 -1
- package/dist/foundation/plugin/types.d.ts +3 -0
- package/dist/foundation/plugin/types.d.ts.map +1 -1
- package/dist/foundation/plugin/types.js.map +1 -1
- package/dist/foundation/reactivity/frameTransaction.d.ts +11 -0
- package/dist/foundation/reactivity/frameTransaction.d.ts.map +1 -1
- package/dist/foundation/reactivity/frameTransaction.js +17 -2
- package/dist/foundation/reactivity/frameTransaction.js.map +1 -1
- package/dist/rendering/render/Renderer.d.ts +58 -74
- package/dist/rendering/render/Renderer.d.ts.map +1 -1
- package/dist/rendering/render/Renderer.js +8 -18
- package/dist/rendering/render/Renderer.js.map +1 -1
- package/dist/rendering/render/createWebGPURenderer.d.ts.map +1 -1
- package/dist/rendering/render/createWebGPURenderer.js +30 -17
- package/dist/rendering/render/createWebGPURenderer.js.map +1 -1
- package/dist/rendering/render/createWebGPUSurfaceBackend.js +3 -3
- package/dist/rendering/render/createWebGPUSurfaceBackend.js.map +1 -1
- package/dist/rendering/render/physicalLine.d.ts +4 -0
- package/dist/rendering/render/physicalLine.d.ts.map +1 -0
- package/dist/rendering/render/physicalLine.js +37 -0
- package/dist/rendering/render/physicalLine.js.map +1 -0
- package/dist/rendering/render/physicalRegion.d.ts +14 -0
- package/dist/rendering/render/physicalRegion.d.ts.map +1 -0
- package/dist/rendering/render/physicalRegion.js +15 -0
- package/dist/rendering/render/physicalRegion.js.map +1 -0
- package/dist/rendering/scene/createLayerFromPlugin.d.ts.map +1 -1
- package/dist/rendering/scene/createLayerFromPlugin.js +8 -3
- package/dist/rendering/scene/createLayerFromPlugin.js.map +1 -1
- package/dist/rendering/scene/createScene.d.ts.map +1 -1
- package/dist/rendering/scene/createScene.js +4 -3
- package/dist/rendering/scene/createScene.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/src/__tests__/stateKernel.test.ts +1 -0
- package/src/controllers/createChartController.ts +9 -8
- package/src/controllers/index.ts +11 -0
- package/src/controllers/types.ts +7 -0
- package/src/data/binance.ts +1 -1
- package/src/engine/__tests__/chart.dpr.test.ts +3 -2
- package/src/engine/__tests__/paneRenderer.resize.test.ts +52 -54
- package/src/engine/__tests__/subPaneManager.test.ts +5 -3
- package/src/engine/chart.ts +76 -109
- package/src/engine/chartTypes.ts +5 -0
- package/src/engine/controller/__tests__/interaction.dpr.test.ts +39 -2
- package/src/engine/controller/interaction.ts +18 -10
- package/src/engine/data/__tests__/chartDataManager.incrementalLoad.test.ts +37 -17
- package/src/engine/data/__tests__/scrollCompensator.geometry.test.ts +87 -75
- package/src/engine/data/chartDataManager.ts +54 -59
- package/src/engine/data/incrementalLoadHint.ts +8 -7
- package/src/engine/data/scrollCompensator.ts +16 -24
- package/src/engine/indicators/__tests__/chartIndicatorManager.test.ts +18 -26
- package/src/engine/indicators/chartIndicatorManager.ts +62 -62
- package/src/engine/layout/chartPaneLayout.ts +73 -21
- package/src/engine/paneRenderer.ts +17 -10
- package/src/engine/render/chartRenderer.ts +187 -129
- package/src/engine/render/layers/leftYAxisLayer.ts +29 -7
- package/src/engine/render/layers/mainIndicatorLegendLayer.test.ts +26 -0
- package/src/engine/render/layers/mainIndicatorLegendLayer.ts +13 -10
- package/src/engine/render/layers/yAxisLayer.ts +29 -7
- package/src/engine/renderers/Indicator/mainIndicatorLegend.ts +270 -403
- package/src/engine/renderers/Indicator/mainIndicatorLegendContext.ts +282 -0
- package/src/engine/renderers/__tests__/mainIndicatorLegend.renderer.test.ts +73 -2
- package/src/engine/renderers/__tests__/yAxis.renderer.test.ts +10 -6
- package/src/engine/renderers/leftYAxis.ts +60 -18
- package/src/engine/renderers/yAxis.ts +57 -22
- package/src/engine/state/viewportState.ts +44 -8
- package/src/engine/subPaneManager.ts +8 -5
- package/src/engine/utils/chartZoomController.ts +22 -19
- package/src/engine/viewport/__tests__/visibleRange.clamp.test.ts +50 -0
- package/src/engine/viewport/chartViewportManager.ts +9 -60
- package/src/engine/viewport/viewport.ts +14 -0
- package/src/foundation/plugin/rendererPluginManager.test.ts +18 -0
- package/src/foundation/plugin/types.ts +3 -0
- package/src/foundation/reactivity/frameTransaction.ts +20 -6
- package/src/rendering/render/Renderer.ts +69 -85
- package/src/rendering/render/__tests__/physicalLine.test.ts +51 -0
- package/src/rendering/render/__tests__/physicalRegion.test.ts +23 -0
- package/src/rendering/render/__tests__/webgpuRenderer.test.ts +31 -1
- package/src/rendering/render/__tests__/webgpuSurfaceBackend.test.ts +11 -0
- package/src/rendering/render/createWebGPURenderer.ts +30 -17
- package/src/rendering/render/createWebGPUSurfaceBackend.ts +3 -3
- package/src/rendering/render/physicalLine.ts +45 -0
- package/src/rendering/render/physicalRegion.ts +32 -0
- package/src/rendering/scene/createLayerFromPlugin.ts +8 -3
- package/src/rendering/scene/createScene.ts +4 -3
- package/src/version.ts +1 -1
|
@@ -6,12 +6,13 @@ import { TimeShareBuffer } from '../../data/timeShareBuffer'
|
|
|
6
6
|
import type { TimeShareFetcherFn } from '../../data/types'
|
|
7
7
|
import { createSignal, type ReadonlySignal, type Signal } from '../../foundation/reactivity/signal'
|
|
8
8
|
import type { KLineData, TimeShareData } from '../../foundation/types/price'
|
|
9
|
-
import type { ChartDom
|
|
9
|
+
import type { ChartDom } from '../chartTypes'
|
|
10
10
|
import type { VisibleRange, UpdateLevel } from '../layout/pane'
|
|
11
11
|
import { getPhysicalKLineConfig } from '../utils/klineConfig'
|
|
12
|
-
import { getVisibleRange } from '../viewport/viewport'
|
|
13
12
|
import type { DataStateModule } from '../state/dataState'
|
|
14
13
|
import type { DataManagerStateModule } from '../state/dataManagerState'
|
|
14
|
+
import type { ViewportStateModule } from '../state/viewportState'
|
|
15
|
+
import type { ComparisonStateModule } from '../state/comparisonState'
|
|
15
16
|
|
|
16
17
|
import { ComparisonManager } from './comparisonManager'
|
|
17
18
|
import { FetchBatchScheduler } from './fetchBatchScheduler'
|
|
@@ -20,17 +21,11 @@ import { ScrollCompensator } from './scrollCompensator'
|
|
|
20
21
|
|
|
21
22
|
export interface DataDependencies {
|
|
22
23
|
getOption: () => { kWidth: number; kGap: number }
|
|
23
|
-
getEffectiveDpr: () => number
|
|
24
|
-
getLogicalScrollLeft: () => number
|
|
25
|
-
getCachedScrollLeft: () => number
|
|
26
|
-
setScrollLeft: (v: number) => void
|
|
27
24
|
getDom: () => ChartDom
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
getLeftLoadBufferWidth: () => number
|
|
33
|
-
getContentWidth: () => number
|
|
25
|
+
/** scroll / dpr / 可见区间 / 几何 SSOT */
|
|
26
|
+
viewport: ViewportStateModule
|
|
27
|
+
/** 对比叠加状态 SSOT */
|
|
28
|
+
comparison: ComparisonStateModule
|
|
34
29
|
scheduleDraw: (level?: UpdateLevel) => void
|
|
35
30
|
resetInteraction: () => void
|
|
36
31
|
getIndicatorScheduler: () => {
|
|
@@ -40,11 +35,8 @@ export interface DataDependencies {
|
|
|
40
35
|
isPointerDown: () => boolean
|
|
41
36
|
onTimeShareDataReady: (dataLength: number) => void
|
|
42
37
|
onDataProcessed?: (data: KLineData[], range: VisibleRange) => void
|
|
38
|
+
/** 写 symbols 选择(含 primary + comparison) */
|
|
43
39
|
setSymbols: (symbols: ReadonlyArray<SymbolSpec>) => void
|
|
44
|
-
setComparisonLoading: (loading: boolean) => void
|
|
45
|
-
comparisonSpecs$: ReadonlySignal<ReadonlyArray<SymbolSpec>>
|
|
46
|
-
comparisonColors$: ReadonlySignal<ReadonlyMap<string, string>>
|
|
47
|
-
comparisonLoading$: ReadonlySignal<boolean>
|
|
48
40
|
}
|
|
49
41
|
|
|
50
42
|
const BUF_PRIMARY = 'main'
|
|
@@ -95,10 +87,10 @@ export class ChartDataManager {
|
|
|
95
87
|
getKLineBuffer: (key) => this._klineBuffers.get(key),
|
|
96
88
|
getKLineBufferKeys: () => [...this._klineBuffers.keys()],
|
|
97
89
|
scheduleDraw: () => this.deps.scheduleDraw(),
|
|
98
|
-
getSpecs: () => this.deps.
|
|
99
|
-
setLoading: (loading) => this.deps.
|
|
90
|
+
getSpecs: () => this.deps.comparison.readonly.specs.peek(),
|
|
91
|
+
setLoading: (loading) => this.deps.comparison.actions.setLoading(loading),
|
|
100
92
|
})
|
|
101
|
-
this._comparisonSpecsUnsub = this.deps.
|
|
93
|
+
this._comparisonSpecsUnsub = this.deps.comparison.readonly.specs.subscribe(() => {
|
|
102
94
|
this.reconcileComparisonBuffers()
|
|
103
95
|
})
|
|
104
96
|
this.reconcileComparisonBuffers()
|
|
@@ -305,7 +297,7 @@ export class ChartDataManager {
|
|
|
305
297
|
this._dmState.actions.setRangeInitialized(true)
|
|
306
298
|
}
|
|
307
299
|
|
|
308
|
-
let currentRange = this.
|
|
300
|
+
let currentRange = this.getVisibleRangeOrNull()
|
|
309
301
|
if (!currentRange && this._dmState.readonly.rangeInitialized.peek() && bufferData.length > 0) {
|
|
310
302
|
currentRange = { start: 0, end: bufferData.length }
|
|
311
303
|
}
|
|
@@ -325,7 +317,7 @@ export class ChartDataManager {
|
|
|
325
317
|
}
|
|
326
318
|
|
|
327
319
|
private recordIncrementalLoad(prependedCount: number): void {
|
|
328
|
-
this._dmState.actions.recordIncrementalLoad(prependedCount, this.deps.
|
|
320
|
+
this._dmState.actions.recordIncrementalLoad(prependedCount, this.deps.viewport.readonly.leftLoadBufferWidth.peek())
|
|
329
321
|
}
|
|
330
322
|
|
|
331
323
|
private scheduleIncrementalLoadHintFlush(key: string): void {
|
|
@@ -370,7 +362,7 @@ export class ChartDataManager {
|
|
|
370
362
|
// ── Internal helpers ──
|
|
371
363
|
|
|
372
364
|
getLeftLoadBufferWidth(): number {
|
|
373
|
-
return this.deps.
|
|
365
|
+
return this.deps.viewport.readonly.leftLoadBufferWidth.peek()
|
|
374
366
|
}
|
|
375
367
|
|
|
376
368
|
private getActiveKLineLength(): number {
|
|
@@ -378,9 +370,21 @@ export class ChartDataManager {
|
|
|
378
370
|
return buf ? buf.getRawData().length : 0
|
|
379
371
|
}
|
|
380
372
|
|
|
373
|
+
/** 无 viewport / 无数据时返回 null;clamped 可索引区间(start>=0) */
|
|
374
|
+
private getVisibleRangeOrNull(): VisibleRange | null {
|
|
375
|
+
if (this.deps.viewport.readonly.viewWidth.peek() === 0) return null
|
|
376
|
+
return this.deps.viewport.readonly.visibleRange.peek()
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/** raw 可见区间(含左右扩窗,start 可能为 -1);供增量加载左缘检测 */
|
|
380
|
+
private getRawVisibleRangeOrNull(): VisibleRange | null {
|
|
381
|
+
if (this.deps.viewport.readonly.viewWidth.peek() === 0) return null
|
|
382
|
+
return this.deps.viewport.readonly.rawVisibleRange.peek()
|
|
383
|
+
}
|
|
384
|
+
|
|
381
385
|
/** 当前可见范围(on-demand 实时计算,消除 stale 缓存) */
|
|
382
386
|
getCurrentVisibleRange(): VisibleRange | null {
|
|
383
|
-
return this.
|
|
387
|
+
return this.getVisibleRangeOrNull()
|
|
384
388
|
}
|
|
385
389
|
|
|
386
390
|
/** Unified data signal — always reflects the active buffer's data */
|
|
@@ -469,7 +473,7 @@ export class ChartDataManager {
|
|
|
469
473
|
}
|
|
470
474
|
|
|
471
475
|
getComparisonSpecs(): SymbolSpec[] {
|
|
472
|
-
return this.deps.
|
|
476
|
+
return this.deps.comparison.readonly.specs.peek().map((spec) => ({ ...spec }))
|
|
473
477
|
}
|
|
474
478
|
|
|
475
479
|
get dataBuffer(): KLineBuffer {
|
|
@@ -485,15 +489,15 @@ export class ChartDataManager {
|
|
|
485
489
|
}
|
|
486
490
|
|
|
487
491
|
get comparisonColors(): ReadonlySignal<ReadonlyMap<string, string>> {
|
|
488
|
-
return this.deps.
|
|
492
|
+
return this.deps.comparison.readonly.colors
|
|
489
493
|
}
|
|
490
494
|
|
|
491
495
|
get comparisonLoading(): ReadonlySignal<boolean> {
|
|
492
|
-
return this.deps.
|
|
496
|
+
return this.deps.comparison.readonly.loading
|
|
493
497
|
}
|
|
494
498
|
|
|
495
499
|
getComparisonColors(): Map<string, string> {
|
|
496
|
-
return new Map(this.deps.
|
|
500
|
+
return new Map(this.deps.comparison.readonly.colors.peek())
|
|
497
501
|
}
|
|
498
502
|
|
|
499
503
|
// ── Data updates (KLine) ──
|
|
@@ -554,20 +558,22 @@ export class ChartDataManager {
|
|
|
554
558
|
if (data.length === 0) return
|
|
555
559
|
const window = buf.loadedWindow
|
|
556
560
|
if (!window) return
|
|
557
|
-
|
|
558
|
-
|
|
561
|
+
// 左缘扩窗检测必须用 raw(start 可为 -1);数据下标用 clamped
|
|
562
|
+
const rawRange = this.getRawVisibleRangeOrNull()
|
|
563
|
+
const range = this.getVisibleRangeOrNull()
|
|
564
|
+
if (!rawRange || !range) return
|
|
559
565
|
|
|
560
566
|
const MS_PER_DAY = 86_400_000
|
|
561
567
|
const spec = buf.currentSpec
|
|
562
568
|
const gapDays = getPeriodDays(spec?.period)
|
|
563
569
|
let firstVisibleTs: number | undefined
|
|
564
570
|
|
|
565
|
-
if (
|
|
571
|
+
if (rawRange.start < 0 && this._dataFetcher) {
|
|
566
572
|
const earlierThanEarliest = window.earliestTs - gapDays * MS_PER_DAY
|
|
567
573
|
buf.ensureRange(earlierThanEarliest, window.earliestTs)
|
|
568
574
|
firstVisibleTs = data[0]?.timestamp
|
|
569
575
|
} else if (range.start < data.length) {
|
|
570
|
-
firstVisibleTs = data[
|
|
576
|
+
firstVisibleTs = data[range.start]?.timestamp
|
|
571
577
|
if (firstVisibleTs !== undefined && firstVisibleTs < window.earliestTs) {
|
|
572
578
|
buf.ensureRange(firstVisibleTs, window.earliestTs)
|
|
573
579
|
}
|
|
@@ -587,18 +593,18 @@ export class ChartDataManager {
|
|
|
587
593
|
|
|
588
594
|
addComparisonSymbol(spec: SymbolSpec): void {
|
|
589
595
|
const primary = this._dataState.readonly.symbols.peek()[0]
|
|
590
|
-
if (!primary || this.deps.
|
|
596
|
+
if (!primary || this.deps.comparison.readonly.specs.peek().some((item) => item.symbol === spec.symbol))
|
|
591
597
|
return
|
|
592
|
-
this.deps.setSymbols([primary, ...this.deps.
|
|
598
|
+
this.deps.setSymbols([primary, ...this.deps.comparison.readonly.specs.peek(), spec])
|
|
593
599
|
}
|
|
594
600
|
|
|
595
601
|
setComparisonData(symbol: string, data: KLineData[]): void {
|
|
596
602
|
const primary = this._dataState.readonly.symbols.peek()[0]
|
|
597
603
|
if (!primary) return
|
|
598
|
-
if (!this.deps.
|
|
604
|
+
if (!this.deps.comparison.readonly.specs.peek().some((spec) => spec.symbol === symbol)) {
|
|
599
605
|
this.deps.setSymbols([
|
|
600
606
|
primary,
|
|
601
|
-
...this.deps.
|
|
607
|
+
...this.deps.comparison.readonly.specs.peek(),
|
|
602
608
|
{ symbol, period: 'daily' },
|
|
603
609
|
])
|
|
604
610
|
}
|
|
@@ -607,11 +613,11 @@ export class ChartDataManager {
|
|
|
607
613
|
|
|
608
614
|
removeComparisonSymbol(symbol: string): void {
|
|
609
615
|
const primary = this._dataState.readonly.symbols.peek()[0]
|
|
610
|
-
if (!primary || !this.deps.
|
|
616
|
+
if (!primary || !this.deps.comparison.readonly.specs.peek().some((spec) => spec.symbol === symbol))
|
|
611
617
|
return
|
|
612
618
|
this.deps.setSymbols([
|
|
613
619
|
primary,
|
|
614
|
-
...this.deps.
|
|
620
|
+
...this.deps.comparison.readonly.specs.peek().filter((spec) => spec.symbol !== symbol),
|
|
615
621
|
])
|
|
616
622
|
this.deps.scheduleDraw()
|
|
617
623
|
}
|
|
@@ -636,19 +642,8 @@ export class ChartDataManager {
|
|
|
636
642
|
const dataLen = kRaw?.length ?? 0
|
|
637
643
|
let visibleStart = 0
|
|
638
644
|
if (dataLen > 0) {
|
|
639
|
-
const
|
|
640
|
-
|
|
641
|
-
const opt = this.deps.getOption()
|
|
642
|
-
const vRange = getVisibleRange(
|
|
643
|
-
vp.scrollLeft,
|
|
644
|
-
vp.plotWidth,
|
|
645
|
-
opt.kWidth,
|
|
646
|
-
opt.kGap,
|
|
647
|
-
dataLen,
|
|
648
|
-
vp.dpr,
|
|
649
|
-
)
|
|
650
|
-
visibleStart = vRange ? Math.max(0, vRange.start) : 0
|
|
651
|
-
}
|
|
645
|
+
const vRange = this.getVisibleRangeOrNull()
|
|
646
|
+
visibleStart = vRange ? Math.max(0, vRange.start) : 0
|
|
652
647
|
}
|
|
653
648
|
// 双路径守卫:
|
|
654
649
|
// - switchToTimeShareForDate 路径:setTimeShareQueryDate 已在
|
|
@@ -693,7 +688,7 @@ export class ChartDataManager {
|
|
|
693
688
|
return
|
|
694
689
|
}
|
|
695
690
|
const next = { ...current, period }
|
|
696
|
-
this.setSymbols([next, ...this.deps.
|
|
691
|
+
this.setSymbols([next, ...this.deps.comparison.readonly.specs.peek()])
|
|
697
692
|
}
|
|
698
693
|
|
|
699
694
|
/**
|
|
@@ -725,7 +720,7 @@ export class ChartDataManager {
|
|
|
725
720
|
incremental: false,
|
|
726
721
|
source: source.source ?? 'custom',
|
|
727
722
|
}
|
|
728
|
-
this.setSymbols([spec, ...this.deps.
|
|
723
|
+
this.setSymbols([spec, ...this.deps.comparison.readonly.specs.peek()])
|
|
729
724
|
|
|
730
725
|
const symbolCode = spec.symbol
|
|
731
726
|
if (symbolCode) {
|
|
@@ -760,7 +755,7 @@ export class ChartDataManager {
|
|
|
760
755
|
this._dataState.actions.setData([])
|
|
761
756
|
this._dmState.actions.setRangeInitialized(false)
|
|
762
757
|
this._dmState.actions.setSavedScrollTimestamp(null)
|
|
763
|
-
this.setSymbols([spec, ...this.deps.
|
|
758
|
+
this.setSymbols([spec, ...this.deps.comparison.readonly.specs.peek()])
|
|
764
759
|
}
|
|
765
760
|
|
|
766
761
|
getPreCustomSpec(): SymbolSpec | null {
|
|
@@ -872,12 +867,12 @@ export class ChartDataManager {
|
|
|
872
867
|
)
|
|
873
868
|
this._dmState.actions.setSavedScrollTimestamp(null)
|
|
874
869
|
if (idx >= 0) {
|
|
875
|
-
const dpr = this.deps.
|
|
870
|
+
const dpr = this.deps.viewport.readonly.dpr.peek()
|
|
876
871
|
const opt = this.deps.getOption()
|
|
877
872
|
const { unitPx, startXPx } = getPhysicalKLineConfig(opt.kWidth, opt.kGap, dpr)
|
|
878
873
|
const leftBuffer = this.getLeftLoadBufferWidth()
|
|
879
874
|
const scrollLeft = ((idx + 1) * unitPx + startXPx) / dpr + leftBuffer
|
|
880
|
-
this.deps.
|
|
875
|
+
this.deps.viewport.actions.scrollTo(scrollLeft)
|
|
881
876
|
return true
|
|
882
877
|
}
|
|
883
878
|
return false
|
|
@@ -886,7 +881,7 @@ export class ChartDataManager {
|
|
|
886
881
|
// ── Content width ──
|
|
887
882
|
|
|
888
883
|
getContentWidth(): number {
|
|
889
|
-
return this.deps.
|
|
884
|
+
return this.deps.viewport.readonly.contentWidth.peek()
|
|
890
885
|
}
|
|
891
886
|
|
|
892
887
|
scrollToRight(): void {
|
|
@@ -962,12 +957,12 @@ export class ChartDataManager {
|
|
|
962
957
|
}
|
|
963
958
|
|
|
964
959
|
getLogicalIndexAtX(mouseX: number): number | null {
|
|
965
|
-
|
|
966
|
-
|
|
960
|
+
if (this.deps.viewport.readonly.viewWidth.peek() === 0) return null
|
|
961
|
+
const vp = this.deps.viewport.readonly.viewport.peek()
|
|
967
962
|
const buf = this.getActiveDataBuffer()
|
|
968
963
|
const data = buf ? buf.getRawData() : []
|
|
969
964
|
if (data.length === 0) return null
|
|
970
|
-
const dpr = this.deps.
|
|
965
|
+
const dpr = this.deps.viewport.readonly.dpr.peek()
|
|
971
966
|
const opt = this.deps.getOption()
|
|
972
967
|
const { startXPx, unitPx } = getPhysicalKLineConfig(opt.kWidth, opt.kGap, dpr)
|
|
973
968
|
const worldX = Math.round((vp.scrollLeft + mouseX) * dpr)
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import type { ChartDom } from '../chartTypes'
|
|
2
2
|
import { getPhysicalKLineConfig } from '../utils/klineConfig'
|
|
3
|
+
import type { ViewportStateModule } from '../state/viewportState'
|
|
3
4
|
|
|
4
5
|
/** 与 theme selectionFill 对齐:light #2D7FF933 / dark #4A9EFF33;fallback 为 light 默认 */
|
|
5
6
|
const INCREMENTAL_LOAD_HINT_BG = 'var(--klc-color-selection-fill, #2D7FF933)'
|
|
6
7
|
|
|
7
8
|
export interface HintDeps {
|
|
8
9
|
getOption: () => { kWidth: number; kGap: number }
|
|
9
|
-
getEffectiveDpr: () => number
|
|
10
10
|
getDom: () => ChartDom
|
|
11
|
-
|
|
11
|
+
viewport: ViewportStateModule
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
interface ActiveHint {
|
|
@@ -86,17 +86,18 @@ export class IncrementalLoadHint {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
private _updateGeometry(hint: HTMLDivElement, count: number, leftBufferWidth: number): void {
|
|
89
|
-
const dpr = this.deps.
|
|
89
|
+
const dpr = this.deps.viewport.readonly.dpr.peek()
|
|
90
90
|
const opt = this.deps.getOption()
|
|
91
91
|
const { unitPx, startXPx } = getPhysicalKLineConfig(opt.kWidth, opt.kGap, dpr)
|
|
92
92
|
|
|
93
93
|
hint.style.left = `${leftBufferWidth}px`
|
|
94
94
|
const width = (startXPx + count * unitPx) / dpr
|
|
95
95
|
hint.style.width = `${Math.max(0, width)}px`
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
this.deps.
|
|
99
|
-
|
|
96
|
+
const viewHeight =
|
|
97
|
+
this.deps.viewport.readonly.viewHeight.peek() ||
|
|
98
|
+
this.deps.getDom().container?.clientHeight ||
|
|
99
|
+
0
|
|
100
|
+
hint.style.height = `${Math.max(0, viewHeight)}px`
|
|
100
101
|
}
|
|
101
102
|
|
|
102
103
|
private _fadeOutAndRemove(entry: ActiveHint): void {
|
|
@@ -1,17 +1,10 @@
|
|
|
1
|
-
import type { ChartDom, Viewport } from '../chartTypes'
|
|
2
1
|
import { getPhysicalKLineConfig } from '../utils/klineConfig'
|
|
2
|
+
import type { ViewportStateModule } from '../state/viewportState'
|
|
3
3
|
|
|
4
4
|
export interface ScrollDeps {
|
|
5
5
|
getOption: () => { kWidth: number; kGap: number }
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
setScrollLeft: (v: number) => void
|
|
9
|
-
getDom: () => ChartDom
|
|
10
|
-
getObservedSize: () => { width: number; height: number }
|
|
11
|
-
getViewport: () => Viewport | null
|
|
12
|
-
/** 几何 SSOT:由 kernel viewport.readonly 注入 */
|
|
13
|
-
getLeftLoadBufferWidth: () => number
|
|
14
|
-
getContentWidth: () => number
|
|
6
|
+
/** scroll / dpr / 几何 SSOT */
|
|
7
|
+
viewport: ViewportStateModule
|
|
15
8
|
}
|
|
16
9
|
|
|
17
10
|
export const SCROLL_TRAILING_SLOTS = 30
|
|
@@ -20,53 +13,52 @@ export class ScrollCompensator {
|
|
|
20
13
|
constructor(private deps: ScrollDeps) {}
|
|
21
14
|
|
|
22
15
|
compensatePrepend(count: number): void {
|
|
23
|
-
const dpr = this.deps.
|
|
16
|
+
const dpr = this.deps.viewport.readonly.dpr.peek()
|
|
24
17
|
const opt = this.deps.getOption()
|
|
25
18
|
const { unitPx } = getPhysicalKLineConfig(opt.kWidth, opt.kGap, dpr)
|
|
26
19
|
const compensation = (count * unitPx) / dpr
|
|
27
|
-
const nextScrollLeft = this.deps.
|
|
28
|
-
this.deps.
|
|
20
|
+
const nextScrollLeft = this.deps.viewport.readonly.scrollLeft.peek() + compensation
|
|
21
|
+
this.deps.viewport.actions.scrollTo(nextScrollLeft)
|
|
29
22
|
}
|
|
30
23
|
|
|
31
24
|
adjustScrollAfterDataChange(dataLength: number): void {
|
|
32
|
-
const scrollLeft = this.deps.
|
|
25
|
+
const scrollLeft = this.deps.viewport.readonly.scrollLeft.peek()
|
|
33
26
|
if (scrollLeft < 0) return
|
|
34
27
|
|
|
35
28
|
if (scrollLeft <= 0) {
|
|
36
|
-
this.deps.
|
|
29
|
+
this.deps.viewport.actions.scrollTo(this.deps.viewport.readonly.leftLoadBufferWidth.peek())
|
|
37
30
|
return
|
|
38
31
|
}
|
|
39
32
|
|
|
40
|
-
const dpr = this.deps.
|
|
33
|
+
const dpr = this.deps.viewport.readonly.dpr.peek()
|
|
41
34
|
const opt = this.deps.getOption()
|
|
42
35
|
const { unitPx, startXPx } = getPhysicalKLineConfig(opt.kWidth, opt.kGap, dpr)
|
|
43
36
|
const totalDataWidth = (startXPx + dataLength * unitPx) / dpr
|
|
44
|
-
const leftBuffer = this.deps.
|
|
37
|
+
const leftBuffer = this.deps.viewport.readonly.leftLoadBufferWidth.peek()
|
|
45
38
|
if (scrollLeft >= leftBuffer + totalDataWidth) {
|
|
46
|
-
this.deps.
|
|
39
|
+
this.deps.viewport.actions.scrollTo(leftBuffer)
|
|
47
40
|
}
|
|
48
41
|
}
|
|
49
42
|
|
|
50
43
|
scrollToRight(dataLength: number): void {
|
|
51
44
|
if (dataLength === 0) return
|
|
52
|
-
const dpr = this.deps.
|
|
45
|
+
const dpr = this.deps.viewport.readonly.dpr.peek()
|
|
53
46
|
const opt = this.deps.getOption()
|
|
54
47
|
const { unitPx, startXPx } = getPhysicalKLineConfig(opt.kWidth, opt.kGap, dpr)
|
|
55
48
|
const lastKLineEndPx = (startXPx + dataLength * unitPx) / dpr
|
|
56
|
-
const
|
|
57
|
-
const clientWidth = viewport?.viewWidth ?? 0
|
|
49
|
+
const clientWidth = this.deps.viewport.readonly.viewWidth.peek()
|
|
58
50
|
if (clientWidth <= 0) return
|
|
59
51
|
|
|
60
|
-
const leftBuffer = this.deps.
|
|
52
|
+
const leftBuffer = this.deps.viewport.readonly.leftLoadBufferWidth.peek()
|
|
61
53
|
let target: number
|
|
62
54
|
if (lastKLineEndPx <= clientWidth) {
|
|
63
55
|
target = leftBuffer - (clientWidth - lastKLineEndPx)
|
|
64
56
|
} else {
|
|
65
57
|
target = leftBuffer + (lastKLineEndPx - clientWidth)
|
|
66
58
|
}
|
|
67
|
-
const contentWidth = this.deps.
|
|
59
|
+
const contentWidth = this.deps.viewport.readonly.contentWidth.peek()
|
|
68
60
|
const maxScroll = Math.max(0, contentWidth - clientWidth)
|
|
69
61
|
const scrollLeft = Math.round(Math.max(0, Math.min(target, maxScroll)) * dpr) / dpr
|
|
70
|
-
this.deps.
|
|
62
|
+
this.deps.viewport.actions.scrollTo(scrollLeft)
|
|
71
63
|
}
|
|
72
64
|
}
|
|
@@ -52,7 +52,7 @@ function createMockDeps() {
|
|
|
52
52
|
upsertPane: vi.fn(),
|
|
53
53
|
removePaneDefinition: vi.fn(),
|
|
54
54
|
getPaneSpecs: vi.fn(() => []),
|
|
55
|
-
|
|
55
|
+
paneRatios$: paneRatiosSignal,
|
|
56
56
|
paneSpecs$: paneSpecsSignal,
|
|
57
57
|
getInternalPaneRatios: vi.fn(() => new Map()),
|
|
58
58
|
setInternalPaneRatio: vi.fn(),
|
|
@@ -68,30 +68,22 @@ function createMockDeps() {
|
|
|
68
68
|
removeLayer: vi.fn(() => false),
|
|
69
69
|
getLayer: vi.fn(() => null),
|
|
70
70
|
setLayerVisibility: vi.fn(),
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
),
|
|
85
|
-
updateSubPaneStateParams: vi.fn((paneId, params) =>
|
|
86
|
-
subPaneState.actions.setParams(paneId, params),
|
|
87
|
-
),
|
|
88
|
-
clearSubPaneState: vi.fn(() => subPaneState.actions.clear()),
|
|
71
|
+
indicator: indicatorState,
|
|
72
|
+
subPaneOps: {
|
|
73
|
+
entries: subPaneState.readonly.entries,
|
|
74
|
+
create: vi.fn((paneId, indicatorId, params) =>
|
|
75
|
+
subPaneState.actions.upsert({ paneId, indicatorId, params }),
|
|
76
|
+
),
|
|
77
|
+
remove: vi.fn((paneId) => subPaneState.actions.remove(paneId)),
|
|
78
|
+
replace: vi.fn((paneId, indicatorId, params) =>
|
|
79
|
+
subPaneState.actions.replace({ paneId, indicatorId, params }),
|
|
80
|
+
),
|
|
81
|
+
setParams: vi.fn((paneId, params) => subPaneState.actions.setParams(paneId, params)),
|
|
82
|
+
clear: vi.fn(() => subPaneState.actions.clear()),
|
|
83
|
+
},
|
|
89
84
|
projectPaneLayout: vi.fn(),
|
|
90
85
|
runRendererTransaction: (run) => run(),
|
|
91
86
|
getIndicatorScheduler: vi.fn(),
|
|
92
|
-
getRightAxisWidth: () => 60,
|
|
93
|
-
getPriceLabelWidth: () => 60,
|
|
94
|
-
getYPaddingPx: () => 4,
|
|
95
87
|
} as IndicatorDependencies & { rendererMap: Map<string, any> }
|
|
96
88
|
}
|
|
97
89
|
|
|
@@ -169,9 +161,9 @@ describe('ChartIndicatorManager', () => {
|
|
|
169
161
|
it('creates sub-pane business state before projecting runtime resources', () => {
|
|
170
162
|
expect(manager.createSubPane('RSI_0', 'RSI', { period1: 6 })).toBe(true)
|
|
171
163
|
|
|
172
|
-
expect(deps.
|
|
164
|
+
expect(deps.subPaneOps.create).toHaveBeenCalledTimes(1)
|
|
173
165
|
expect(deps.useRenderer).toHaveBeenCalled()
|
|
174
|
-
expect(deps.
|
|
166
|
+
expect(deps.subPaneOps.create.mock.invocationCallOrder[0]).toBeLessThan(
|
|
175
167
|
deps.useRenderer.mock.invocationCallOrder[0]!,
|
|
176
168
|
)
|
|
177
169
|
expect(manager.getSubPaneEntry('RSI_0')?.params).toEqual({ period1: 6 })
|
|
@@ -183,7 +175,7 @@ describe('ChartIndicatorManager', () => {
|
|
|
183
175
|
|
|
184
176
|
expect(manager.createSubPane('RSI_0', 'MACD', { fast: 5 })).toBe(true)
|
|
185
177
|
|
|
186
|
-
expect(deps.
|
|
178
|
+
expect(deps.subPaneOps.replace).not.toHaveBeenCalled()
|
|
187
179
|
expect(manager.getSubPaneEntry('RSI_0')?.indicatorId).toBe('RSI')
|
|
188
180
|
expect(manager.getSubPaneEntry('RSI_0')?.params).toEqual({ period1: 6 })
|
|
189
181
|
})
|
|
@@ -213,7 +205,7 @@ describe('ChartIndicatorManager', () => {
|
|
|
213
205
|
manager.destroy()
|
|
214
206
|
vi.clearAllMocks()
|
|
215
207
|
|
|
216
|
-
deps.
|
|
208
|
+
deps.indicator.actions.upsert('MA', { ma5: true })
|
|
217
209
|
|
|
218
210
|
expect(deps.useRenderer).not.toHaveBeenCalled()
|
|
219
211
|
expect(deps.scheduleDraw).not.toHaveBeenCalled()
|