@363045841yyt/klinechart-core 0.9.0-alpha.2 → 0.9.0-alpha.4
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/data/timeShareBuffer.d.ts +3 -0
- package/dist/data/timeShareBuffer.d.ts.map +1 -1
- package/dist/data/timeShareBuffer.js +13 -0
- package/dist/data/timeShareBuffer.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 +87 -101
- 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 +14 -18
- package/dist/engine/data/chartDataManager.d.ts.map +1 -1
- package/dist/engine/data/chartDataManager.js +55 -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/modes/timeShareMath.d.ts +56 -0
- package/dist/engine/modes/timeShareMath.d.ts.map +1 -0
- package/dist/engine/modes/timeShareMath.js +90 -0
- package/dist/engine/modes/timeShareMath.js.map +1 -0
- package/dist/engine/modes/timeShareMode.d.ts +5 -0
- package/dist/engine/modes/timeShareMode.d.ts.map +1 -1
- package/dist/engine/modes/timeShareMode.js +27 -27
- package/dist/engine/modes/timeShareMode.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 +143 -85
- 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 +73 -0
- package/dist/engine/renderers/Indicator/mainIndicatorLegendContext.d.ts.map +1 -0
- package/dist/engine/renderers/Indicator/mainIndicatorLegendContext.js +182 -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/timeShare.d.ts.map +1 -1
- package/dist/engine/renderers/timeShare.js +20 -9
- package/dist/engine/renderers/timeShare.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/config/chartSettings.d.ts +0 -5
- package/dist/foundation/config/chartSettings.d.ts.map +1 -1
- package/dist/foundation/config/chartSettings.js +14 -0
- package/dist/foundation/config/chartSettings.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/foundation/utils/kLineDraw/axis.d.ts +3 -0
- package/dist/foundation/utils/kLineDraw/axis.d.ts.map +1 -1
- package/dist/foundation/utils/kLineDraw/axis.js +40 -9
- package/dist/foundation/utils/kLineDraw/axis.js.map +1 -1
- package/dist/foundation/utils/sessionTimeLabels.d.ts +59 -0
- package/dist/foundation/utils/sessionTimeLabels.d.ts.map +1 -0
- package/dist/foundation/utils/sessionTimeLabels.js +170 -0
- package/dist/foundation/utils/sessionTimeLabels.js.map +1 -0
- package/dist/foundation/utils/timeShareAxisLabels.d.ts +27 -0
- package/dist/foundation/utils/timeShareAxisLabels.d.ts.map +1 -0
- package/dist/foundation/utils/timeShareAxisLabels.js +45 -0
- package/dist/foundation/utils/timeShareAxisLabels.js.map +1 -0
- 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/__tests__/timeShareBuffer.test.ts +45 -0
- package/src/data/binance.ts +1 -1
- package/src/data/timeShareBuffer.ts +15 -0
- package/src/engine/__tests__/chart.dpr.test.ts +31 -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 +105 -115
- 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 +64 -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/modes/__tests__/timeShareMath.test.ts +185 -0
- package/src/engine/modes/__tests__/timeShareMode.test.ts +81 -0
- package/src/engine/modes/timeShareMath.ts +150 -0
- package/src/engine/modes/timeShareMode.ts +35 -28
- package/src/engine/paneRenderer.ts +17 -10
- package/src/engine/render/chartRenderer.ts +214 -145
- 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 +290 -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/timeShare.ts +25 -9
- package/src/engine/renderers/yAxis.ts +57 -22
- package/src/engine/state/__tests__/settingsState.test.ts +9 -0
- 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/config/chartSettings.ts +13 -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/foundation/utils/__tests__/sessionTimeLabels.test.ts +91 -0
- package/src/foundation/utils/kLineDraw/axis.ts +50 -9
- package/src/foundation/utils/sessionTimeLabels.ts +237 -0
- package/src/foundation/utils/timeShareAxisLabels.ts +94 -0
- 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
|
@@ -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()
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
type ReadonlySignal,
|
|
12
12
|
type Computed,
|
|
13
13
|
} from '../../foundation/reactivity/signal'
|
|
14
|
-
import type { MainIndicatorEntry } from '../state/indicatorState'
|
|
14
|
+
import type { IndicatorStateModule, MainIndicatorEntry } from '../state/indicatorState'
|
|
15
15
|
import type { SubPaneSpec } from '../state/subPaneState'
|
|
16
16
|
import type { Layer } from '../../rendering/scene/types'
|
|
17
17
|
import type { KLineData } from '../../foundation/types/price'
|
|
@@ -47,6 +47,24 @@ function mainIndicatorProjectionKey(
|
|
|
47
47
|
.join('|')
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
/** 副图业务操作:create/remove/clear 会联动 pane 布局,不能只写 subPane 模块 */
|
|
51
|
+
export interface SubPaneOps {
|
|
52
|
+
readonly entries: ReadonlySignal<ReadonlyArray<SubPaneSpec>>
|
|
53
|
+
create: (
|
|
54
|
+
paneId: string,
|
|
55
|
+
indicatorId: string,
|
|
56
|
+
params: Readonly<Record<string, unknown>>,
|
|
57
|
+
) => void
|
|
58
|
+
remove: (paneId: string) => void
|
|
59
|
+
replace: (
|
|
60
|
+
paneId: string,
|
|
61
|
+
indicatorId: string,
|
|
62
|
+
params: Readonly<Record<string, unknown>>,
|
|
63
|
+
) => void
|
|
64
|
+
setParams: (paneId: string, params: Readonly<Record<string, unknown>>) => void
|
|
65
|
+
clear: () => void
|
|
66
|
+
}
|
|
67
|
+
|
|
50
68
|
export interface IndicatorDependencies {
|
|
51
69
|
getOption: () => ResolvedChartOptions
|
|
52
70
|
getPluginHost: () => PluginHostImpl
|
|
@@ -58,7 +76,8 @@ export interface IndicatorDependencies {
|
|
|
58
76
|
removeRenderer: (name: string) => void
|
|
59
77
|
updateRendererConfig: (name: string, config: Record<string, unknown>) => void
|
|
60
78
|
setRendererEnabled: (name: string, enabled: boolean) => void
|
|
61
|
-
|
|
79
|
+
/** pane ratios SSOT */
|
|
80
|
+
paneRatios$: ReadonlySignal<Readonly<Record<string, number>>>
|
|
62
81
|
paneSpecs$: ReadonlySignal<ReadonlyArray<PaneSpec>>
|
|
63
82
|
projectPaneLayout: (
|
|
64
83
|
specs: ReadonlyArray<PaneSpec>,
|
|
@@ -74,29 +93,10 @@ export interface IndicatorDependencies {
|
|
|
74
93
|
removeLayer: (id: string) => boolean
|
|
75
94
|
getLayer: (id: string) => Layer | null
|
|
76
95
|
setLayerVisibility: (id: string, visible: boolean) => void
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
upsertMainIndicator: (id: string, params: Record<string, number | boolean | string>) => void
|
|
82
|
-
removeMainIndicator: (id: string) => void
|
|
83
|
-
setMainIndicatorParams: (id: string, params: Record<string, number | boolean | string>) => void
|
|
84
|
-
replaceMainIndicators: (entries: ReadonlyMap<string, MainIndicatorEntry>) => void
|
|
85
|
-
clearMainIndicators: () => void
|
|
86
|
-
subPanes$: ReadonlySignal<ReadonlyArray<SubPaneSpec>>
|
|
87
|
-
createSubPaneState: (
|
|
88
|
-
paneId: string,
|
|
89
|
-
indicatorId: string,
|
|
90
|
-
params: Readonly<Record<string, unknown>>,
|
|
91
|
-
) => void
|
|
92
|
-
removeSubPaneState: (paneId: string) => void
|
|
93
|
-
replaceSubPaneState: (
|
|
94
|
-
paneId: string,
|
|
95
|
-
indicatorId: string,
|
|
96
|
-
params: Readonly<Record<string, unknown>>,
|
|
97
|
-
) => void
|
|
98
|
-
updateSubPaneStateParams: (paneId: string, params: Readonly<Record<string, unknown>>) => void
|
|
99
|
-
clearSubPaneState: () => void
|
|
96
|
+
/** 主图指标状态模块 */
|
|
97
|
+
indicator: IndicatorStateModule
|
|
98
|
+
/** 副图状态 + 联动 pane 布局的复合操作 */
|
|
99
|
+
subPaneOps: SubPaneOps
|
|
100
100
|
runRendererTransaction: (run: () => void) => void
|
|
101
101
|
}
|
|
102
102
|
|
|
@@ -169,12 +169,12 @@ export class ChartIndicatorManager {
|
|
|
169
169
|
|
|
170
170
|
// 注册副图活跃列表提供者
|
|
171
171
|
this.indicatorScheduler.setActiveSubPaneProvider(() =>
|
|
172
|
-
this.deps.
|
|
172
|
+
this.deps.subPaneOps.entries.peek().map((entry) => entry.paneId),
|
|
173
173
|
)
|
|
174
174
|
|
|
175
175
|
// 派生信号
|
|
176
176
|
this._indicatorsComputed = computed<ReadonlyArray<IndicatorInstance>>(() => {
|
|
177
|
-
const mainIndicators: IndicatorInstance[] = [...this.deps.mainIndicators
|
|
177
|
+
const mainIndicators: IndicatorInstance[] = [...this.deps.indicator.readonly.mainIndicators().entries()].map(
|
|
178
178
|
([id, entry]) => ({
|
|
179
179
|
id,
|
|
180
180
|
definitionId: id,
|
|
@@ -185,7 +185,7 @@ export class ChartIndicatorManager {
|
|
|
185
185
|
}),
|
|
186
186
|
)
|
|
187
187
|
|
|
188
|
-
const subIndicators: IndicatorInstance[] = this.deps.
|
|
188
|
+
const subIndicators: IndicatorInstance[] = this.deps.subPaneOps.entries().map((entry) => ({
|
|
189
189
|
id: entry.paneId,
|
|
190
190
|
definitionId: entry.indicatorId,
|
|
191
191
|
label: entry.indicatorId,
|
|
@@ -198,8 +198,8 @@ export class ChartIndicatorManager {
|
|
|
198
198
|
return [...mainIndicators, ...subIndicators]
|
|
199
199
|
})
|
|
200
200
|
this._subPanesComputed = computed<ReadonlyArray<SubPaneInfo>>(() => {
|
|
201
|
-
const ratios = deps.
|
|
202
|
-
return this.deps.
|
|
201
|
+
const ratios = deps.paneRatios$()
|
|
202
|
+
return this.deps.subPaneOps.entries().map((entry) => ({
|
|
203
203
|
paneId: entry.paneId,
|
|
204
204
|
indicatorId: entry.indicatorId,
|
|
205
205
|
params: { ...entry.params },
|
|
@@ -220,12 +220,12 @@ export class ChartIndicatorManager {
|
|
|
220
220
|
}
|
|
221
221
|
|
|
222
222
|
this.projectedPaneSpecs = this.deps.paneSpecs$.peek()
|
|
223
|
-
this.projectedPaneRatios = this.deps.
|
|
223
|
+
this.projectedPaneRatios = this.deps.paneRatios$.peek()
|
|
224
224
|
this.disposeProjection = effect(() => {
|
|
225
225
|
const paneSpecs = this.deps.paneSpecs$()
|
|
226
|
-
const paneRatios = this.deps.
|
|
227
|
-
const mainIndicators = this.deps.mainIndicators
|
|
228
|
-
const subPanes = this.deps.
|
|
226
|
+
const paneRatios = this.deps.paneRatios$()
|
|
227
|
+
const mainIndicators = this.deps.indicator.readonly.mainIndicators()
|
|
228
|
+
const subPanes = this.deps.subPaneOps.entries()
|
|
229
229
|
this.deps.runRendererTransaction(() => {
|
|
230
230
|
let paneChanged = false
|
|
231
231
|
if (paneSpecs !== this.projectedPaneSpecs || paneRatios !== this.projectedPaneRatios) {
|
|
@@ -250,7 +250,7 @@ export class ChartIndicatorManager {
|
|
|
250
250
|
}
|
|
251
251
|
|
|
252
252
|
get mainIndicatorsSignalPeek(): ReadonlyMap<string, MainIndicatorEntry> {
|
|
253
|
-
return this.deps.mainIndicators
|
|
253
|
+
return this.deps.indicator.readonly.mainIndicators.peek()
|
|
254
254
|
}
|
|
255
255
|
|
|
256
256
|
get indicatorsComputed(): Computed<ReadonlyArray<IndicatorInstance>> {
|
|
@@ -273,26 +273,26 @@ export class ChartIndicatorManager {
|
|
|
273
273
|
return false
|
|
274
274
|
}
|
|
275
275
|
|
|
276
|
-
const existing = this.deps.mainIndicators
|
|
276
|
+
const existing = this.deps.indicator.readonly.mainIndicators.peek().get(id)
|
|
277
277
|
|
|
278
278
|
if (existing) {
|
|
279
279
|
if (params) {
|
|
280
|
-
this.deps.
|
|
280
|
+
this.deps.indicator.actions.upsert(id, params)
|
|
281
281
|
}
|
|
282
282
|
return true
|
|
283
283
|
}
|
|
284
284
|
|
|
285
285
|
const defaults = ChartIndicatorManager.DEFAULT_MAIN_PARAMS[id] ?? {}
|
|
286
286
|
const merged = params ? { ...defaults, ...params } : defaults
|
|
287
|
-
this.deps.
|
|
287
|
+
this.deps.indicator.actions.upsert(id, merged)
|
|
288
288
|
return true
|
|
289
289
|
}
|
|
290
290
|
|
|
291
291
|
disableMainIndicator(indicatorId: string): boolean {
|
|
292
292
|
const id = indicatorId.toUpperCase()
|
|
293
|
-
if (!this.deps.mainIndicators
|
|
293
|
+
if (!this.deps.indicator.readonly.mainIndicators.peek().has(id)) return false
|
|
294
294
|
|
|
295
|
-
this.deps.
|
|
295
|
+
this.deps.indicator.actions.remove(id)
|
|
296
296
|
return true
|
|
297
297
|
}
|
|
298
298
|
|
|
@@ -305,11 +305,11 @@ export class ChartIndicatorManager {
|
|
|
305
305
|
}
|
|
306
306
|
|
|
307
307
|
getActiveMainIndicators(): string[] {
|
|
308
|
-
return [...this.deps.mainIndicators
|
|
308
|
+
return [...this.deps.indicator.readonly.mainIndicators.peek().keys()]
|
|
309
309
|
}
|
|
310
310
|
|
|
311
311
|
isMainIndicatorActive(indicatorId: string): boolean {
|
|
312
|
-
return this.deps.mainIndicators
|
|
312
|
+
return this.deps.indicator.readonly.mainIndicators.peek().has(indicatorId.toUpperCase())
|
|
313
313
|
}
|
|
314
314
|
|
|
315
315
|
updateMainIndicatorParams(
|
|
@@ -317,18 +317,18 @@ export class ChartIndicatorManager {
|
|
|
317
317
|
params: Record<string, number | boolean | string>,
|
|
318
318
|
): void {
|
|
319
319
|
const id = indicatorId.toUpperCase()
|
|
320
|
-
if (!this.deps.mainIndicators
|
|
320
|
+
if (!this.deps.indicator.readonly.mainIndicators.peek().has(id)) return
|
|
321
321
|
|
|
322
|
-
this.deps.
|
|
322
|
+
this.deps.indicator.actions.setParams(id, params)
|
|
323
323
|
}
|
|
324
324
|
|
|
325
325
|
getMainIndicatorParams(indicatorId: string): Record<string, number | boolean | string> | null {
|
|
326
|
-
const params = this.deps.mainIndicators
|
|
326
|
+
const params = this.deps.indicator.readonly.mainIndicators.peek().get(indicatorId.toUpperCase())?.params
|
|
327
327
|
return params ? { ...params } : null
|
|
328
328
|
}
|
|
329
329
|
|
|
330
330
|
clearMainIndicators(): void {
|
|
331
|
-
this.deps.
|
|
331
|
+
this.deps.indicator.actions.clear()
|
|
332
332
|
}
|
|
333
333
|
|
|
334
334
|
private reconcileMainIndicators(desired: ReadonlyMap<string, MainIndicatorEntry>): boolean {
|
|
@@ -397,7 +397,7 @@ export class ChartIndicatorManager {
|
|
|
397
397
|
}
|
|
398
398
|
|
|
399
399
|
private updateIndicatorSchedulerConfig(indicatorId: string): void {
|
|
400
|
-
const entry = this.deps.mainIndicators
|
|
400
|
+
const entry = this.deps.indicator.readonly.mainIndicators.peek().get(indicatorId)
|
|
401
401
|
const isActive = entry !== undefined
|
|
402
402
|
const params = entry?.params ?? {}
|
|
403
403
|
|
|
@@ -419,7 +419,7 @@ export class ChartIndicatorManager {
|
|
|
419
419
|
const newIds = indicators
|
|
420
420
|
.map((i) => i.toUpperCase())
|
|
421
421
|
.filter((id) => ChartIndicatorManager.ENABLE_MAIN_INDICATORS.includes(id))
|
|
422
|
-
const prev = this.deps.mainIndicators
|
|
422
|
+
const prev = this.deps.indicator.readonly.mainIndicators.peek()
|
|
423
423
|
|
|
424
424
|
const next = new Map<string, MainIndicatorEntry>()
|
|
425
425
|
for (const id of newIds) {
|
|
@@ -432,7 +432,7 @@ export class ChartIndicatorManager {
|
|
|
432
432
|
})
|
|
433
433
|
}
|
|
434
434
|
}
|
|
435
|
-
this.deps.
|
|
435
|
+
this.deps.indicator.actions.replaceAll(next)
|
|
436
436
|
}
|
|
437
437
|
|
|
438
438
|
// ========== 副图管理 API ==========
|
|
@@ -446,7 +446,7 @@ export class ChartIndicatorManager {
|
|
|
446
446
|
if (!definition) {
|
|
447
447
|
throw new KLineChartError('NOT_REGISTERED', `[Chart] Unknown indicator: ${indicatorId}`)
|
|
448
448
|
}
|
|
449
|
-
this.deps.
|
|
449
|
+
this.deps.subPaneOps.create(
|
|
450
450
|
paneId,
|
|
451
451
|
indicatorId,
|
|
452
452
|
params ?? this.getDefaultSubPaneParams(indicatorId),
|
|
@@ -458,13 +458,13 @@ export class ChartIndicatorManager {
|
|
|
458
458
|
indicatorId: SubIndicatorType,
|
|
459
459
|
params?: Record<string, number | boolean | string>,
|
|
460
460
|
): boolean {
|
|
461
|
-
const existing = this.deps.
|
|
461
|
+
const existing = this.deps.subPaneOps.entries.peek().find((entry) => entry.paneId === paneId)
|
|
462
462
|
if (existing) {
|
|
463
463
|
if (
|
|
464
464
|
existing.indicatorId === indicatorId &&
|
|
465
465
|
!this.subPaneManager.getMountedResources(paneId)
|
|
466
466
|
) {
|
|
467
|
-
this.deps.
|
|
467
|
+
this.deps.subPaneOps.replace(
|
|
468
468
|
paneId,
|
|
469
469
|
existing.indicatorId,
|
|
470
470
|
existing.params,
|
|
@@ -475,7 +475,7 @@ export class ChartIndicatorManager {
|
|
|
475
475
|
if (!this.indicatorScheduler.getIndicatorMetadata(indicatorId)) {
|
|
476
476
|
throw new KLineChartError('NOT_REGISTERED', `[Chart] Unknown indicator: ${indicatorId}`)
|
|
477
477
|
}
|
|
478
|
-
this.deps.
|
|
478
|
+
this.deps.subPaneOps.create(
|
|
479
479
|
paneId,
|
|
480
480
|
indicatorId,
|
|
481
481
|
params ?? this.getDefaultSubPaneParams(indicatorId),
|
|
@@ -484,7 +484,7 @@ export class ChartIndicatorManager {
|
|
|
484
484
|
}
|
|
485
485
|
|
|
486
486
|
removeSubPane(paneId: string): void {
|
|
487
|
-
this.deps.
|
|
487
|
+
this.deps.subPaneOps.remove(paneId)
|
|
488
488
|
}
|
|
489
489
|
|
|
490
490
|
replaceSubPaneIndicator(
|
|
@@ -495,7 +495,7 @@ export class ChartIndicatorManager {
|
|
|
495
495
|
if (!this.indicatorScheduler.getIndicatorMetadata(newIndicatorId)) {
|
|
496
496
|
throw new KLineChartError('NOT_REGISTERED', `[Chart] Unknown indicator: ${newIndicatorId}`)
|
|
497
497
|
}
|
|
498
|
-
this.deps.
|
|
498
|
+
this.deps.subPaneOps.replace(
|
|
499
499
|
paneId,
|
|
500
500
|
newIndicatorId,
|
|
501
501
|
params ?? this.getDefaultSubPaneParams(newIndicatorId),
|
|
@@ -503,22 +503,22 @@ export class ChartIndicatorManager {
|
|
|
503
503
|
}
|
|
504
504
|
|
|
505
505
|
updateSubPaneParams(paneId: string, params: Record<string, unknown>): void {
|
|
506
|
-
this.deps.
|
|
506
|
+
this.deps.subPaneOps.setParams(paneId, params)
|
|
507
507
|
}
|
|
508
508
|
|
|
509
509
|
clearSubPanes(): void {
|
|
510
|
-
this.deps.
|
|
510
|
+
this.deps.subPaneOps.clear()
|
|
511
511
|
}
|
|
512
512
|
|
|
513
513
|
/**
|
|
514
514
|
* @deprecated 使用 getSubPaneEntries 获取完整信息
|
|
515
515
|
*/
|
|
516
516
|
getSubPaneIndicators(): SubIndicatorType[] {
|
|
517
|
-
return this.deps.
|
|
517
|
+
return this.deps.subPaneOps.entries.peek().map((entry) => entry.indicatorId)
|
|
518
518
|
}
|
|
519
519
|
|
|
520
520
|
getSubPaneEntries(): SubPaneEntry[] {
|
|
521
|
-
return this.deps.
|
|
521
|
+
return this.deps.subPaneOps.entries.peek().map((entry) => ({
|
|
522
522
|
...entry,
|
|
523
523
|
params: { ...entry.params },
|
|
524
524
|
...this.subPaneManager.getMountedResources(entry.paneId),
|
|
@@ -526,7 +526,7 @@ export class ChartIndicatorManager {
|
|
|
526
526
|
}
|
|
527
527
|
|
|
528
528
|
getSubPaneEntry(paneId: string): SubPaneEntry | undefined {
|
|
529
|
-
const entry = this.deps.
|
|
529
|
+
const entry = this.deps.subPaneOps.entries.peek().find((candidate) => candidate.paneId === paneId)
|
|
530
530
|
if (!entry) return undefined
|
|
531
531
|
return {
|
|
532
532
|
...entry,
|
|
@@ -569,7 +569,7 @@ export class ChartIndicatorManager {
|
|
|
569
569
|
removeIndicator(instanceId: string): boolean {
|
|
570
570
|
const id = instanceId.toUpperCase()
|
|
571
571
|
|
|
572
|
-
if (this.deps.mainIndicators
|
|
572
|
+
if (this.deps.indicator.readonly.mainIndicators.peek().has(id)) {
|
|
573
573
|
return this.disableMainIndicator(instanceId)
|
|
574
574
|
}
|
|
575
575
|
|
|
@@ -585,7 +585,7 @@ export class ChartIndicatorManager {
|
|
|
585
585
|
updateIndicatorParams(instanceId: string, params: Record<string, unknown>): boolean {
|
|
586
586
|
const id = instanceId.toUpperCase()
|
|
587
587
|
|
|
588
|
-
if (this.deps.mainIndicators
|
|
588
|
+
if (this.deps.indicator.readonly.mainIndicators.peek().has(id)) {
|
|
589
589
|
this.updateMainIndicatorParams(
|
|
590
590
|
instanceId,
|
|
591
591
|
params as Record<string, number | boolean | string>,
|