@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
|
@@ -4,56 +4,58 @@ import { describe, expect, it } from 'vitest'
|
|
|
4
4
|
import { Pane } from '@/core/layout/pane'
|
|
5
5
|
import { PaneRenderer } from '@/core/paneRenderer'
|
|
6
6
|
|
|
7
|
+
function createDom() {
|
|
8
|
+
return {
|
|
9
|
+
mainCanvas: document.createElement('canvas'),
|
|
10
|
+
overlayCanvas: document.createElement('canvas'),
|
|
11
|
+
yAxisCanvas: document.createElement('canvas'),
|
|
12
|
+
yAxisOverlayCanvas: document.createElement('canvas'),
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
7
16
|
describe('PaneRenderer resize DPR mapping', () => {
|
|
8
17
|
it('maps logical plot size to physical canvas size and keeps CSS size logical', () => {
|
|
9
|
-
const
|
|
10
|
-
const overlayCanvas = document.createElement('canvas')
|
|
11
|
-
const yAxisCanvas = document.createElement('canvas')
|
|
18
|
+
const dom = createDom()
|
|
12
19
|
const pane = new Pane('main')
|
|
13
|
-
const renderer = new PaneRenderer(
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
yPaddingPx: 0,
|
|
20
|
-
priceLabelWidth: 60,
|
|
21
|
-
},
|
|
22
|
-
)
|
|
20
|
+
const renderer = new PaneRenderer(dom, pane, {
|
|
21
|
+
rightAxisWidth: 80,
|
|
22
|
+
leftAxisWidth: 60,
|
|
23
|
+
yPaddingPx: 0,
|
|
24
|
+
priceLabelWidth: 60,
|
|
25
|
+
})
|
|
23
26
|
|
|
24
27
|
renderer.resize(500, 240, 2)
|
|
25
28
|
|
|
26
|
-
expect(mainCanvas.width).toBe(Math.round(500 * 2))
|
|
27
|
-
expect(mainCanvas.height).toBe(Math.round(240 * 2))
|
|
28
|
-
expect(mainCanvas.style.width).toBe('500px')
|
|
29
|
-
expect(mainCanvas.style.height).toBe('240px')
|
|
29
|
+
expect(dom.mainCanvas.width).toBe(Math.round(500 * 2))
|
|
30
|
+
expect(dom.mainCanvas.height).toBe(Math.round(240 * 2))
|
|
31
|
+
expect(dom.mainCanvas.style.width).toBe('500px')
|
|
32
|
+
expect(dom.mainCanvas.style.height).toBe('240px')
|
|
30
33
|
// overlayCanvas should match mainCanvas
|
|
31
|
-
expect(overlayCanvas.width).toBe(mainCanvas.width)
|
|
32
|
-
expect(overlayCanvas.height).toBe(mainCanvas.height)
|
|
34
|
+
expect(dom.overlayCanvas.width).toBe(dom.mainCanvas.width)
|
|
35
|
+
expect(dom.overlayCanvas.height).toBe(dom.mainCanvas.height)
|
|
36
|
+
// yAxis overlay matches yAxis base
|
|
37
|
+
expect(dom.yAxisOverlayCanvas.width).toBe(dom.yAxisCanvas.width)
|
|
38
|
+
expect(dom.yAxisOverlayCanvas.height).toBe(dom.yAxisCanvas.height)
|
|
33
39
|
})
|
|
34
40
|
|
|
35
41
|
it('uses (rightAxisWidth + priceLabelWidth) for yAxis physical width when no parent width is available', () => {
|
|
36
|
-
const
|
|
37
|
-
const overlayCanvas = document.createElement('canvas')
|
|
38
|
-
const yAxisCanvas = document.createElement('canvas')
|
|
42
|
+
const dom = createDom()
|
|
39
43
|
const pane = new Pane('main')
|
|
40
|
-
const renderer = new PaneRenderer(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
yPaddingPx: 0,
|
|
47
|
-
priceLabelWidth: 70,
|
|
48
|
-
},
|
|
49
|
-
)
|
|
44
|
+
const renderer = new PaneRenderer(dom, pane, {
|
|
45
|
+
rightAxisWidth: 100,
|
|
46
|
+
leftAxisWidth: 60,
|
|
47
|
+
yPaddingPx: 0,
|
|
48
|
+
priceLabelWidth: 70,
|
|
49
|
+
})
|
|
50
50
|
|
|
51
51
|
renderer.resize(500, 200, 1.5)
|
|
52
52
|
|
|
53
|
-
expect(yAxisCanvas.width).toBe(Math.round((100 + 70) * 1.5))
|
|
54
|
-
expect(yAxisCanvas.height).toBe(Math.round(200 * 1.5))
|
|
55
|
-
expect(yAxisCanvas.style.width).toBe('170px')
|
|
56
|
-
expect(yAxisCanvas.style.height).toBe('200px')
|
|
53
|
+
expect(dom.yAxisCanvas.width).toBe(Math.round((100 + 70) * 1.5))
|
|
54
|
+
expect(dom.yAxisCanvas.height).toBe(Math.round(200 * 1.5))
|
|
55
|
+
expect(dom.yAxisCanvas.style.width).toBe('170px')
|
|
56
|
+
expect(dom.yAxisCanvas.style.height).toBe('200px')
|
|
57
|
+
expect(dom.yAxisOverlayCanvas.width).toBe(dom.yAxisCanvas.width)
|
|
58
|
+
expect(dom.yAxisOverlayCanvas.height).toBe(dom.yAxisCanvas.height)
|
|
57
59
|
})
|
|
58
60
|
|
|
59
61
|
it('uses parent clientWidth for yAxis canvas width when available', () => {
|
|
@@ -63,28 +65,24 @@ describe('PaneRenderer resize DPR mapping', () => {
|
|
|
63
65
|
configurable: true,
|
|
64
66
|
})
|
|
65
67
|
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
host.appendChild(yAxisCanvas)
|
|
68
|
+
const dom = createDom()
|
|
69
|
+
host.appendChild(dom.yAxisCanvas)
|
|
70
|
+
host.appendChild(dom.yAxisOverlayCanvas)
|
|
70
71
|
|
|
71
72
|
const pane = new Pane('main')
|
|
72
|
-
const renderer = new PaneRenderer(
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
yPaddingPx: 0,
|
|
79
|
-
priceLabelWidth: 70,
|
|
80
|
-
},
|
|
81
|
-
)
|
|
73
|
+
const renderer = new PaneRenderer(dom, pane, {
|
|
74
|
+
rightAxisWidth: 100,
|
|
75
|
+
leftAxisWidth: 60,
|
|
76
|
+
yPaddingPx: 0,
|
|
77
|
+
priceLabelWidth: 70,
|
|
78
|
+
})
|
|
82
79
|
|
|
83
80
|
renderer.resize(500, 200, 1.5)
|
|
84
81
|
|
|
85
|
-
expect(yAxisCanvas.width).toBe(Math.round(168 * 1.5))
|
|
86
|
-
expect(yAxisCanvas.height).toBe(Math.round(200 * 1.5))
|
|
87
|
-
expect(yAxisCanvas.style.width).toBe('168px')
|
|
88
|
-
expect(yAxisCanvas.style.height).toBe('200px')
|
|
82
|
+
expect(dom.yAxisCanvas.width).toBe(Math.round(168 * 1.5))
|
|
83
|
+
expect(dom.yAxisCanvas.height).toBe(Math.round(200 * 1.5))
|
|
84
|
+
expect(dom.yAxisCanvas.style.width).toBe('168px')
|
|
85
|
+
expect(dom.yAxisCanvas.style.height).toBe('200px')
|
|
86
|
+
expect(dom.yAxisOverlayCanvas.width).toBe(dom.yAxisCanvas.width)
|
|
89
87
|
})
|
|
90
88
|
})
|
|
@@ -41,9 +41,11 @@ function createMockContext(): SubPaneContext & {
|
|
|
41
41
|
removeRenderer: vi.fn((name) => renderers.delete(name)),
|
|
42
42
|
setRendererEnabled: vi.fn(),
|
|
43
43
|
updateRendererConfig: vi.fn(),
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
getOption: () => ({
|
|
45
|
+
rightAxisWidth: 60,
|
|
46
|
+
priceLabelWidth: 60,
|
|
47
|
+
yPaddingPx: 4,
|
|
48
|
+
}),
|
|
47
49
|
getCrosshairPos: () => null,
|
|
48
50
|
getCrosshairPrice: () => null,
|
|
49
51
|
getActivePaneId: () => null,
|
package/src/engine/chart.ts
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chart — 图表顶层编排器。
|
|
3
|
+
*
|
|
4
|
+
* 职责范围:
|
|
5
|
+
* - 持有 StateKernel(所有配置与状态的唯一数据源)
|
|
6
|
+
* - 管理 Viewport / 布局 / 渲染器生命周期
|
|
7
|
+
* - 提供 scheduleDraw / draw 入口供外部(交互、数据、插件)触发重绘
|
|
8
|
+
* - 协调插件宿主、指标控制器、标注管理器等子系统的初始化与销毁
|
|
9
|
+
*
|
|
10
|
+
* 不是绘制管线的一部分。绘制由 ChartRenderer 完成,Chart 仅负责代理调用并维护 runtimeProjection(批量投影)屏障。
|
|
11
|
+
*/
|
|
1
12
|
import { createAlertController } from '../features/alerts/index'
|
|
2
13
|
import {
|
|
3
14
|
createVolumeLookbacks,
|
|
@@ -15,10 +26,13 @@ import {
|
|
|
15
26
|
import { createLayerFromPlugin } from '../rendering/scene/createLayerFromPlugin'
|
|
16
27
|
import {
|
|
17
28
|
computed,
|
|
29
|
+
createSignal,
|
|
18
30
|
type Computed,
|
|
19
31
|
type ReadonlySignal,
|
|
20
32
|
type Signal,
|
|
33
|
+
type WritableSignal,
|
|
21
34
|
} from '../foundation/reactivity/signal'
|
|
35
|
+
import type { LegendTemplateContext } from './renderers/Indicator/mainIndicatorLegendContext'
|
|
22
36
|
|
|
23
37
|
import { InteractionController, type InteractionSnapshot } from './controller/interaction'
|
|
24
38
|
|
|
@@ -46,10 +60,9 @@ import { UpdateLevel, type VisibleRange } from './layout/pane'
|
|
|
46
60
|
import { KLineMode } from './modes/kLineMode'
|
|
47
61
|
import { TimeShareMode } from './modes/timeShareMode'
|
|
48
62
|
import { PaneRenderer } from './paneRenderer'
|
|
49
|
-
import { ChartRenderer } from './render/chartRenderer'
|
|
63
|
+
import { ChartRenderer, mergeUpdateLevel } from './render/chartRenderer'
|
|
50
64
|
import { ChartStateKernel } from './state/chartStateKernel'
|
|
51
65
|
import { ChartViewportManager } from './viewport/chartViewportManager'
|
|
52
|
-
import { getVisibleRange } from './viewport/viewport'
|
|
53
66
|
import { ChartZoomController } from './utils/chartZoomController'
|
|
54
67
|
import { getPhysicalKLineConfig } from './utils/klineConfig'
|
|
55
68
|
import type {
|
|
@@ -117,8 +130,13 @@ export class Chart {
|
|
|
117
130
|
|
|
118
131
|
/** 渲染器 */
|
|
119
132
|
private renderer: ChartRenderer
|
|
133
|
+
/** runRuntimeProjection 嵌套深度,大于 0 时推迟 scheduleDraw */
|
|
120
134
|
private runtimeProjectionDepth = 0
|
|
121
|
-
|
|
135
|
+
/** 被推迟的绘制级别,退出嵌套后统一 flush */
|
|
136
|
+
private pendingProjectionLevel: UpdateLevel | null = null
|
|
137
|
+
/** 主图图例模板上下文(每帧由 mainIndicatorLegend 发布) */
|
|
138
|
+
private readonly _legendTemplateContext: WritableSignal<LegendTemplateContext | null> =
|
|
139
|
+
createSignal<LegendTemplateContext | null>(null)
|
|
122
140
|
|
|
123
141
|
/** 绘图交互会话(锚点/预览/拖拽);工具 id 在 kernel */
|
|
124
142
|
private drawingSession: DrawingInteractionController | null = null
|
|
@@ -275,17 +293,13 @@ export class Chart {
|
|
|
275
293
|
defaultPaneMinHeightPx: o.defaultPaneMinHeightPx,
|
|
276
294
|
}
|
|
277
295
|
},
|
|
278
|
-
|
|
296
|
+
viewport: this.kernel.viewport,
|
|
279
297
|
setKnownPaneIds: (ids) => this.rendererPluginManager.setKnownPaneIds(ids),
|
|
280
298
|
notifyPaneResize: (paneId, pane) =>
|
|
281
299
|
this.rendererPluginManager.notifyResize(paneId, wrapPaneInfo(pane)),
|
|
282
300
|
scheduleDraw: (level) => this.scheduleDraw(level),
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
commitLayout: (ratios, specs) => {
|
|
286
|
-
this.kernel.pane.actions.commitLayout(ratios, specs)
|
|
287
|
-
this.ensurePaneScaleTypesFromSettings()
|
|
288
|
-
},
|
|
301
|
+
pane: this.kernel.pane,
|
|
302
|
+
afterCommitLayout: () => this.ensurePaneScaleTypesFromSettings(),
|
|
289
303
|
})
|
|
290
304
|
|
|
291
305
|
this.alertController = createAlertController()
|
|
@@ -300,51 +314,25 @@ export class Chart {
|
|
|
300
314
|
kGap: this.kernel.viewport.readonly.kGap(),
|
|
301
315
|
}
|
|
302
316
|
},
|
|
303
|
-
getEffectiveDpr: () => this.viewportManager.getEffectiveDpr(),
|
|
304
|
-
getLogicalScrollLeft: () => this.viewportManager.getLogicalScrollLeft(),
|
|
305
|
-
getCachedScrollLeft: () => this.viewportManager.getCachedScrollLeft(),
|
|
306
|
-
setScrollLeft: (v) => {
|
|
307
|
-
this.viewportManager.setScrollLeft(v)
|
|
308
|
-
},
|
|
309
317
|
getDom: () => this.dom,
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
getVisibleRange: () => {
|
|
313
|
-
const vp = this.viewportManager.computeViewport()
|
|
314
|
-
if (!vp) return null
|
|
315
|
-
const dataLen = this.dataManager?.getData().length ?? 0
|
|
316
|
-
if (dataLen === 0) return null
|
|
317
|
-
return getVisibleRange(
|
|
318
|
-
vp.scrollLeft,
|
|
319
|
-
vp.plotWidth,
|
|
320
|
-
this.kernel.zoom.readonly.kWidth(),
|
|
321
|
-
this.kernel.viewport.readonly.kGap(),
|
|
322
|
-
dataLen,
|
|
323
|
-
vp.dpr,
|
|
324
|
-
)
|
|
325
|
-
},
|
|
326
|
-
getLeftLoadBufferWidth: () => this.kernel.viewport.readonly.leftLoadBufferWidth.peek(),
|
|
327
|
-
getContentWidth: () => this.kernel.viewport.readonly.contentWidth.peek(),
|
|
318
|
+
viewport: this.kernel.viewport,
|
|
319
|
+
comparison: this.kernel.comparison,
|
|
328
320
|
scheduleDraw: (level) => this.scheduleDraw(level),
|
|
329
321
|
resetInteraction: () => this.interaction.reset(),
|
|
330
322
|
getIndicatorScheduler: () => this.indicatorManager.indicatorSchedulerAccessor,
|
|
331
323
|
isPointerDown: () => this.interaction.isPointerDown(),
|
|
332
324
|
onTimeShareDataReady: (dataLength) => {
|
|
333
|
-
const vp = this.
|
|
325
|
+
const vp = this.getViewport()
|
|
334
326
|
if (!vp || vp.plotWidth <= 0) return
|
|
335
327
|
const result = this._activeMode.computeKWidth(dataLength, vp.plotWidth, vp.dpr)
|
|
336
328
|
if (result) {
|
|
337
329
|
this.applyRenderState(result.kWidth, result.kGap)
|
|
338
330
|
const leftBuffer = this.getLeftLoadBufferWidth()
|
|
339
|
-
this.
|
|
331
|
+
this.kernel.viewport.actions.scrollTo(leftBuffer)
|
|
340
332
|
}
|
|
341
333
|
},
|
|
342
334
|
onDataProcessed: (data, range) => this.evaluateAlerts(data, range),
|
|
343
335
|
setSymbols: (symbols) => this.kernel.actions.setSymbols(symbols),
|
|
344
|
-
setComparisonLoading: (loading) => this.kernel.comparison.actions.setLoading(loading),
|
|
345
|
-
comparisonSpecs$: this.kernel.comparison.readonly.specs,
|
|
346
|
-
comparisonColors$: this.kernel.comparison.readonly.colors,
|
|
347
|
-
comparisonLoading$: this.kernel.comparison.readonly.loading,
|
|
348
336
|
},
|
|
349
337
|
this.kernel.data,
|
|
350
338
|
this.kernel.dataManager,
|
|
@@ -352,22 +340,16 @@ export class Chart {
|
|
|
352
340
|
|
|
353
341
|
this.zoomController = new ChartZoomController(
|
|
354
342
|
{
|
|
355
|
-
|
|
356
|
-
|
|
343
|
+
viewport: this.kernel.viewport,
|
|
344
|
+
options: this.kernel.options,
|
|
345
|
+
period$: this.kernel.dataManager.readonly.currentPeriod,
|
|
357
346
|
getClientWidth: () =>
|
|
358
|
-
this.
|
|
347
|
+
this.getViewport()?.viewWidth ?? this.dom.container?.clientWidth ?? 0,
|
|
359
348
|
getDataLength: () => this.dataManager.getData().length,
|
|
360
349
|
getPlotWidth: () => this.getLeftLoadBufferWidth(),
|
|
361
|
-
setScrollLeft: (v) => {
|
|
362
|
-
this.viewportManager.setScrollLeft(v)
|
|
363
|
-
},
|
|
364
350
|
onChange: () => {
|
|
365
351
|
this.scheduleDraw()
|
|
366
352
|
},
|
|
367
|
-
getMinKWidth: () => this.kernel.options.readonly.options.peek().minKWidth,
|
|
368
|
-
getMaxKWidth: () => this.kernel.options.readonly.options.peek().maxKWidth,
|
|
369
|
-
getPeriod: () => this.kernel.dataManager.readonly.currentPeriod.peek(),
|
|
370
|
-
zoomLevelCount,
|
|
371
353
|
},
|
|
372
354
|
this.kernel.zoom,
|
|
373
355
|
)
|
|
@@ -387,8 +369,9 @@ export class Chart {
|
|
|
387
369
|
removeRenderer: (name) => this.removeRenderer(name),
|
|
388
370
|
updateRendererConfig: (name, config) => this.updateRendererConfig(name, config),
|
|
389
371
|
setRendererEnabled: (name, enabled) => this.setRendererEnabled(name, enabled),
|
|
390
|
-
|
|
391
|
-
|
|
372
|
+
paneRatios$: this.kernel.pane.readonly.paneRatios as ReadonlySignal<
|
|
373
|
+
Readonly<Record<string, number>>
|
|
374
|
+
>,
|
|
392
375
|
paneSpecs$: this.kernel.pane.readonly.paneSpecs,
|
|
393
376
|
projectPaneLayout: (specs, ratios) => {
|
|
394
377
|
this.layoutManager.projectState(specs, ratios)
|
|
@@ -405,24 +388,17 @@ export class Chart {
|
|
|
405
388
|
getLayer: (id) => this.renderer?.getScene()?.getLayer(id) ?? null,
|
|
406
389
|
setLayerVisibility: (id, visible) =>
|
|
407
390
|
this.renderer?.getScene()?.setLayerVisibility(id, visible),
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
this.kernel.actions.createSubPane(paneId, indicatorId, params),
|
|
420
|
-
removeSubPaneState: (paneId) => this.kernel.actions.removeSubPane(paneId),
|
|
421
|
-
replaceSubPaneState: (paneId, indicatorId, params) =>
|
|
422
|
-
this.kernel.actions.replaceSubPane(paneId, indicatorId, params),
|
|
423
|
-
updateSubPaneStateParams: (paneId, params) =>
|
|
424
|
-
this.kernel.actions.updateSubPaneParams(paneId, params),
|
|
425
|
-
clearSubPaneState: () => this.kernel.actions.clearSubPanes(),
|
|
391
|
+
indicator: this.kernel.indicator,
|
|
392
|
+
subPaneOps: {
|
|
393
|
+
entries: this.kernel.subPane.readonly.entries,
|
|
394
|
+
create: (paneId, indicatorId, params) =>
|
|
395
|
+
this.kernel.actions.createSubPane(paneId, indicatorId, params),
|
|
396
|
+
remove: (paneId) => this.kernel.actions.removeSubPane(paneId),
|
|
397
|
+
replace: (paneId, indicatorId, params) =>
|
|
398
|
+
this.kernel.actions.replaceSubPane(paneId, indicatorId, params),
|
|
399
|
+
setParams: (paneId, params) => this.kernel.actions.updateSubPaneParams(paneId, params),
|
|
400
|
+
clear: () => this.kernel.actions.clearSubPanes(),
|
|
401
|
+
},
|
|
426
402
|
runRendererTransaction: (run) => this.runRuntimeProjection(run),
|
|
427
403
|
})
|
|
428
404
|
|
|
@@ -456,10 +432,10 @@ export class Chart {
|
|
|
456
432
|
getSceneRenderer: () => this.rendererHost.renderer,
|
|
457
433
|
getPluginHost: () => this.pluginHost,
|
|
458
434
|
getRendererPluginManager: () => this.rendererPluginManager,
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
435
|
+
theme$: this.kernel.effectiveTheme$,
|
|
436
|
+
zoom: this.kernel.zoom,
|
|
437
|
+
options: this.kernel.options,
|
|
438
|
+
viewport: this.kernel.viewport,
|
|
463
439
|
getDataManager: () => this.dataManager,
|
|
464
440
|
getIndicatorManager: () => this.indicatorManager,
|
|
465
441
|
getActiveMode: () => this._activeMode,
|
|
@@ -468,6 +444,9 @@ export class Chart {
|
|
|
468
444
|
drawings$: this.kernel.drawing.readonly.drawings,
|
|
469
445
|
selectedDrawingId$: this.kernel.drawing.readonly.selectedDrawingId,
|
|
470
446
|
getOverlay: () => this.drawingSession?.getPaintOverlay() ?? [],
|
|
447
|
+
onLegendContext: (ctx) => {
|
|
448
|
+
this._legendTemplateContext.set(ctx)
|
|
449
|
+
},
|
|
471
450
|
})
|
|
472
451
|
this.renderer.registerDrawingPlugins()
|
|
473
452
|
this.renderer.initCoreRenderers()
|
|
@@ -476,7 +455,8 @@ export class Chart {
|
|
|
476
455
|
}
|
|
477
456
|
|
|
478
457
|
getViewport(): Viewport | null {
|
|
479
|
-
|
|
458
|
+
if (this.kernel.viewport.readonly.viewWidth.peek() === 0) return null
|
|
459
|
+
return this.kernel.viewport.readonly.viewport.peek()
|
|
480
460
|
}
|
|
481
461
|
|
|
482
462
|
/** 获取当前活跃的模式处理器 */
|
|
@@ -572,7 +552,7 @@ export class Chart {
|
|
|
572
552
|
}
|
|
573
553
|
|
|
574
554
|
getCurrentDpr(): number {
|
|
575
|
-
return this.
|
|
555
|
+
return this.kernel.viewport.readonly.dpr.peek()
|
|
576
556
|
}
|
|
577
557
|
|
|
578
558
|
/** 获取当前周期 */
|
|
@@ -580,25 +560,6 @@ export class Chart {
|
|
|
580
560
|
return this.dataManager.currentPeriod
|
|
581
561
|
}
|
|
582
562
|
|
|
583
|
-
/** 获取缓存的 scrollLeft(避免读取 DOM 触发强制回流) */
|
|
584
|
-
getCachedScrollLeft(): number {
|
|
585
|
-
return this.viewportManager.getCachedScrollLeft()
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
/** 同步程序性 scrollLeft 写入后的缓存,避免等待异步 scroll 事件 */
|
|
589
|
-
syncScrollLeft(scrollLeft: number): void {
|
|
590
|
-
this.viewportManager.setScrollLeft(scrollLeft)
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
setScrollLeft(v: number): void {
|
|
594
|
-
this.viewportManager.setScrollLeft(v)
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
/** 获取逻辑 scrollLeft(减去左侧加载缓冲宽度,可为负值) */
|
|
598
|
-
getLogicalScrollLeft(): number {
|
|
599
|
-
return this.viewportManager.getLogicalScrollLeft()
|
|
600
|
-
}
|
|
601
|
-
|
|
602
563
|
/** 获取插件宿主 */
|
|
603
564
|
get plugin(): PluginHostImpl {
|
|
604
565
|
return this.pluginHost
|
|
@@ -1211,14 +1172,14 @@ export class Chart {
|
|
|
1211
1172
|
resize() {
|
|
1212
1173
|
if (this._activeMode === this._timeShareMode) {
|
|
1213
1174
|
const tsData = this.dataManager.getTimeShareData()
|
|
1214
|
-
const vp = this.
|
|
1175
|
+
const vp = this.getViewport()
|
|
1215
1176
|
if (!vp || vp.plotWidth <= 0) return
|
|
1216
1177
|
if (tsData.length > 0) {
|
|
1217
1178
|
const result = this._activeMode.computeKWidth(tsData.length, vp.plotWidth, vp.dpr)
|
|
1218
1179
|
if (result) {
|
|
1219
1180
|
this.applyRenderState(result.kWidth, result.kGap)
|
|
1220
1181
|
const leftBuffer = this.getLeftLoadBufferWidth()
|
|
1221
|
-
this.
|
|
1182
|
+
this.kernel.viewport.actions.scrollTo(leftBuffer)
|
|
1222
1183
|
}
|
|
1223
1184
|
}
|
|
1224
1185
|
this.renderer.clearCachedFrame()
|
|
@@ -1226,7 +1187,7 @@ export class Chart {
|
|
|
1226
1187
|
this.scheduleDraw()
|
|
1227
1188
|
return
|
|
1228
1189
|
}
|
|
1229
|
-
const vp = this.
|
|
1190
|
+
const vp = this.getViewport()
|
|
1230
1191
|
// 防御性检查:容器尺寸无效时跳过布局
|
|
1231
1192
|
if (!vp || vp.viewWidth < 10 || vp.viewHeight < 10) {
|
|
1232
1193
|
return
|
|
@@ -1241,22 +1202,27 @@ export class Chart {
|
|
|
1241
1202
|
* @param level 更新级别,默认为 All
|
|
1242
1203
|
*/
|
|
1243
1204
|
scheduleDraw(level: UpdateLevel = UpdateLevel.All): void {
|
|
1205
|
+
// 正在批量安装/卸载 renderer(pane 重排、指标切换、子图增删),等全部完成再 flush
|
|
1244
1206
|
if (this.runtimeProjectionDepth > 0) {
|
|
1245
|
-
this.
|
|
1207
|
+
this.pendingProjectionLevel = this.pendingProjectionLevel
|
|
1208
|
+
? mergeUpdateLevel(this.pendingProjectionLevel, level)
|
|
1209
|
+
: level
|
|
1246
1210
|
return
|
|
1247
1211
|
}
|
|
1248
1212
|
this.renderer.scheduleDraw(level)
|
|
1249
1213
|
}
|
|
1250
1214
|
|
|
1215
|
+
/** 在 RendererPluginManager 事务内执行 run,推迟期间的所有 scheduleDraw 到最外层统一 flush */
|
|
1251
1216
|
private runRuntimeProjection(run: () => void): void {
|
|
1252
1217
|
this.runtimeProjectionDepth++
|
|
1253
1218
|
try {
|
|
1254
1219
|
this.rendererPluginManager.transaction(run)
|
|
1255
1220
|
} finally {
|
|
1256
1221
|
this.runtimeProjectionDepth--
|
|
1257
|
-
if (this.runtimeProjectionDepth === 0 && this.
|
|
1258
|
-
|
|
1259
|
-
this.
|
|
1222
|
+
if (this.runtimeProjectionDepth === 0 && this.pendingProjectionLevel !== null) {
|
|
1223
|
+
const level = this.pendingProjectionLevel
|
|
1224
|
+
this.pendingProjectionLevel = null
|
|
1225
|
+
this.renderer?.scheduleDraw(level)
|
|
1260
1226
|
}
|
|
1261
1227
|
}
|
|
1262
1228
|
}
|
|
@@ -1310,10 +1276,6 @@ export class Chart {
|
|
|
1310
1276
|
await this.pluginHost.destroy()
|
|
1311
1277
|
}
|
|
1312
1278
|
|
|
1313
|
-
private computeViewport(): Viewport | null {
|
|
1314
|
-
return this.viewportManager.computeViewport()
|
|
1315
|
-
}
|
|
1316
|
-
|
|
1317
1279
|
// ==================== Facade API (High-level interface for adapters) ====================
|
|
1318
1280
|
|
|
1319
1281
|
/** interactionSnapshot lazy computed for the createChartController facade */
|
|
@@ -1329,7 +1291,7 @@ export class Chart {
|
|
|
1329
1291
|
|
|
1330
1292
|
/** 视口状态信号 */
|
|
1331
1293
|
get viewport(): ReadonlySignal<ViewportState> {
|
|
1332
|
-
return this.
|
|
1294
|
+
return this.kernel.viewport.readonly.viewportState
|
|
1333
1295
|
}
|
|
1334
1296
|
|
|
1335
1297
|
/** 数据信号 */
|
|
@@ -1359,12 +1321,12 @@ export class Chart {
|
|
|
1359
1321
|
|
|
1360
1322
|
/** 比较商品颜色信号 */
|
|
1361
1323
|
get comparisonColors(): ReadonlySignal<ReadonlyMap<string, string>> {
|
|
1362
|
-
return this.
|
|
1324
|
+
return this.kernel.comparison.readonly.colors
|
|
1363
1325
|
}
|
|
1364
1326
|
|
|
1365
1327
|
/** 比较商品加载信号 */
|
|
1366
1328
|
get comparisonLoading(): ReadonlySignal<boolean> {
|
|
1367
|
-
return this.
|
|
1329
|
+
return this.kernel.comparison.readonly.loading
|
|
1368
1330
|
}
|
|
1369
1331
|
|
|
1370
1332
|
/** 生效主题信号(settings.theme + systemTheme 推导) */
|
|
@@ -1414,6 +1376,11 @@ export class Chart {
|
|
|
1414
1376
|
return this._interactionSnapshot
|
|
1415
1377
|
}
|
|
1416
1378
|
|
|
1379
|
+
/** 主图左上角图例模板上下文(null 表示无数据) */
|
|
1380
|
+
get legendTemplateContext(): ReadonlySignal<LegendTemplateContext | null> {
|
|
1381
|
+
return this._legendTemplateContext
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1417
1384
|
// ---------- Data ----------
|
|
1418
1385
|
|
|
1419
1386
|
setData(data: KLineData[]): void {
|
package/src/engine/chartTypes.ts
CHANGED
|
@@ -22,7 +22,10 @@ export type PaneRendererDom = {
|
|
|
22
22
|
mainCanvas: HTMLCanvasElement
|
|
23
23
|
overlayCanvas: HTMLCanvasElement
|
|
24
24
|
yAxisCanvas: HTMLCanvasElement
|
|
25
|
+
/** 轴区动态层(最新价标签、十字线价签),叠在 yAxisCanvas 上 */
|
|
26
|
+
yAxisOverlayCanvas: HTMLCanvasElement
|
|
25
27
|
leftYAxisCanvas?: HTMLCanvasElement
|
|
28
|
+
leftYAxisOverlayCanvas?: HTMLCanvasElement
|
|
26
29
|
}
|
|
27
30
|
|
|
28
31
|
export type ChartOptions = {
|
|
@@ -58,7 +61,9 @@ export type ViewportState = {
|
|
|
58
61
|
plotWidth: number
|
|
59
62
|
plotHeight: number
|
|
60
63
|
dpr: number
|
|
64
|
+
/** 可索引可见起点(已 clamp start>=0) */
|
|
61
65
|
visibleFrom: number
|
|
66
|
+
/** 可索引可见终点(开区间) */
|
|
62
67
|
visibleTo: number
|
|
63
68
|
kWidth: number
|
|
64
69
|
kGap: number
|
|
@@ -223,8 +223,22 @@ function createChartStub(args: {
|
|
|
223
223
|
dpr: args.dpr,
|
|
224
224
|
}),
|
|
225
225
|
getCurrentDpr: () => args.dpr,
|
|
226
|
-
|
|
227
|
-
|
|
226
|
+
kernel: {
|
|
227
|
+
viewport: {
|
|
228
|
+
readonly: {
|
|
229
|
+
scrollLeft: { peek: () => 0 },
|
|
230
|
+
scrollLeftLogical: { peek: () => 0 },
|
|
231
|
+
},
|
|
232
|
+
actions: {
|
|
233
|
+
scrollTo: () => undefined,
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
settings: {
|
|
237
|
+
readonly: {
|
|
238
|
+
settings: { peek: () => ({}) },
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
},
|
|
228
242
|
getMarkerManager: () => markerManager,
|
|
229
243
|
getPaneRenderers: () => paneRenderers,
|
|
230
244
|
getData: () => data,
|
|
@@ -302,6 +316,29 @@ describe('InteractionController DPR consumption', () => {
|
|
|
302
316
|
expect(interaction.crosshairPos).toBeNull()
|
|
303
317
|
expect(interaction.crosshairIndex).toBeNull()
|
|
304
318
|
})
|
|
319
|
+
|
|
320
|
+
it('indexes bars from sealed frameVisibleRange, not stale viewport.visibleFrom', () => {
|
|
321
|
+
// hit-test 与 positions 必须同帧同源;即使 viewport 快照与 seal range 不一致,也以 seal 为准
|
|
322
|
+
const chart = createChartStub({ dpr: 1, plotWidth: 300, plotHeight: 160 })
|
|
323
|
+
chart.viewport.peek = () => ({
|
|
324
|
+
zoomLevel: 1,
|
|
325
|
+
plotWidth: 300,
|
|
326
|
+
plotHeight: 160,
|
|
327
|
+
dpr: 1,
|
|
328
|
+
visibleFrom: 99,
|
|
329
|
+
visibleTo: 101,
|
|
330
|
+
kWidth: 6,
|
|
331
|
+
kGap: 2,
|
|
332
|
+
})
|
|
333
|
+
const interaction = new InteractionController(chart as never, createMockInteractionState())
|
|
334
|
+
interaction.setKLinePositions([0, 10], { start: 0, end: 2 }, 10)
|
|
335
|
+
|
|
336
|
+
interaction.onPointerMove({ clientX: 5, clientY: 40, isPrimary: true } as PointerEvent)
|
|
337
|
+
interaction.flushPendingHover()
|
|
338
|
+
|
|
339
|
+
expect(interaction.crosshairIndex).toBe(0)
|
|
340
|
+
expect(interaction.crosshairPos).not.toBeNull()
|
|
341
|
+
})
|
|
305
342
|
})
|
|
306
343
|
|
|
307
344
|
describe('InteractionController pane capability gating', () => {
|