@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
|
@@ -30,18 +30,16 @@ import { createDrawingRendererPlugin, createDrawingLabelOverlayPlugin } from '..
|
|
|
30
30
|
import { ChartIndicatorManager } from '../indicators/chartIndicatorManager'
|
|
31
31
|
import { UpdateLevel } from '../layout/pane'
|
|
32
32
|
import type { VisibleRange } from '../layout/pane'
|
|
33
|
-
import {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
} from '../marker/registry'
|
|
33
|
+
import { MarkerManager, type CustomMarkerEntity, type MarkerManagerDeps } from '../marker/registry'
|
|
34
|
+
import { ASHARE_MARKET_SESSION } from '../../foundation/utils/timeShareAxisLabels'
|
|
35
|
+
import { resolveMarketSessionSlots } from '../../foundation/utils/timeShareAxisLabels'
|
|
36
|
+
import { computeTimeShareXLayout } from '../modes/timeShareMath'
|
|
38
37
|
import type { ChartModeHandler } from '../modes/types'
|
|
39
38
|
import { PaneRenderer } from '../paneRenderer'
|
|
40
39
|
import { createTimeAxisRendererPlugin } from '../renderers/timeAxis'
|
|
41
40
|
import { getPhysicalKLineConfig } from '../utils/klineConfig'
|
|
42
41
|
import { calculateTickCount } from '../utils/tickCount'
|
|
43
|
-
|
|
44
|
-
import { getVisibleRange } from '../viewport/viewport'
|
|
42
|
+
|
|
45
43
|
|
|
46
44
|
import { createCandleLayer } from './layers/candleLayer'
|
|
47
45
|
import { createComparisonLineLayer } from './layers/comparisonLineLayer'
|
|
@@ -51,11 +49,21 @@ import { createExtremaMarkersLayer } from './layers/extremaMarkersLayer'
|
|
|
51
49
|
import { createGridLinesLayer } from './layers/gridLinesLayer'
|
|
52
50
|
import { createLastPriceLabelLayer } from './layers/lastPriceLabelLayer'
|
|
53
51
|
import { createLastPriceLineLayer } from './layers/lastPriceLineLayer'
|
|
54
|
-
import {
|
|
52
|
+
import {
|
|
53
|
+
createLeftYAxisOverlayLayer,
|
|
54
|
+
createLeftYAxisStaticLayer,
|
|
55
|
+
} from './layers/leftYAxisLayer'
|
|
55
56
|
import { createMainIndicatorLegendLayer } from './layers/mainIndicatorLegendLayer'
|
|
56
|
-
import {
|
|
57
|
-
import {
|
|
57
|
+
import { createYAxisOverlayLayer, createYAxisStaticLayer } from './layers/yAxisLayer'
|
|
58
|
+
import type { LayerRole } from '../../rendering/scene/types'
|
|
59
|
+
import {
|
|
60
|
+
createFrameTransaction,
|
|
61
|
+
type FrameTransaction,
|
|
62
|
+
} from '../../foundation/reactivity/frameTransaction'
|
|
58
63
|
import type { ReadonlySignal } from '../../foundation/reactivity/signal'
|
|
64
|
+
import type { ViewportStateModule } from '../state/viewportState'
|
|
65
|
+
import type { ZoomStateModule } from '../state/zoomState'
|
|
66
|
+
import type { OptionsStateModule } from '../state/optionsState'
|
|
59
67
|
|
|
60
68
|
type ResolvedChartOptions = Omit<ChartOptions, 'kWidth' | 'kGap'> & {
|
|
61
69
|
kWidth: number
|
|
@@ -89,15 +97,12 @@ type FrameContext = {
|
|
|
89
97
|
zoomLevelCount: number
|
|
90
98
|
}
|
|
91
99
|
|
|
92
|
-
/**
|
|
100
|
+
/** 帧事务输入:合并多次 scheduleDraw 的 level */
|
|
93
101
|
type FrameDrawInput = {
|
|
94
102
|
level: UpdateLevel
|
|
95
103
|
}
|
|
96
104
|
|
|
97
|
-
/**
|
|
98
|
-
* 帧事务快照:单代际绘制契约。
|
|
99
|
-
* generation 由 FrameTransaction 写入;frame 为 null 表示无可画数据。
|
|
100
|
-
*/
|
|
105
|
+
/** 单帧快照,frame 为 null 表示无可画数据 */
|
|
101
106
|
type FrameDrawSnapshot = {
|
|
102
107
|
generation: number
|
|
103
108
|
level: UpdateLevel
|
|
@@ -105,7 +110,7 @@ type FrameDrawSnapshot = {
|
|
|
105
110
|
}
|
|
106
111
|
|
|
107
112
|
/** Main 与 Overlay 合并为 All,其余取更全或后者 */
|
|
108
|
-
function mergeUpdateLevel(current: UpdateLevel, next: UpdateLevel): UpdateLevel {
|
|
113
|
+
export function mergeUpdateLevel(current: UpdateLevel, next: UpdateLevel): UpdateLevel {
|
|
109
114
|
if (current === UpdateLevel.All || next === UpdateLevel.All) return UpdateLevel.All
|
|
110
115
|
if (current === next) return current
|
|
111
116
|
if (
|
|
@@ -125,10 +130,14 @@ export interface RendererDependencies {
|
|
|
125
130
|
getSceneRenderer: () => Renderer
|
|
126
131
|
getPluginHost: () => PluginHostImpl
|
|
127
132
|
getRendererPluginManager: () => RendererPluginManager
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
133
|
+
/** 生效主题 SSOT */
|
|
134
|
+
theme$: ReadonlySignal<'light' | 'dark'>
|
|
135
|
+
/** zoomLevel / kWidth SSOT */
|
|
136
|
+
zoom: ZoomStateModule
|
|
137
|
+
/** zoomLevelCount 等 options SSOT */
|
|
138
|
+
options: OptionsStateModule
|
|
139
|
+
/** scroll / dpr / plot 几何 SSOT */
|
|
140
|
+
viewport: ViewportStateModule
|
|
132
141
|
getDataManager: () => ChartDataManager
|
|
133
142
|
getIndicatorManager: () => ChartIndicatorManager
|
|
134
143
|
getActiveMode: () => ChartModeHandler
|
|
@@ -137,6 +146,10 @@ export interface RendererDependencies {
|
|
|
137
146
|
drawings$: DrawingStoreDeps['drawings$']
|
|
138
147
|
selectedDrawingId$: DrawingStoreDeps['selectedDrawingId$']
|
|
139
148
|
getOverlay?: DrawingStoreDeps['getOverlay']
|
|
149
|
+
/** 主图图例上下文发布(canvas / external 均触发;draw 内回调) */
|
|
150
|
+
onLegendContext?: (
|
|
151
|
+
ctx: import('../renderers/Indicator/mainIndicatorLegendContext').LegendTemplateContext | null,
|
|
152
|
+
) => void
|
|
140
153
|
}
|
|
141
154
|
|
|
142
155
|
export class ChartRenderer {
|
|
@@ -147,14 +160,9 @@ export class ChartRenderer {
|
|
|
147
160
|
* 帧事务:scheduleDraw 只写输入并合并 rAF;flush 内 prepare → seal → paint。
|
|
148
161
|
* 绘制阶段不再反向写 kernel 几何(seal 在 render 回调最前、与 paint 同代)。
|
|
149
162
|
*/
|
|
150
|
-
private readonly frameTx:
|
|
151
|
-
typeof createFrameTransaction<FrameDrawInput, FrameDrawSnapshot>
|
|
152
|
-
>
|
|
163
|
+
private readonly frameTx: FrameTransaction<FrameDrawInput, FrameDrawSnapshot>
|
|
153
164
|
|
|
154
|
-
/**
|
|
155
|
-
* 与 frameTx pending 同步的重绘级别镜像。
|
|
156
|
-
* FrameTransaction 对 level 是浅覆盖,Main/Overlay 升格在此完成。
|
|
157
|
-
*/
|
|
165
|
+
/** 合并多次 scheduleDraw 的 level,合并后写入 frameTx */
|
|
158
166
|
private pendingLevel: UpdateLevel = UpdateLevel.All
|
|
159
167
|
|
|
160
168
|
/** 已排队的 rAF 句柄;null 表示当前没有挂起的帧调度 */
|
|
@@ -207,11 +215,13 @@ export class ChartRenderer {
|
|
|
207
215
|
render: (snapshot) => {
|
|
208
216
|
// generation 0 占位不绘制
|
|
209
217
|
if (snapshot.generation === 0) return
|
|
210
|
-
//
|
|
218
|
+
// 把本帧 K 线信息(kLinePositions,range,kWidthPx,kLineCenters)写入 InteractionController,保证 hover 命中与本帧一致
|
|
211
219
|
if (snapshot.frame) {
|
|
212
220
|
this.sealFrameGeometry(snapshot.frame)
|
|
213
221
|
}
|
|
222
|
+
// 用本帧几何将鼠标坐标吸附到最近 K 线,算出十字线位置
|
|
214
223
|
this.deps.getInteraction().flushPendingHover()
|
|
224
|
+
// 绘制:清 canvas → 构建 RenderContext → 遍历 pane 调 scene.paintPane → endFrame(GPU 一次性 submit 所有 pane)→ 时间轴
|
|
215
225
|
this.drawWithFrame(snapshot.level, snapshot.frame)
|
|
216
226
|
},
|
|
217
227
|
schedule: (run) => {
|
|
@@ -280,11 +290,15 @@ export class ChartRenderer {
|
|
|
280
290
|
this.scene.addLayer(layer)
|
|
281
291
|
}
|
|
282
292
|
{
|
|
283
|
-
const layer = createMainIndicatorLegendLayer(
|
|
284
|
-
{
|
|
293
|
+
const { layer, plugin } = createMainIndicatorLegendLayer(
|
|
294
|
+
{
|
|
295
|
+
yPaddingPx: opt.yPaddingPx,
|
|
296
|
+
onContext: this.deps.onLegendContext,
|
|
297
|
+
},
|
|
285
298
|
getCtx('main'),
|
|
286
|
-
this.deps.getPluginHost(),
|
|
287
299
|
)
|
|
300
|
+
// 注册进 Manager,使 updateRendererConfig('mainIndicatorLegend') 可切换 renderMode
|
|
301
|
+
this.deps.getRendererPluginManager().register(plugin)
|
|
288
302
|
this.scene.addLayer(layer)
|
|
289
303
|
}
|
|
290
304
|
{
|
|
@@ -302,42 +316,38 @@ export class ChartRenderer {
|
|
|
302
316
|
this.scene.addLayer(layer)
|
|
303
317
|
}
|
|
304
318
|
{
|
|
305
|
-
const
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
return null
|
|
317
|
-
},
|
|
319
|
+
const yAxisOpts = {
|
|
320
|
+
axisWidth,
|
|
321
|
+
yPaddingPx: opt.yPaddingPx,
|
|
322
|
+
getCrosshair: () => {
|
|
323
|
+
const pos = interaction.crosshairPos
|
|
324
|
+
const price = interaction.crosshairPrice
|
|
325
|
+
const activePaneId = interaction.activePaneId
|
|
326
|
+
if (pos && price !== null) {
|
|
327
|
+
return { y: pos.y, price, activePaneId }
|
|
328
|
+
}
|
|
329
|
+
return null
|
|
318
330
|
},
|
|
319
|
-
|
|
320
|
-
)
|
|
321
|
-
this.scene.addLayer(
|
|
331
|
+
}
|
|
332
|
+
this.scene.addLayer(createYAxisStaticLayer(yAxisOpts, getCtxForCurrentPane))
|
|
333
|
+
this.scene.addLayer(createYAxisOverlayLayer(yAxisOpts, getCtxForCurrentPane))
|
|
322
334
|
}
|
|
323
335
|
{
|
|
324
|
-
const
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
return null
|
|
336
|
-
},
|
|
336
|
+
const leftYAxisOpts = {
|
|
337
|
+
axisWidth: opt.leftAxisWidth,
|
|
338
|
+
yPaddingPx: opt.yPaddingPx,
|
|
339
|
+
getCrosshair: () => {
|
|
340
|
+
const pos = interaction.crosshairPos
|
|
341
|
+
const price = interaction.crosshairPrice
|
|
342
|
+
const activePaneId = interaction.activePaneId
|
|
343
|
+
if (pos && price !== null) {
|
|
344
|
+
return { y: pos.y, price, activePaneId }
|
|
345
|
+
}
|
|
346
|
+
return null
|
|
337
347
|
},
|
|
338
|
-
|
|
339
|
-
)
|
|
340
|
-
this.scene.addLayer(
|
|
348
|
+
}
|
|
349
|
+
this.scene.addLayer(createLeftYAxisStaticLayer(leftYAxisOpts, getCtxForCurrentPane))
|
|
350
|
+
this.scene.addLayer(createLeftYAxisOverlayLayer(leftYAxisOpts, getCtxForCurrentPane))
|
|
341
351
|
}
|
|
342
352
|
}
|
|
343
353
|
|
|
@@ -395,6 +405,7 @@ export class ChartRenderer {
|
|
|
395
405
|
* @param level - Main 只画主层,Overlay 只画覆盖层(crosshair 等),All 全画
|
|
396
406
|
*/
|
|
397
407
|
scheduleDraw(level: UpdateLevel = UpdateLevel.All): void {
|
|
408
|
+
// 已经有待执行的下一帧,只合并 level,不重复 scheduleFlush
|
|
398
409
|
if (this.raf !== null) {
|
|
399
410
|
this.pendingLevel = mergeUpdateLevel(this.pendingLevel, level)
|
|
400
411
|
this.frameTx.writeInput({ level: this.pendingLevel })
|
|
@@ -402,16 +413,16 @@ export class ChartRenderer {
|
|
|
402
413
|
}
|
|
403
414
|
this.pendingLevel = level
|
|
404
415
|
this.frameTx.writeInput({ level })
|
|
416
|
+
// 提交帧,下次 rAF 上屏
|
|
405
417
|
this.frameTx.scheduleFlush()
|
|
406
418
|
}
|
|
407
419
|
|
|
408
420
|
/**
|
|
409
|
-
*
|
|
410
|
-
*
|
|
411
|
-
* 若已有 rAF 挂起:与 pendingLevel 合并后同步 flush(消费合并后的 level)。
|
|
412
|
-
* 若正处于帧事务非 idle(render/publish 重入):只写输入并调度下一帧,禁止嵌套 flush。
|
|
421
|
+
* 立即同步重绘一帧,不走 rAF。
|
|
413
422
|
*
|
|
414
|
-
*
|
|
423
|
+
* 若已有 rAF 挂起:合并本次 level 后同步 flush,把挂起的也带走。
|
|
424
|
+
* 若正处于帧事务非 idle(paint 重入中):只写输入,调度下一帧,不嵌套 flush。
|
|
425
|
+
* 与 scheduleDraw 的唯一区别:同步还是异步。
|
|
415
426
|
*/
|
|
416
427
|
draw(level: UpdateLevel = UpdateLevel.All): void {
|
|
417
428
|
if (this.frameTx.phase !== 'idle') {
|
|
@@ -428,10 +439,6 @@ export class ChartRenderer {
|
|
|
428
439
|
}
|
|
429
440
|
this.frameTx.writeInput({ level: this.pendingLevel })
|
|
430
441
|
this.frameTx.flush()
|
|
431
|
-
// 同步 flush 已消费本帧;若 flush 中又 scheduleDraw,raf 非 null,保留 pendingLevel
|
|
432
|
-
if (this.raf === null) {
|
|
433
|
-
this.pendingLevel = UpdateLevel.All
|
|
434
|
-
}
|
|
435
442
|
}
|
|
436
443
|
|
|
437
444
|
/**
|
|
@@ -444,9 +451,11 @@ export class ChartRenderer {
|
|
|
444
451
|
.setKLinePositions(frame.kLinePositions, frame.range, frame.kWidthPx, frame.kLineCenters)
|
|
445
452
|
}
|
|
446
453
|
|
|
454
|
+
/** 将 prepareFrameData 的帧几何按 level 画到 canvas,含所有 pane 的 main/overlay/yAxis 及时间轴 */
|
|
447
455
|
private drawWithFrame(level: UpdateLevel, frame: FrameContext | null): void {
|
|
448
456
|
this.markerManager.clear()
|
|
449
457
|
|
|
458
|
+
// frame 为空(无数据或首帧),清理画布后跳过绘制
|
|
450
459
|
if (!frame) {
|
|
451
460
|
const dataManager = this.deps.getDataManager()
|
|
452
461
|
if (dataManager.getInternalData().length === 0 && dataManager.getTimeShareData().length === 0)
|
|
@@ -459,7 +468,9 @@ export class ChartRenderer {
|
|
|
459
468
|
const dataManager = this.deps.getDataManager()
|
|
460
469
|
const mode = this.deps.getActiveMode()
|
|
461
470
|
if (mode.useIndicatorScheduler) {
|
|
471
|
+
// 获取指标管理器实例(持有 scheduler、状态、reconcile 逻辑)
|
|
462
472
|
const indicatorManager = this.deps.getIndicatorManager()
|
|
473
|
+
// 将主图指标列表(含参数)同步给 scheduler,使其在本帧预计算价格区间
|
|
463
474
|
indicatorManager.indicatorSchedulerAccessor.setActiveMainIndicators(
|
|
464
475
|
[...indicatorManager.mainIndicatorsSignalPeek.entries()].map(([id, entry]) => ({
|
|
465
476
|
id,
|
|
@@ -474,13 +485,13 @@ export class ChartRenderer {
|
|
|
474
485
|
|
|
475
486
|
const renderData = frame.data
|
|
476
487
|
|
|
488
|
+
// 遍历所有 pane,清 canvas → 构建 RenderContext → scene.paintPane
|
|
477
489
|
const { sharedXAxisLabels, sharedXAxisRanges } = this.renderPanes(
|
|
478
490
|
vp,
|
|
479
491
|
range,
|
|
480
492
|
kLinePositions,
|
|
481
493
|
kLineCenters,
|
|
482
494
|
kBarRects,
|
|
483
|
-
kWidthPx,
|
|
484
495
|
mainIndicatorRange,
|
|
485
496
|
hasCrosshair,
|
|
486
497
|
useCachedFrame,
|
|
@@ -489,6 +500,7 @@ export class ChartRenderer {
|
|
|
489
500
|
)
|
|
490
501
|
|
|
491
502
|
this.overlayHadCrosshair = hasCrosshair
|
|
503
|
+
// 画底部时间轴(独立 layer,不进 scene)
|
|
492
504
|
this.renderXAxis(
|
|
493
505
|
vp,
|
|
494
506
|
range,
|
|
@@ -503,42 +515,35 @@ export class ChartRenderer {
|
|
|
503
515
|
}
|
|
504
516
|
|
|
505
517
|
/**
|
|
506
|
-
*
|
|
518
|
+
* 计算一帧的 viewport、可见区间、K 线位置。
|
|
507
519
|
*
|
|
508
|
-
* Overlay
|
|
509
|
-
*
|
|
510
|
-
*
|
|
511
|
-
* TimeShare 模式按 plotWidth 平分 bar,不走 K 线物理宽度那套。
|
|
512
|
-
*
|
|
513
|
-
* @param level - Overlay 可走缓存,Main/All 强制重算
|
|
514
|
-
* @returns 无 viewport 或无数据时返回 null,调用方自己清屏或跳过
|
|
520
|
+
* Overlay 时复用 cachedDrawFrame 跳过重算,Main/All 强制刷新缓存。
|
|
521
|
+
* range 变化时调 checkVisibleRangeGapWhenIdle 触发空闲补数据。
|
|
522
|
+
* TimeShare 模式按 plotWidth 平分 bar,覆盖 K 线位置。
|
|
515
523
|
*/
|
|
524
|
+
/** viewWidth 为 0 表示尚未完成首帧尺寸 */
|
|
525
|
+
private peekViewport(): Viewport | null {
|
|
526
|
+
if (this.deps.viewport.readonly.viewWidth.peek() === 0) return null
|
|
527
|
+
return this.deps.viewport.readonly.viewport.peek()
|
|
528
|
+
}
|
|
529
|
+
|
|
516
530
|
private prepareFrameData(level: UpdateLevel): FrameContext | null {
|
|
517
531
|
const useCachedFrame = level === UpdateLevel.Overlay && this.cachedDrawFrame !== null
|
|
518
532
|
|
|
519
|
-
const vp = useCachedFrame
|
|
520
|
-
? this.cachedDrawFrame!.viewport
|
|
521
|
-
: this.deps.getViewportManager().computeViewport()
|
|
533
|
+
const vp = useCachedFrame ? this.cachedDrawFrame!.viewport : this.peekViewport()
|
|
522
534
|
if (!vp) return null
|
|
523
535
|
|
|
524
536
|
const internalData = this.deps.getDataManager().getRenderData() as KLineData[]
|
|
525
537
|
if (internalData.length === 0) return null
|
|
526
538
|
|
|
527
539
|
const opt = this.deps.getOption()
|
|
528
|
-
|
|
540
|
+
// 可见区间 SSOT 在 viewportState:clamped 可索引;raw 含扩窗(start 可能为 -1)
|
|
541
|
+
const range = useCachedFrame
|
|
529
542
|
? this.cachedDrawFrame!.range
|
|
530
|
-
: (
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
opt.kWidth,
|
|
535
|
-
opt.kGap,
|
|
536
|
-
internalData.length,
|
|
537
|
-
vp.dpr,
|
|
538
|
-
)
|
|
539
|
-
return { start, end }
|
|
540
|
-
})()
|
|
541
|
-
const range = { start: Math.max(0, rawRange.start), end: rawRange.end }
|
|
543
|
+
: this.deps.viewport.readonly.visibleRange.peek()
|
|
544
|
+
const rawRange = useCachedFrame
|
|
545
|
+
? (this._prevFrameRange?.raw ?? range)
|
|
546
|
+
: this.deps.viewport.readonly.rawVisibleRange.peek()
|
|
542
547
|
|
|
543
548
|
const dataManager = this.deps.getDataManager()
|
|
544
549
|
const mode = this.deps.getActiveMode()
|
|
@@ -568,6 +573,7 @@ export class ChartRenderer {
|
|
|
568
573
|
kWidthPx = this.cachedDrawFrame!.kWidthPx
|
|
569
574
|
} else {
|
|
570
575
|
const physConfig = getPhysicalKLineConfig(opt.kWidth, opt.kGap, vp.dpr)
|
|
576
|
+
// bar 宽度取奇数,保证 center 对齐整数像素
|
|
571
577
|
let barWidthPx = Math.max(1, physConfig.unitPx - 1)
|
|
572
578
|
if (barWidthPx % 2 === 0) barWidthPx -= 1
|
|
573
579
|
|
|
@@ -577,6 +583,7 @@ export class ChartRenderer {
|
|
|
577
583
|
for (let i = 0; i < kLinePositions.length; i++) {
|
|
578
584
|
const x = kLinePositions[i]!
|
|
579
585
|
const leftPx = Math.round(x * vp.dpr)
|
|
586
|
+
// 影线 center = left + 半根物理宽度
|
|
580
587
|
const wickXPx = leftPx + (physConfig.kWidthPx - 1) / 2
|
|
581
588
|
kLineCenters[i] = wickXPx / vp.dpr
|
|
582
589
|
|
|
@@ -584,28 +591,31 @@ export class ChartRenderer {
|
|
|
584
591
|
kBarRects[i] = { x: barLeftPx / vp.dpr, width: barWidthPx / vp.dpr }
|
|
585
592
|
}
|
|
586
593
|
|
|
594
|
+
// TimeShare:按全天 sessionSlots 划分宽度,已到达点落在时间线上,未到时段右侧留白
|
|
587
595
|
if (mode.debugName === 'TimeShare') {
|
|
588
|
-
const totalWidth = vp.plotWidth
|
|
589
596
|
const count = kLineCenters.length
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
const halfBarPx = Math.floor(
|
|
597
|
+
const marketSession =
|
|
598
|
+
'marketSession' in mode && mode.marketSession
|
|
599
|
+
? (mode as { marketSession: typeof ASHARE_MARKET_SESSION }).marketSession
|
|
600
|
+
: ASHARE_MARKET_SESSION
|
|
601
|
+
const layout = computeTimeShareXLayout({
|
|
602
|
+
arrivedCount: count,
|
|
603
|
+
sessionSlots: resolveMarketSessionSlots(marketSession),
|
|
604
|
+
totalWidth: vp.plotWidth,
|
|
605
|
+
dpr: vp.dpr,
|
|
606
|
+
})
|
|
607
|
+
if (layout) {
|
|
608
|
+
const halfBarPx = Math.floor((layout.barWidth * vp.dpr) / 2)
|
|
602
609
|
for (let i = 0; i < count; i++) {
|
|
603
|
-
|
|
610
|
+
kLineCenters[i] = layout.centers[i]!
|
|
611
|
+
kLinePositions[i] = layout.lefts[i]!
|
|
612
|
+
const centerPx = Math.round(layout.centers[i]! * vp.dpr)
|
|
604
613
|
kBarRects[i] = {
|
|
605
|
-
x: (centerPx - halfBarPx) / dpr,
|
|
606
|
-
width:
|
|
614
|
+
x: (centerPx - halfBarPx) / vp.dpr,
|
|
615
|
+
width: layout.barWidth,
|
|
607
616
|
}
|
|
608
617
|
}
|
|
618
|
+
kWidthPx = layout.kWidthPx
|
|
609
619
|
} else {
|
|
610
620
|
kWidthPx = getPhysicalKLineConfig(opt.kWidth, opt.kGap, vp.dpr).kWidthPx
|
|
611
621
|
}
|
|
@@ -631,8 +641,8 @@ export class ChartRenderer {
|
|
|
631
641
|
kWidthPx,
|
|
632
642
|
useCachedFrame,
|
|
633
643
|
data: internalData,
|
|
634
|
-
zoomLevel: this.deps.
|
|
635
|
-
zoomLevelCount: this.deps.
|
|
644
|
+
zoomLevel: this.deps.zoom.readonly.zoomLevel.peek(),
|
|
645
|
+
zoomLevelCount: this.deps.options.readonly.options.peek().zoomLevelCount,
|
|
636
646
|
}
|
|
637
647
|
}
|
|
638
648
|
|
|
@@ -648,20 +658,28 @@ export class ChartRenderer {
|
|
|
648
658
|
}
|
|
649
659
|
|
|
650
660
|
clearAllCanvases(): void {
|
|
651
|
-
const vp = this.
|
|
661
|
+
const vp = this.peekViewport()
|
|
652
662
|
if (!vp) return
|
|
653
663
|
for (const r of this.deps.getPaneRenderers()) {
|
|
654
|
-
const { mainCtx, overlayCtx, yAxisCtx, leftAxisCtx } =
|
|
664
|
+
const { mainCtx, overlayCtx, yAxisCtx, yAxisOverlayCtx, leftAxisCtx, leftAxisOverlayCtx } =
|
|
665
|
+
r.getContexts()
|
|
655
666
|
const pane = r.getPane()
|
|
656
667
|
mainCtx?.clearRect(0, 0, vp.plotWidth + 1, pane.height + 2 / vp.dpr)
|
|
657
668
|
overlayCtx?.clearRect(0, 0, vp.plotWidth + 1, pane.height + 2 / vp.dpr)
|
|
658
|
-
yAxisCtx?.clearRect(0, 0, vp.plotWidth + 1, pane.height + 2 / vp.dpr)
|
|
669
|
+
yAxisCtx?.clearRect(0, 0, (yAxisCtx.canvas?.width ?? 0) / vp.dpr || vp.plotWidth + 1, pane.height + 2 / vp.dpr)
|
|
670
|
+
yAxisOverlayCtx?.clearRect(
|
|
671
|
+
0,
|
|
672
|
+
0,
|
|
673
|
+
(yAxisOverlayCtx.canvas?.width ?? 0) / vp.dpr || vp.plotWidth + 1,
|
|
674
|
+
pane.height + 2 / vp.dpr,
|
|
675
|
+
)
|
|
659
676
|
if (leftAxisCtx) {
|
|
660
|
-
const
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
677
|
+
const laW = (leftAxisCtx.canvas?.width ?? 0) / vp.dpr || vp.plotWidth + 1
|
|
678
|
+
leftAxisCtx.clearRect(0, 0, laW, pane.height + 2 / vp.dpr)
|
|
679
|
+
}
|
|
680
|
+
if (leftAxisOverlayCtx) {
|
|
681
|
+
const laW = (leftAxisOverlayCtx.canvas?.width ?? 0) / vp.dpr || vp.plotWidth + 1
|
|
682
|
+
leftAxisOverlayCtx.clearRect(0, 0, laW, pane.height + 2 / vp.dpr)
|
|
665
683
|
}
|
|
666
684
|
}
|
|
667
685
|
const xCtx = this.xAxisCtx
|
|
@@ -683,19 +701,20 @@ export class ChartRenderer {
|
|
|
683
701
|
}
|
|
684
702
|
}
|
|
685
703
|
|
|
704
|
+
/** 遍历所有 pane,逐 pane 清 canvas → 构建 RenderContext → beginFrame → scene.paintPane,所有 pane 结束后 endFrame 统一提交 GPU / 时间轴 */
|
|
686
705
|
private renderPanes(
|
|
687
706
|
vp: Viewport,
|
|
688
707
|
range: VisibleRange,
|
|
689
708
|
kLinePositions: KLinePositions,
|
|
690
709
|
kLineCenters: number[],
|
|
691
710
|
kBarRects: Array<{ x: number; width: number }>,
|
|
692
|
-
kWidthPx: number,
|
|
693
711
|
mainIndicatorRange: { min: number; max: number } | null,
|
|
694
712
|
hasCrosshair: boolean,
|
|
695
713
|
useCachedFrame: boolean,
|
|
696
714
|
level: UpdateLevel,
|
|
697
715
|
renderData: unknown[],
|
|
698
716
|
): { sharedXAxisLabels: XAxisLabel[]; sharedXAxisRanges: XAxisRange[] } {
|
|
717
|
+
// 跨 pane 共享的 Y/X 轴 labels 和 ranges(各 layer 写入,时间轴层读取)
|
|
699
718
|
const sharedYAxisLabels: YAxisLabel[] = []
|
|
700
719
|
const sharedXAxisLabels: XAxisLabel[] = []
|
|
701
720
|
const sharedYAxisRanges: YAxisRange[] = []
|
|
@@ -704,10 +723,28 @@ export class ChartRenderer {
|
|
|
704
723
|
const dataManager = this.deps.getDataManager()
|
|
705
724
|
const mode = this.deps.getActiveMode()
|
|
706
725
|
|
|
726
|
+
// main canvas 只画非 overlay 角色;overlay canvas 只画 overlay 角色
|
|
727
|
+
const MAIN_CANVAS_ROLES: readonly LayerRole[] = [
|
|
728
|
+
'background',
|
|
729
|
+
'primary',
|
|
730
|
+
'indicator',
|
|
731
|
+
'component',
|
|
732
|
+
'drawing',
|
|
733
|
+
]
|
|
734
|
+
|
|
735
|
+
// 遍历主图 pane 和所有子图 pane,每个 pane 有一组独立 canvas 以及对应更新级别(main/overlay/yAxis)
|
|
707
736
|
for (const renderer of this.deps.getPaneRenderers()) {
|
|
708
737
|
const pane = renderer.getPane()
|
|
709
|
-
const {
|
|
710
|
-
|
|
738
|
+
const {
|
|
739
|
+
mainCtx,
|
|
740
|
+
overlayCtx,
|
|
741
|
+
yAxisCtx,
|
|
742
|
+
yAxisOverlayCtx,
|
|
743
|
+
leftAxisCtx,
|
|
744
|
+
leftAxisOverlayCtx,
|
|
745
|
+
} = renderer.getContexts()
|
|
746
|
+
|
|
747
|
+
// 非缓存帧:合并指标与对比标的极值,更新 pane Y 轴范围
|
|
711
748
|
if (!useCachedFrame) {
|
|
712
749
|
const indicatorRange =
|
|
713
750
|
pane.role === 'price' && mode.useIndicatorScheduler ? mainIndicatorRange : null
|
|
@@ -720,17 +757,21 @@ export class ChartRenderer {
|
|
|
720
757
|
}
|
|
721
758
|
}
|
|
722
759
|
|
|
760
|
+
// 根据 UpdateLevel 决定清哪些 canvas
|
|
723
761
|
const shouldUpdateMain = level === UpdateLevel.Main || level === UpdateLevel.All
|
|
762
|
+
// Overlay 单独重绘:有十字线才画;overlayHadCrosshair 保证十字线消失时最后清一次
|
|
724
763
|
const shouldUpdateOverlay =
|
|
725
764
|
level === UpdateLevel.All ||
|
|
726
765
|
(level === UpdateLevel.Overlay && (hasCrosshair || this.overlayHadCrosshair))
|
|
727
766
|
|
|
767
|
+
// 清 main canvas
|
|
728
768
|
if (shouldUpdateMain && mainCtx) {
|
|
729
769
|
mainCtx.setTransform(1, 0, 0, 1, 0, 0)
|
|
730
770
|
mainCtx.scale(vp.dpr, vp.dpr)
|
|
731
771
|
mainCtx.clearRect(0, 0, vp.plotWidth + 1, pane.height + 2 / vp.dpr)
|
|
732
772
|
}
|
|
733
773
|
|
|
774
|
+
// 清 overlay canvas
|
|
734
775
|
if (shouldUpdateOverlay && overlayCtx) {
|
|
735
776
|
const overlayWidth = overlayCtx.canvas.width / vp.dpr
|
|
736
777
|
overlayCtx.setTransform(1, 0, 0, 1, 0, 0)
|
|
@@ -738,15 +779,26 @@ export class ChartRenderer {
|
|
|
738
779
|
overlayCtx.clearRect(0, 0, overlayWidth + 1, pane.height + 2 / vp.dpr)
|
|
739
780
|
}
|
|
740
781
|
|
|
741
|
-
|
|
782
|
+
// 清 Y 轴静态 canvas(Main/All)
|
|
783
|
+
if (shouldUpdateMain && yAxisCtx) {
|
|
742
784
|
const yAxisWidth = yAxisCtx.canvas.width / vp.dpr
|
|
743
785
|
this.clearAxisCtx(yAxisCtx, vp.dpr, yAxisWidth, pane.height)
|
|
744
786
|
}
|
|
745
|
-
if (
|
|
787
|
+
if (shouldUpdateMain && leftAxisCtx) {
|
|
746
788
|
const leftAxisWidth = leftAxisCtx.canvas.width / vp.dpr
|
|
747
789
|
this.clearAxisCtx(leftAxisCtx, vp.dpr, leftAxisWidth, pane.height)
|
|
748
790
|
}
|
|
791
|
+
// 清 Y 轴动态 canvas(Overlay/All)
|
|
792
|
+
if (shouldUpdateOverlay && yAxisOverlayCtx) {
|
|
793
|
+
const yAxisWidth = yAxisOverlayCtx.canvas.width / vp.dpr
|
|
794
|
+
this.clearAxisCtx(yAxisOverlayCtx, vp.dpr, yAxisWidth, pane.height)
|
|
795
|
+
}
|
|
796
|
+
if (shouldUpdateOverlay && leftAxisOverlayCtx) {
|
|
797
|
+
const leftAxisWidth = leftAxisOverlayCtx.canvas.width / vp.dpr
|
|
798
|
+
this.clearAxisCtx(leftAxisOverlayCtx, vp.dpr, leftAxisWidth, pane.height)
|
|
799
|
+
}
|
|
749
800
|
|
|
801
|
+
// 构造本 pane 的 RenderContext,供所有 layer 读取
|
|
750
802
|
const opt = this.deps.getOption()
|
|
751
803
|
const context: RenderContext = {
|
|
752
804
|
ctx: mainCtx!,
|
|
@@ -769,26 +821,35 @@ export class ChartRenderer {
|
|
|
769
821
|
markerManager: this.markerManager,
|
|
770
822
|
crosshairIndex: this.deps.getInteraction().getCrosshairIndex(),
|
|
771
823
|
yAxisCtx: yAxisCtx ?? undefined,
|
|
824
|
+
yAxisOverlayCtx: yAxisOverlayCtx ?? undefined,
|
|
772
825
|
leftAxisCtx: leftAxisCtx ?? undefined,
|
|
773
|
-
|
|
774
|
-
|
|
826
|
+
leftAxisOverlayCtx: leftAxisOverlayCtx ?? undefined,
|
|
827
|
+
zoomLevel: this.deps.zoom.readonly.zoomLevel.peek(),
|
|
828
|
+
zoomLevelCount: this.deps.options.readonly.options.peek().zoomLevelCount,
|
|
775
829
|
viewport: {
|
|
776
830
|
scrollLeft: vp.scrollLeft,
|
|
777
831
|
plotWidth: vp.plotWidth,
|
|
778
832
|
plotHeight: vp.plotHeight,
|
|
779
833
|
},
|
|
780
|
-
settings:
|
|
834
|
+
settings: {
|
|
835
|
+
...this.settings,
|
|
836
|
+
// 分时昨收优先读 series 元数据,settings 作回退
|
|
837
|
+
preClose:
|
|
838
|
+
dataManager.getTimeSharePreClose() ??
|
|
839
|
+
(this.settings.preClose as number | undefined),
|
|
840
|
+
},
|
|
781
841
|
yAxisLabels: sharedYAxisLabels,
|
|
782
842
|
xAxisLabels: sharedXAxisLabels,
|
|
783
843
|
yAxisRanges: sharedYAxisRanges,
|
|
784
844
|
xAxisRanges: sharedXAxisRanges,
|
|
785
|
-
theme: this.deps.
|
|
845
|
+
theme: this.deps.theme$.peek(),
|
|
786
846
|
isAsiaMarket: this.settings.isAsiaMarket as boolean,
|
|
787
847
|
colorPresetSettings: this.settings.colorPresetSettings,
|
|
788
848
|
monthKeys: dataManager.getMonthKeys() ?? undefined,
|
|
789
849
|
dayKeys: dataManager.getDayKeys() ?? undefined,
|
|
790
850
|
}
|
|
791
851
|
|
|
852
|
+
// 计算本 pane 的 Y 轴刻度(等分 + yToPrice 映射)
|
|
792
853
|
{
|
|
793
854
|
const pt = pane.yAxis.getPaddingTop()
|
|
794
855
|
const pb = pane.yAxis.getPaddingBottom()
|
|
@@ -811,24 +872,32 @@ export class ChartRenderer {
|
|
|
811
872
|
|
|
812
873
|
const region = { x: 0, y: pane.top, width: vp.plotWidth, height: pane.height, dpr: vp.dpr }
|
|
813
874
|
const sceneRenderer = this.deps.getSceneRenderer()
|
|
875
|
+
const paneRole = (pane.id === 'main' ? 'main' : 'sub') as PaneRole
|
|
876
|
+
// 画 main canvas(非 overlay 角色 layer)
|
|
814
877
|
if (shouldUpdateMain) {
|
|
878
|
+
// 标记后续 GPU 绘制属于此 region
|
|
815
879
|
sceneRenderer.beginFrame(region)
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
880
|
+
// 遍历 Scene 中该 pane 的可见 layer,逐层 paint
|
|
881
|
+
this.scene.paintPane(
|
|
882
|
+
{
|
|
883
|
+
renderer: sceneRenderer,
|
|
884
|
+
region,
|
|
885
|
+
paneRole,
|
|
886
|
+
paneId: pane.id,
|
|
887
|
+
frameNumber: this.frameCount++,
|
|
888
|
+
deltaMs: 0,
|
|
889
|
+
},
|
|
890
|
+
MAIN_CANVAS_ROLES,
|
|
891
|
+
)
|
|
824
892
|
}
|
|
825
|
-
|
|
893
|
+
// 画 overlay canvas(仅 overlay 角色 layer);All 级也画
|
|
894
|
+
if (shouldUpdateOverlay) {
|
|
826
895
|
sceneRenderer.beginFrame(region)
|
|
827
896
|
this.scene.paintPane(
|
|
828
897
|
{
|
|
829
898
|
renderer: sceneRenderer,
|
|
830
899
|
region,
|
|
831
|
-
paneRole
|
|
900
|
+
paneRole,
|
|
832
901
|
paneId: pane.id,
|
|
833
902
|
frameNumber: this.frameCount++,
|
|
834
903
|
deltaMs: 0,
|
|
@@ -838,7 +907,7 @@ export class ChartRenderer {
|
|
|
838
907
|
}
|
|
839
908
|
}
|
|
840
909
|
|
|
841
|
-
//
|
|
910
|
+
// 所有 pane 绘制完成后统一提交 GPU(WebGPU 单次 queue.submit,WebGL 单次 flush)
|
|
842
911
|
this.deps.getSceneRenderer().endFrame()
|
|
843
912
|
|
|
844
913
|
return { sharedXAxisLabels, sharedXAxisRanges }
|
|
@@ -911,7 +980,7 @@ export class ChartRenderer {
|
|
|
911
980
|
yAxisLabels: [],
|
|
912
981
|
xAxisLabels: sharedXAxisLabels,
|
|
913
982
|
xAxisRanges: sharedXAxisRanges,
|
|
914
|
-
theme: this.deps.
|
|
983
|
+
theme: this.deps.theme$.peek(),
|
|
915
984
|
isAsiaMarket: this.settings.isAsiaMarket as boolean,
|
|
916
985
|
colorPresetSettings: this.settings.colorPresetSettings,
|
|
917
986
|
monthKeys: dataManager.getMonthKeys() ?? undefined,
|
|
@@ -935,7 +1004,7 @@ export class ChartRenderer {
|
|
|
935
1004
|
|
|
936
1005
|
if (count <= 0) return []
|
|
937
1006
|
|
|
938
|
-
const dpr = this.deps.
|
|
1007
|
+
const dpr = this.deps.viewport.readonly.dpr.peek()
|
|
939
1008
|
const opt = this.deps.getOption()
|
|
940
1009
|
const { unitPx, startXPx } = getPhysicalKLineConfig(opt.kWidth, opt.kGap, dpr)
|
|
941
1010
|
|