@363045841yyt/klinechart-core 0.7.3 → 0.7.5-alpha.2
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/README.md +201 -201
- package/README.zh-CN.md +201 -201
- package/dist/engine/renderers/webgl/candleSurface.js +47 -47
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -2
- package/dist/version.js.map +1 -1
- package/package.json +129 -122
- package/src/__tests__/signal.test.ts +124 -124
- package/src/config/chartSettings.ts +66 -66
- package/src/controllers/__tests__/drawing.test.ts +214 -214
- package/src/controllers/__tests__/indicatorSelector.test.ts +481 -481
- package/src/controllers/__tests__/toolbar.test.ts +225 -225
- package/src/controllers/createChartController.ts +665 -665
- package/src/controllers/createDrawingController.ts +96 -96
- package/src/controllers/createIndicatorSelectorController.ts +307 -307
- package/src/controllers/createToolbarController.ts +146 -146
- package/src/controllers/index.ts +19 -19
- package/src/controllers/types.ts +284 -284
- package/src/engine/__tests__/chart.dpr.test.ts +401 -401
- package/src/engine/__tests__/paneRenderer.resize.test.ts +92 -92
- package/src/engine/chart-store.ts +121 -121
- package/src/engine/chart.d.ts +617 -617
- package/src/engine/chart.ts +2815 -2815
- package/src/engine/controller/__tests__/interaction.dpr.test.ts +259 -259
- package/src/engine/controller/interaction.ts +722 -722
- package/src/engine/controller/markerInteraction.ts +130 -130
- package/src/engine/controller/pinchTracker.ts +82 -82
- package/src/engine/controller/tooltipPosition.ts +48 -48
- package/src/engine/draw/__tests__/pixelAlign.spec.ts +176 -176
- package/src/engine/draw/pixelAlign.ts +259 -259
- package/src/engine/drawing/index.ts +655 -655
- package/src/engine/drawing/interaction.ts +842 -842
- package/src/engine/drawing/plugin.ts +343 -343
- package/src/engine/indicators/__tests__/__fixtures__/golden/atr.json +38 -38
- package/src/engine/indicators/__tests__/__fixtures__/golden/dema.json +14 -14
- package/src/engine/indicators/__tests__/__fixtures__/golden/hma.json +14 -14
- package/src/engine/indicators/__tests__/__fixtures__/golden/index.ts +55 -55
- package/src/engine/indicators/__tests__/__fixtures__/golden/kama.json +14 -14
- package/src/engine/indicators/__tests__/__fixtures__/golden/tema.json +14 -14
- package/src/engine/indicators/__tests__/__fixtures__/golden/wma.json +40 -40
- package/src/engine/indicators/__tests__/__fixtures__/synthetic.ts +65 -65
- package/src/engine/indicators/__tests__/_propertyAssertions.ts +76 -76
- package/src/engine/indicators/__tests__/atr.test.ts +153 -153
- package/src/engine/indicators/__tests__/calculators.test.ts +614 -614
- package/src/engine/indicators/__tests__/cmf-mfi.test.ts +100 -100
- package/src/engine/indicators/__tests__/dema.test.ts +73 -73
- package/src/engine/indicators/__tests__/donchian.test.ts +70 -70
- package/src/engine/indicators/__tests__/hma.test.ts +73 -73
- package/src/engine/indicators/__tests__/ichimoku.test.ts +105 -105
- package/src/engine/indicators/__tests__/kama.test.ts +80 -80
- package/src/engine/indicators/__tests__/keltner.test.ts +65 -65
- package/src/engine/indicators/__tests__/pivot-fib.test.ts +110 -110
- package/src/engine/indicators/__tests__/roc.test.ts +68 -68
- package/src/engine/indicators/__tests__/sar.test.ts +86 -86
- package/src/engine/indicators/__tests__/scheduler.test.ts +831 -831
- package/src/engine/indicators/__tests__/soa.test.ts +533 -533
- package/src/engine/indicators/__tests__/structure.test.ts +110 -110
- package/src/engine/indicators/__tests__/supertrend.test.ts +65 -65
- package/src/engine/indicators/__tests__/tema.test.ts +68 -68
- package/src/engine/indicators/__tests__/trix.test.ts +70 -70
- package/src/engine/indicators/__tests__/volatility.test.ts +117 -117
- package/src/engine/indicators/__tests__/volume.test.ts +115 -115
- package/src/engine/indicators/__tests__/volumeProfile.test.ts +74 -74
- package/src/engine/indicators/__tests__/vwap.test.ts +69 -69
- package/src/engine/indicators/__tests__/wma.test.ts +112 -112
- package/src/engine/indicators/__tests__/zones.test.ts +95 -95
- package/src/engine/indicators/atrState.ts +27 -27
- package/src/engine/indicators/bollState.ts +51 -51
- package/src/engine/indicators/calculators.ts +2593 -2593
- package/src/engine/indicators/cciState.ts +25 -25
- package/src/engine/indicators/chaikinVolState.ts +32 -32
- package/src/engine/indicators/cmfState.ts +27 -27
- package/src/engine/indicators/demaState.ts +27 -27
- package/src/engine/indicators/donchianState.ts +43 -43
- package/src/engine/indicators/eneState.ts +43 -43
- package/src/engine/indicators/expmaState.ts +43 -43
- package/src/engine/indicators/fastkState.ts +25 -25
- package/src/engine/indicators/fibState.ts +41 -41
- package/src/engine/indicators/hmaState.ts +27 -27
- package/src/engine/indicators/hvState.ts +28 -28
- package/src/engine/indicators/ichimokuState.ts +70 -70
- package/src/engine/indicators/indicator.worker.ts +169 -169
- package/src/engine/indicators/indicatorDefinitionRegistry.ts +62 -62
- package/src/engine/indicators/indicatorMetadata.ts +110 -110
- package/src/engine/indicators/indicatorRegistry.ts +106 -106
- package/src/engine/indicators/indicatorRuntime.ts +1548 -1548
- package/src/engine/indicators/kamaState.ts +34 -34
- package/src/engine/indicators/keltnerState.ts +49 -49
- package/src/engine/indicators/kstState.ts +42 -42
- package/src/engine/indicators/maState.ts +36 -36
- package/src/engine/indicators/macdState.ts +76 -76
- package/src/engine/indicators/mfiState.ts +27 -27
- package/src/engine/indicators/momState.ts +25 -25
- package/src/engine/indicators/obvState.ts +25 -25
- package/src/engine/indicators/parkinsonState.ts +28 -28
- package/src/engine/indicators/pivotState.ts +51 -51
- package/src/engine/indicators/pvtState.ts +25 -25
- package/src/engine/indicators/rocState.ts +27 -27
- package/src/engine/indicators/rsiState.ts +65 -65
- package/src/engine/indicators/sarState.ts +41 -41
- package/src/engine/indicators/scheduler.ts +1205 -1205
- package/src/engine/indicators/soa.ts +352 -352
- package/src/engine/indicators/stateComposer.ts +1262 -1262
- package/src/engine/indicators/stochState.ts +26 -26
- package/src/engine/indicators/structureState.ts +69 -69
- package/src/engine/indicators/supertrendState.ts +37 -37
- package/src/engine/indicators/temaState.ts +27 -27
- package/src/engine/indicators/trixState.ts +35 -35
- package/src/engine/indicators/vmaState.ts +27 -27
- package/src/engine/indicators/volumeProfileState.ts +63 -63
- package/src/engine/indicators/vwapState.ts +29 -29
- package/src/engine/indicators/wmaState.ts +27 -27
- package/src/engine/indicators/wmsrState.ts +25 -25
- package/src/engine/indicators/workerProtocol.ts +613 -613
- package/src/engine/indicators/zonesState.ts +47 -47
- package/src/engine/layout/pane.ts +161 -161
- package/src/engine/marker/registry.ts +265 -265
- package/src/engine/paneRenderer.ts +169 -169
- package/src/engine/renderers/Indicator/atr.ts +237 -237
- package/src/engine/renderers/Indicator/boll.ts +317 -317
- package/src/engine/renderers/Indicator/cci.ts +275 -275
- package/src/engine/renderers/Indicator/chaikinVol.ts +138 -138
- package/src/engine/renderers/Indicator/cmf.ts +137 -137
- package/src/engine/renderers/Indicator/dema.ts +136 -136
- package/src/engine/renderers/Indicator/donchian.ts +137 -137
- package/src/engine/renderers/Indicator/ene.ts +271 -271
- package/src/engine/renderers/Indicator/expma.ts +197 -197
- package/src/engine/renderers/Indicator/fastk.ts +316 -316
- package/src/engine/renderers/Indicator/fib.ts +141 -141
- package/src/engine/renderers/Indicator/hma.ts +136 -136
- package/src/engine/renderers/Indicator/hv.ts +124 -124
- package/src/engine/renderers/Indicator/ichimoku.ts +181 -181
- package/src/engine/renderers/Indicator/index.ts +241 -241
- package/src/engine/renderers/Indicator/indicatorData.ts +650 -650
- package/src/engine/renderers/Indicator/kama.ts +136 -136
- package/src/engine/renderers/Indicator/keltner.ts +137 -137
- package/src/engine/renderers/Indicator/kst.ts +302 -302
- package/src/engine/renderers/Indicator/ma.ts +200 -200
- package/src/engine/renderers/Indicator/macd.ts +477 -477
- package/src/engine/renderers/Indicator/macdLegend.ts +141 -141
- package/src/engine/renderers/Indicator/mainIndicatorLegend.ts +272 -272
- package/src/engine/renderers/Indicator/mfi.ts +142 -142
- package/src/engine/renderers/Indicator/mom.ts +311 -311
- package/src/engine/renderers/Indicator/obv.ts +123 -123
- package/src/engine/renderers/Indicator/parkinson.ts +124 -124
- package/src/engine/renderers/Indicator/pivot.ts +131 -131
- package/src/engine/renderers/Indicator/pvt.ts +123 -123
- package/src/engine/renderers/Indicator/roc.ts +143 -143
- package/src/engine/renderers/Indicator/rsi.ts +390 -390
- package/src/engine/renderers/Indicator/sar.ts +113 -113
- package/src/engine/renderers/Indicator/scale/atr_scale.ts +19 -19
- package/src/engine/renderers/Indicator/scale/cci_scale.ts +19 -19
- package/src/engine/renderers/Indicator/scale/fastk_scale.ts +19 -19
- package/src/engine/renderers/Indicator/scale/indicator_scale.ts +204 -204
- package/src/engine/renderers/Indicator/scale/kst_scale.ts +19 -19
- package/src/engine/renderers/Indicator/scale/macd_scale.ts +22 -22
- package/src/engine/renderers/Indicator/scale/mom_scale.ts +19 -19
- package/src/engine/renderers/Indicator/scale/rsi_scale.ts +19 -19
- package/src/engine/renderers/Indicator/scale/stoch_scale.ts +19 -19
- package/src/engine/renderers/Indicator/scale/volume_scale.ts +26 -26
- package/src/engine/renderers/Indicator/scale/wmsr_scale.ts +19 -19
- package/src/engine/renderers/Indicator/stoch.ts +359 -359
- package/src/engine/renderers/Indicator/structure.ts +126 -126
- package/src/engine/renderers/Indicator/subPaneConfig.ts +265 -265
- package/src/engine/renderers/Indicator/supertrend.ts +115 -115
- package/src/engine/renderers/Indicator/tema.ts +136 -136
- package/src/engine/renderers/Indicator/trix.ts +158 -158
- package/src/engine/renderers/Indicator/vma.ts +124 -124
- package/src/engine/renderers/Indicator/volumeProfile.ts +125 -125
- package/src/engine/renderers/Indicator/vwap.ts +123 -123
- package/src/engine/renderers/Indicator/wma.ts +136 -136
- package/src/engine/renderers/Indicator/wmsr.ts +328 -328
- package/src/engine/renderers/Indicator/zones.ts +104 -104
- package/src/engine/renderers/__tests__/boll.renderer.test.ts +314 -314
- package/src/engine/renderers/__tests__/ene.renderer.test.ts +305 -305
- package/src/engine/renderers/__tests__/expma.renderer.test.ts +279 -279
- package/src/engine/renderers/__tests__/ma.renderer.test.ts +426 -426
- package/src/engine/renderers/__tests__/mainIndicatorLegend.renderer.test.ts +502 -502
- package/src/engine/renderers/__tests__/yAxis.renderer.test.ts +173 -173
- package/src/engine/renderers/candle.ts +459 -459
- package/src/engine/renderers/crosshair.ts +69 -69
- package/src/engine/renderers/customMarkers.ts +162 -162
- package/src/engine/renderers/extremaMarkers.ts +246 -246
- package/src/engine/renderers/gridLines.ts +90 -90
- package/src/engine/renderers/lastPrice.ts +97 -97
- package/src/engine/renderers/paneTitle.ts +136 -136
- package/src/engine/renderers/subVolume.ts +236 -236
- package/src/engine/renderers/timeAxis.ts +121 -121
- package/src/engine/renderers/webgl/candleSurface.ts +955 -955
- package/src/engine/renderers/webgl/sharedWebGLSurface.ts +146 -146
- package/src/engine/renderers/yAxis.ts +105 -105
- package/src/engine/scale/__tests__/logFormula.spec.ts +148 -148
- package/src/engine/scale/logFormula.ts +130 -130
- package/src/engine/scale/price.ts +39 -39
- package/src/engine/scale/priceScale.ts +264 -264
- package/src/engine/subPaneManager.ts +427 -427
- package/src/engine/theme/colors.ts +642 -642
- package/src/engine/theme/fonts.ts +20 -20
- package/src/engine/utils/klineConfig.ts +49 -49
- package/src/engine/utils/tickCount.ts +11 -11
- package/src/engine/utils/tickPosition.ts +214 -214
- package/src/engine/utils/zoom.ts +83 -83
- package/src/engine/viewport/viewport.ts +67 -67
- package/src/index.ts +3 -3
- package/src/plugin/ConfigManager.ts +93 -93
- package/src/plugin/EventBus.ts +77 -77
- package/src/plugin/HookSystem.ts +106 -106
- package/src/plugin/PluginHost.ts +243 -243
- package/src/plugin/PluginRegistry.ts +92 -92
- package/src/plugin/StateStore.ts +73 -73
- package/src/plugin/index.ts +19 -19
- package/src/plugin/rendererPluginManager.ts +368 -368
- package/src/plugin/stateKeys.ts +8 -8
- package/src/plugin/types.ts +526 -526
- package/src/reactivity/index.ts +2 -2
- package/src/reactivity/signal.ts +119 -119
- package/src/semantic/controller.ts +251 -251
- package/src/semantic/drawShape.ts +260 -260
- package/src/semantic/index.ts +28 -28
- package/src/semantic/schema.json +256 -256
- package/src/semantic/types.ts +251 -251
- package/src/semantic/validator.ts +349 -349
- package/src/types/kLine.ts +13 -13
- package/src/types/price.ts +56 -56
- package/src/types/volumePrice.ts +33 -33
- package/src/utils/dateFormat.ts +208 -208
- package/src/utils/kLineDraw/axis.ts +562 -562
- package/src/utils/priceToY.ts +34 -34
- package/src/utils/volumePrice.ts +202 -202
- package/src/version.ts +1 -1
|
@@ -1,368 +1,368 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 渲染器插件管理器
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import type {
|
|
6
|
-
RendererPlugin,
|
|
7
|
-
RenderContext,
|
|
8
|
-
PaneInfo,
|
|
9
|
-
RendererPluginWithHost,
|
|
10
|
-
PluginHost,
|
|
11
|
-
} from './types'
|
|
12
|
-
import { UpdateLevel } from '../engine/layout/pane'
|
|
13
|
-
|
|
14
|
-
/** 渲染器错误事件(裁剪后,不含大数据) */
|
|
15
|
-
export interface RendererErrorEvent {
|
|
16
|
-
name: string
|
|
17
|
-
error: { message: string; stack?: string }
|
|
18
|
-
paneId: string
|
|
19
|
-
timestamp: number
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/** 内部缓存 key(模块私有,避免与外部 paneId 冲突) */
|
|
23
|
-
const GLOBAL_CACHE_KEY = Symbol('renderer:global-cache')
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* 渲染器插件管理器
|
|
27
|
-
*
|
|
28
|
-
* 启用状态优先级:
|
|
29
|
-
* 1. setEnabled() 运行时设置的状态(enabledState 中存在)
|
|
30
|
-
* 2. 插件初始 enabled 字段
|
|
31
|
-
* 3. 默认启用(enabled !== false)
|
|
32
|
-
*/
|
|
33
|
-
export class RendererPluginManager {
|
|
34
|
-
private plugins: Map<string, RendererPlugin> = new Map()
|
|
35
|
-
private pluginHost: PluginHost | null = null
|
|
36
|
-
|
|
37
|
-
// 启用状态(独立存储,避免修改原始插件对象,支持多实例隔离)
|
|
38
|
-
private enabledState: Map<string, boolean> = new Map()
|
|
39
|
-
|
|
40
|
-
// 分组缓存:paneId -> 渲染器列表
|
|
41
|
-
private groupCache: Map<string | symbol, RendererPlugin[]> = new Map()
|
|
42
|
-
|
|
43
|
-
// 合并缓存:paneId -> pane+global 合并后的渲染器列表
|
|
44
|
-
private mergedCache: Map<string | symbol, RendererPlugin[]> = new Map()
|
|
45
|
-
|
|
46
|
-
// 已知的 paneId 集合(用于动态 pane 管理)
|
|
47
|
-
private knownPaneIds: Set<string> = new Set()
|
|
48
|
-
|
|
49
|
-
private cacheInvalid = true
|
|
50
|
-
private onInvalidate: (() => void) | null = null
|
|
51
|
-
|
|
52
|
-
/** 设置重绘回调(由 Chart 注入) */
|
|
53
|
-
setInvalidateCallback(cb: () => void): void {
|
|
54
|
-
this.onInvalidate = cb
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/** 设置 PluginHost(用于支持 RendererPluginWithHost) */
|
|
58
|
-
setPluginHost(host: PluginHost): void {
|
|
59
|
-
this.pluginHost = host
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/** 添加已知的 paneId */
|
|
63
|
-
addKnownPaneId(paneId: string): void {
|
|
64
|
-
this.knownPaneIds.add(paneId)
|
|
65
|
-
this.cacheInvalid = true
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/** 移除 paneId */
|
|
69
|
-
removeKnownPaneId(paneId: string): void {
|
|
70
|
-
this.knownPaneIds.delete(paneId)
|
|
71
|
-
this.cacheInvalid = true
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
/** 覆盖已知 paneId 集合 */
|
|
76
|
-
setKnownPaneIds(paneIds: string[]): void {
|
|
77
|
-
this.knownPaneIds = new Set(paneIds)
|
|
78
|
-
this.cacheInvalid = true
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/** 注册渲染器插件 */
|
|
82
|
-
register(plugin: RendererPlugin | RendererPluginWithHost): void {
|
|
83
|
-
if (this.plugins.has(plugin.name)) {
|
|
84
|
-
console.warn(`Renderer plugin "${plugin.name}" already registered`)
|
|
85
|
-
return
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
this.plugins.set(plugin.name, plugin)
|
|
89
|
-
// 初始化启用状态(仅当初始值有定义时存储)
|
|
90
|
-
if (plugin.enabled !== undefined) {
|
|
91
|
-
this.enabledState.set(plugin.name, plugin.enabled)
|
|
92
|
-
}
|
|
93
|
-
this.cacheInvalid = true
|
|
94
|
-
|
|
95
|
-
// 如果是 RendererPluginWithHost,调用 onInstall
|
|
96
|
-
const withHost = plugin as RendererPluginWithHost
|
|
97
|
-
if (withHost.onInstall && this.pluginHost) {
|
|
98
|
-
try {
|
|
99
|
-
withHost.onInstall(this.pluginHost)
|
|
100
|
-
} catch (e) {
|
|
101
|
-
console.error(`[RendererPlugin] ${plugin.name} onInstall error:`, e)
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// 记录声明的状态命名空间(用于自动清理)
|
|
106
|
-
const namespaces = withHost.getDeclaredNamespaces?.()
|
|
107
|
-
if (namespaces && this.pluginHost) {
|
|
108
|
-
this.pluginHost.registerStateOwner(plugin.name, namespaces)
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// 注册后自动触发重绘
|
|
112
|
-
this.onInvalidate?.()
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/** 移除渲染器插件 */
|
|
116
|
-
unregister(name: string): void {
|
|
117
|
-
const plugin = this.plugins.get(name)
|
|
118
|
-
if (!plugin) return
|
|
119
|
-
|
|
120
|
-
// 自动清理状态(在 onUninstall 之前),仅当插件声明过命名空间时
|
|
121
|
-
const withHost = plugin as RendererPluginWithHost
|
|
122
|
-
if (withHost.getDeclaredNamespaces) {
|
|
123
|
-
this.pluginHost?.clearByOwner(name)
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// 调用卸载回调
|
|
127
|
-
if (plugin.onUninstall) {
|
|
128
|
-
try {
|
|
129
|
-
plugin.onUninstall()
|
|
130
|
-
} catch (e) {
|
|
131
|
-
console.error(`[RendererPlugin] ${plugin.name} onUninstall error:`, e)
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
this.plugins.delete(name)
|
|
136
|
-
this.enabledState.delete(name)
|
|
137
|
-
this.cacheInvalid = true
|
|
138
|
-
|
|
139
|
-
// 卸载后自动触发重绘
|
|
140
|
-
this.onInvalidate?.()
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/** 清空所有插件 */
|
|
144
|
-
clear(): void {
|
|
145
|
-
for (const plugin of this.plugins.values()) {
|
|
146
|
-
if (plugin.onUninstall) {
|
|
147
|
-
try {
|
|
148
|
-
plugin.onUninstall()
|
|
149
|
-
} catch (e) {
|
|
150
|
-
console.error(`[RendererPlugin] ${plugin.name} onUninstall error:`, e)
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
this.plugins.clear()
|
|
155
|
-
this.enabledState.clear()
|
|
156
|
-
this.groupCache.clear()
|
|
157
|
-
this.mergedCache.clear()
|
|
158
|
-
this.cacheInvalid = false
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* 归并两个已排序数组 O(n)
|
|
163
|
-
* 优先级相同时,pane 专属渲染器(a)先于 global 渲染器(b)
|
|
164
|
-
*/
|
|
165
|
-
private mergeSorted(a: RendererPlugin[], b: RendererPlugin[]): RendererPlugin[] {
|
|
166
|
-
const result: RendererPlugin[] = []
|
|
167
|
-
let i = 0,
|
|
168
|
-
j = 0
|
|
169
|
-
while (i < a.length && j < b.length) {
|
|
170
|
-
// 优先级相同时,a(pane 专属)优先
|
|
171
|
-
if (a[i]!.priority <= b[j]!.priority) result.push(a[i++]!)
|
|
172
|
-
else result.push(b[j++]!)
|
|
173
|
-
}
|
|
174
|
-
return [...result, ...a.slice(i), ...b.slice(j)]
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/** 重建缓存(统一管理所有缓存逻辑) */
|
|
178
|
-
private rebuildCache(): void {
|
|
179
|
-
if (!this.cacheInvalid) return
|
|
180
|
-
|
|
181
|
-
this.groupCache.clear()
|
|
182
|
-
this.mergedCache.clear()
|
|
183
|
-
|
|
184
|
-
// 按 paneId 分组
|
|
185
|
-
for (const plugin of this.plugins.values()) {
|
|
186
|
-
const cacheKey = typeof plugin.paneId === 'symbol' ? GLOBAL_CACHE_KEY : plugin.paneId
|
|
187
|
-
if (!this.groupCache.has(cacheKey)) {
|
|
188
|
-
this.groupCache.set(cacheKey, [])
|
|
189
|
-
}
|
|
190
|
-
this.groupCache.get(cacheKey)!.push(plugin)
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// 对每组排序
|
|
194
|
-
for (const [, list] of this.groupCache) {
|
|
195
|
-
list.sort((a, b) => a.priority - b.priority)
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// 预构建合并缓存
|
|
199
|
-
const globalRenderers = this.groupCache.get(GLOBAL_CACHE_KEY) ?? []
|
|
200
|
-
|
|
201
|
-
// 为每个已知 paneId 构建合并缓存
|
|
202
|
-
for (const paneId of this.knownPaneIds) {
|
|
203
|
-
const paneRenderers = this.groupCache.get(paneId) ?? []
|
|
204
|
-
const merged = this.mergeSorted(paneRenderers, globalRenderers)
|
|
205
|
-
this.mergedCache.set(paneId, merged)
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// 缓存纯 global 渲染器作为 fallback
|
|
209
|
-
this.mergedCache.set(GLOBAL_CACHE_KEY, [...globalRenderers])
|
|
210
|
-
|
|
211
|
-
this.cacheInvalid = false
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
/** 判断渲染器是否启用 */
|
|
215
|
-
private isRendererEnabled(plugin: RendererPlugin): boolean {
|
|
216
|
-
const state = this.enabledState.get(plugin.name)
|
|
217
|
-
return state !== undefined ? state : plugin.enabled !== false
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/** 获取指定 pane 的合并渲染器(包含 system 渲染器) */
|
|
221
|
-
private getMergedRenderers(paneId: string): RendererPlugin[] {
|
|
222
|
-
this.rebuildCache()
|
|
223
|
-
|
|
224
|
-
let cached = this.mergedCache.get(paneId)
|
|
225
|
-
if (!cached) {
|
|
226
|
-
const paneRenderers = this.groupCache.get(paneId) ?? []
|
|
227
|
-
const globalRenderers = this.groupCache.get(GLOBAL_CACHE_KEY) ?? []
|
|
228
|
-
cached = this.mergeSorted(paneRenderers, globalRenderers)
|
|
229
|
-
this.mergedCache.set(paneId, cached)
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
return cached
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/** 获取指定 pane 的渲染器(已缓存,无穿透) */
|
|
236
|
-
getRenderers(paneId: string): RendererPlugin[] {
|
|
237
|
-
const cached = this.getMergedRenderers(paneId)
|
|
238
|
-
|
|
239
|
-
// 根据启用状态过滤,同时排除系统渲染器
|
|
240
|
-
return cached.filter((p) => {
|
|
241
|
-
// 系统渲染器不通过 getRenderers 返回,只能通过 renderPlugin 单独渲染
|
|
242
|
-
if (p.isSystem) return false
|
|
243
|
-
return this.isRendererEnabled(p)
|
|
244
|
-
})
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
/** 渲染指定 pane(带错误隔离,支持按 UpdateLevel 过滤) */
|
|
249
|
-
render(
|
|
250
|
-
paneId: string,
|
|
251
|
-
context: RenderContext,
|
|
252
|
-
level?: UpdateLevel
|
|
253
|
-
): RendererErrorEvent[] {
|
|
254
|
-
const renderers = this.getRenderers(paneId)
|
|
255
|
-
const errors: RendererErrorEvent[] = []
|
|
256
|
-
|
|
257
|
-
for (const renderer of renderers) {
|
|
258
|
-
// UpdateLevel 过滤:未传 level 或为 All 时不过滤
|
|
259
|
-
if (level) {
|
|
260
|
-
const rendererLayer = renderer.layer ?? 'main'
|
|
261
|
-
if (level === UpdateLevel.Overlay && rendererLayer !== 'overlay') {
|
|
262
|
-
continue // Overlay 更新时跳过非 overlay 渲染器
|
|
263
|
-
}
|
|
264
|
-
if (level === UpdateLevel.Main && rendererLayer === 'overlay') {
|
|
265
|
-
continue // Main 更新时跳过 overlay 渲染器
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
try {
|
|
270
|
-
renderer.draw(context)
|
|
271
|
-
} catch (e) {
|
|
272
|
-
const error = e instanceof Error ? e : new Error(String(e))
|
|
273
|
-
console.error(`[RendererPlugin] ${renderer.name} draw error:`, error)
|
|
274
|
-
// 裁剪错误事件,不含大数据
|
|
275
|
-
errors.push({
|
|
276
|
-
name: renderer.name,
|
|
277
|
-
error: { message: error.message, stack: error.stack },
|
|
278
|
-
paneId: context.pane.id,
|
|
279
|
-
timestamp: Date.now(),
|
|
280
|
-
})
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
return errors
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
/** 渲染指定名称的插件(带错误隔离,用于系统渲染器) */
|
|
288
|
-
renderPlugin(name: string, context: RenderContext): RendererErrorEvent[] {
|
|
289
|
-
const plugin = this.plugins.get(name)
|
|
290
|
-
if (!plugin) return []
|
|
291
|
-
|
|
292
|
-
// 检查启用状态
|
|
293
|
-
if (!this.isRendererEnabled(plugin)) return []
|
|
294
|
-
|
|
295
|
-
const errors: RendererErrorEvent[] = []
|
|
296
|
-
try {
|
|
297
|
-
plugin.draw(context)
|
|
298
|
-
} catch (e) {
|
|
299
|
-
const error = e instanceof Error ? e : new Error(String(e))
|
|
300
|
-
console.error(`[RendererPlugin] ${name} draw error:`, error)
|
|
301
|
-
errors.push({
|
|
302
|
-
name,
|
|
303
|
-
error: { message: error.message, stack: error.stack },
|
|
304
|
-
paneId: context.pane.id,
|
|
305
|
-
timestamp: Date.now(),
|
|
306
|
-
})
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
return errors
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
/** 启用/禁用渲染器(修改独立状态,不影响原始插件对象) */
|
|
313
|
-
setEnabled(name: string, enabled: boolean): void {
|
|
314
|
-
if (!this.plugins.has(name)) return
|
|
315
|
-
this.enabledState.set(name, enabled)
|
|
316
|
-
this.onInvalidate?.()
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
/** 更新配置(自动触发重绘) */
|
|
320
|
-
updateConfig(name: string, config: Record<string, unknown>): boolean {
|
|
321
|
-
const plugin = this.plugins.get(name)
|
|
322
|
-
if (!plugin?.setConfig) return false
|
|
323
|
-
|
|
324
|
-
plugin.setConfig(config)
|
|
325
|
-
this.onInvalidate?.()
|
|
326
|
-
return true
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
/** 获取所有渲染器插件 */
|
|
330
|
-
getAllPlugins(): RendererPlugin[] {
|
|
331
|
-
return Array.from(this.plugins.values())
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
/** 获取指定渲染器 */
|
|
335
|
-
getPlugin<T extends RendererPlugin = RendererPlugin>(name: string): T | undefined {
|
|
336
|
-
return this.plugins.get(name) as T | undefined
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
/* 调用 onDataUpdate 钩子通知数据更新 */
|
|
340
|
-
notifyDataUpdate(data: unknown[], range: { start: number; end: number }): void {
|
|
341
|
-
for (const plugin of this.plugins.values()) {
|
|
342
|
-
if (!plugin.onDataUpdate) continue
|
|
343
|
-
|
|
344
|
-
// 检查启用状态,跳过禁用的插件
|
|
345
|
-
if (!this.isRendererEnabled(plugin)) continue
|
|
346
|
-
|
|
347
|
-
try {
|
|
348
|
-
plugin.onDataUpdate(data, range)
|
|
349
|
-
} catch (e) {
|
|
350
|
-
console.error(`[RendererPlugin] ${plugin.name} onDataUpdate error:`, e)
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
/** 通知尺寸变化 */
|
|
356
|
-
notifyResize(paneId: string, pane: PaneInfo): void {
|
|
357
|
-
const renderers = this.getMergedRenderers(paneId).filter((renderer) => this.isRendererEnabled(renderer))
|
|
358
|
-
for (const renderer of renderers) {
|
|
359
|
-
if (renderer.onResize) {
|
|
360
|
-
try {
|
|
361
|
-
renderer.onResize(pane)
|
|
362
|
-
} catch (e) {
|
|
363
|
-
console.error(`[RendererPlugin] ${renderer.name} onResize error:`, e)
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* 渲染器插件管理器
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type {
|
|
6
|
+
RendererPlugin,
|
|
7
|
+
RenderContext,
|
|
8
|
+
PaneInfo,
|
|
9
|
+
RendererPluginWithHost,
|
|
10
|
+
PluginHost,
|
|
11
|
+
} from './types'
|
|
12
|
+
import { UpdateLevel } from '../engine/layout/pane'
|
|
13
|
+
|
|
14
|
+
/** 渲染器错误事件(裁剪后,不含大数据) */
|
|
15
|
+
export interface RendererErrorEvent {
|
|
16
|
+
name: string
|
|
17
|
+
error: { message: string; stack?: string }
|
|
18
|
+
paneId: string
|
|
19
|
+
timestamp: number
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** 内部缓存 key(模块私有,避免与外部 paneId 冲突) */
|
|
23
|
+
const GLOBAL_CACHE_KEY = Symbol('renderer:global-cache')
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* 渲染器插件管理器
|
|
27
|
+
*
|
|
28
|
+
* 启用状态优先级:
|
|
29
|
+
* 1. setEnabled() 运行时设置的状态(enabledState 中存在)
|
|
30
|
+
* 2. 插件初始 enabled 字段
|
|
31
|
+
* 3. 默认启用(enabled !== false)
|
|
32
|
+
*/
|
|
33
|
+
export class RendererPluginManager {
|
|
34
|
+
private plugins: Map<string, RendererPlugin> = new Map()
|
|
35
|
+
private pluginHost: PluginHost | null = null
|
|
36
|
+
|
|
37
|
+
// 启用状态(独立存储,避免修改原始插件对象,支持多实例隔离)
|
|
38
|
+
private enabledState: Map<string, boolean> = new Map()
|
|
39
|
+
|
|
40
|
+
// 分组缓存:paneId -> 渲染器列表
|
|
41
|
+
private groupCache: Map<string | symbol, RendererPlugin[]> = new Map()
|
|
42
|
+
|
|
43
|
+
// 合并缓存:paneId -> pane+global 合并后的渲染器列表
|
|
44
|
+
private mergedCache: Map<string | symbol, RendererPlugin[]> = new Map()
|
|
45
|
+
|
|
46
|
+
// 已知的 paneId 集合(用于动态 pane 管理)
|
|
47
|
+
private knownPaneIds: Set<string> = new Set()
|
|
48
|
+
|
|
49
|
+
private cacheInvalid = true
|
|
50
|
+
private onInvalidate: (() => void) | null = null
|
|
51
|
+
|
|
52
|
+
/** 设置重绘回调(由 Chart 注入) */
|
|
53
|
+
setInvalidateCallback(cb: () => void): void {
|
|
54
|
+
this.onInvalidate = cb
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** 设置 PluginHost(用于支持 RendererPluginWithHost) */
|
|
58
|
+
setPluginHost(host: PluginHost): void {
|
|
59
|
+
this.pluginHost = host
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** 添加已知的 paneId */
|
|
63
|
+
addKnownPaneId(paneId: string): void {
|
|
64
|
+
this.knownPaneIds.add(paneId)
|
|
65
|
+
this.cacheInvalid = true
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** 移除 paneId */
|
|
69
|
+
removeKnownPaneId(paneId: string): void {
|
|
70
|
+
this.knownPaneIds.delete(paneId)
|
|
71
|
+
this.cacheInvalid = true
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
/** 覆盖已知 paneId 集合 */
|
|
76
|
+
setKnownPaneIds(paneIds: string[]): void {
|
|
77
|
+
this.knownPaneIds = new Set(paneIds)
|
|
78
|
+
this.cacheInvalid = true
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** 注册渲染器插件 */
|
|
82
|
+
register(plugin: RendererPlugin | RendererPluginWithHost): void {
|
|
83
|
+
if (this.plugins.has(plugin.name)) {
|
|
84
|
+
console.warn(`Renderer plugin "${plugin.name}" already registered`)
|
|
85
|
+
return
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
this.plugins.set(plugin.name, plugin)
|
|
89
|
+
// 初始化启用状态(仅当初始值有定义时存储)
|
|
90
|
+
if (plugin.enabled !== undefined) {
|
|
91
|
+
this.enabledState.set(plugin.name, plugin.enabled)
|
|
92
|
+
}
|
|
93
|
+
this.cacheInvalid = true
|
|
94
|
+
|
|
95
|
+
// 如果是 RendererPluginWithHost,调用 onInstall
|
|
96
|
+
const withHost = plugin as RendererPluginWithHost
|
|
97
|
+
if (withHost.onInstall && this.pluginHost) {
|
|
98
|
+
try {
|
|
99
|
+
withHost.onInstall(this.pluginHost)
|
|
100
|
+
} catch (e) {
|
|
101
|
+
console.error(`[RendererPlugin] ${plugin.name} onInstall error:`, e)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// 记录声明的状态命名空间(用于自动清理)
|
|
106
|
+
const namespaces = withHost.getDeclaredNamespaces?.()
|
|
107
|
+
if (namespaces && this.pluginHost) {
|
|
108
|
+
this.pluginHost.registerStateOwner(plugin.name, namespaces)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// 注册后自动触发重绘
|
|
112
|
+
this.onInvalidate?.()
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** 移除渲染器插件 */
|
|
116
|
+
unregister(name: string): void {
|
|
117
|
+
const plugin = this.plugins.get(name)
|
|
118
|
+
if (!plugin) return
|
|
119
|
+
|
|
120
|
+
// 自动清理状态(在 onUninstall 之前),仅当插件声明过命名空间时
|
|
121
|
+
const withHost = plugin as RendererPluginWithHost
|
|
122
|
+
if (withHost.getDeclaredNamespaces) {
|
|
123
|
+
this.pluginHost?.clearByOwner(name)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// 调用卸载回调
|
|
127
|
+
if (plugin.onUninstall) {
|
|
128
|
+
try {
|
|
129
|
+
plugin.onUninstall()
|
|
130
|
+
} catch (e) {
|
|
131
|
+
console.error(`[RendererPlugin] ${plugin.name} onUninstall error:`, e)
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
this.plugins.delete(name)
|
|
136
|
+
this.enabledState.delete(name)
|
|
137
|
+
this.cacheInvalid = true
|
|
138
|
+
|
|
139
|
+
// 卸载后自动触发重绘
|
|
140
|
+
this.onInvalidate?.()
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** 清空所有插件 */
|
|
144
|
+
clear(): void {
|
|
145
|
+
for (const plugin of this.plugins.values()) {
|
|
146
|
+
if (plugin.onUninstall) {
|
|
147
|
+
try {
|
|
148
|
+
plugin.onUninstall()
|
|
149
|
+
} catch (e) {
|
|
150
|
+
console.error(`[RendererPlugin] ${plugin.name} onUninstall error:`, e)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
this.plugins.clear()
|
|
155
|
+
this.enabledState.clear()
|
|
156
|
+
this.groupCache.clear()
|
|
157
|
+
this.mergedCache.clear()
|
|
158
|
+
this.cacheInvalid = false
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* 归并两个已排序数组 O(n)
|
|
163
|
+
* 优先级相同时,pane 专属渲染器(a)先于 global 渲染器(b)
|
|
164
|
+
*/
|
|
165
|
+
private mergeSorted(a: RendererPlugin[], b: RendererPlugin[]): RendererPlugin[] {
|
|
166
|
+
const result: RendererPlugin[] = []
|
|
167
|
+
let i = 0,
|
|
168
|
+
j = 0
|
|
169
|
+
while (i < a.length && j < b.length) {
|
|
170
|
+
// 优先级相同时,a(pane 专属)优先
|
|
171
|
+
if (a[i]!.priority <= b[j]!.priority) result.push(a[i++]!)
|
|
172
|
+
else result.push(b[j++]!)
|
|
173
|
+
}
|
|
174
|
+
return [...result, ...a.slice(i), ...b.slice(j)]
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/** 重建缓存(统一管理所有缓存逻辑) */
|
|
178
|
+
private rebuildCache(): void {
|
|
179
|
+
if (!this.cacheInvalid) return
|
|
180
|
+
|
|
181
|
+
this.groupCache.clear()
|
|
182
|
+
this.mergedCache.clear()
|
|
183
|
+
|
|
184
|
+
// 按 paneId 分组
|
|
185
|
+
for (const plugin of this.plugins.values()) {
|
|
186
|
+
const cacheKey = typeof plugin.paneId === 'symbol' ? GLOBAL_CACHE_KEY : plugin.paneId
|
|
187
|
+
if (!this.groupCache.has(cacheKey)) {
|
|
188
|
+
this.groupCache.set(cacheKey, [])
|
|
189
|
+
}
|
|
190
|
+
this.groupCache.get(cacheKey)!.push(plugin)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// 对每组排序
|
|
194
|
+
for (const [, list] of this.groupCache) {
|
|
195
|
+
list.sort((a, b) => a.priority - b.priority)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// 预构建合并缓存
|
|
199
|
+
const globalRenderers = this.groupCache.get(GLOBAL_CACHE_KEY) ?? []
|
|
200
|
+
|
|
201
|
+
// 为每个已知 paneId 构建合并缓存
|
|
202
|
+
for (const paneId of this.knownPaneIds) {
|
|
203
|
+
const paneRenderers = this.groupCache.get(paneId) ?? []
|
|
204
|
+
const merged = this.mergeSorted(paneRenderers, globalRenderers)
|
|
205
|
+
this.mergedCache.set(paneId, merged)
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// 缓存纯 global 渲染器作为 fallback
|
|
209
|
+
this.mergedCache.set(GLOBAL_CACHE_KEY, [...globalRenderers])
|
|
210
|
+
|
|
211
|
+
this.cacheInvalid = false
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/** 判断渲染器是否启用 */
|
|
215
|
+
private isRendererEnabled(plugin: RendererPlugin): boolean {
|
|
216
|
+
const state = this.enabledState.get(plugin.name)
|
|
217
|
+
return state !== undefined ? state : plugin.enabled !== false
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/** 获取指定 pane 的合并渲染器(包含 system 渲染器) */
|
|
221
|
+
private getMergedRenderers(paneId: string): RendererPlugin[] {
|
|
222
|
+
this.rebuildCache()
|
|
223
|
+
|
|
224
|
+
let cached = this.mergedCache.get(paneId)
|
|
225
|
+
if (!cached) {
|
|
226
|
+
const paneRenderers = this.groupCache.get(paneId) ?? []
|
|
227
|
+
const globalRenderers = this.groupCache.get(GLOBAL_CACHE_KEY) ?? []
|
|
228
|
+
cached = this.mergeSorted(paneRenderers, globalRenderers)
|
|
229
|
+
this.mergedCache.set(paneId, cached)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return cached
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/** 获取指定 pane 的渲染器(已缓存,无穿透) */
|
|
236
|
+
getRenderers(paneId: string): RendererPlugin[] {
|
|
237
|
+
const cached = this.getMergedRenderers(paneId)
|
|
238
|
+
|
|
239
|
+
// 根据启用状态过滤,同时排除系统渲染器
|
|
240
|
+
return cached.filter((p) => {
|
|
241
|
+
// 系统渲染器不通过 getRenderers 返回,只能通过 renderPlugin 单独渲染
|
|
242
|
+
if (p.isSystem) return false
|
|
243
|
+
return this.isRendererEnabled(p)
|
|
244
|
+
})
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
/** 渲染指定 pane(带错误隔离,支持按 UpdateLevel 过滤) */
|
|
249
|
+
render(
|
|
250
|
+
paneId: string,
|
|
251
|
+
context: RenderContext,
|
|
252
|
+
level?: UpdateLevel
|
|
253
|
+
): RendererErrorEvent[] {
|
|
254
|
+
const renderers = this.getRenderers(paneId)
|
|
255
|
+
const errors: RendererErrorEvent[] = []
|
|
256
|
+
|
|
257
|
+
for (const renderer of renderers) {
|
|
258
|
+
// UpdateLevel 过滤:未传 level 或为 All 时不过滤
|
|
259
|
+
if (level) {
|
|
260
|
+
const rendererLayer = renderer.layer ?? 'main'
|
|
261
|
+
if (level === UpdateLevel.Overlay && rendererLayer !== 'overlay') {
|
|
262
|
+
continue // Overlay 更新时跳过非 overlay 渲染器
|
|
263
|
+
}
|
|
264
|
+
if (level === UpdateLevel.Main && rendererLayer === 'overlay') {
|
|
265
|
+
continue // Main 更新时跳过 overlay 渲染器
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
try {
|
|
270
|
+
renderer.draw(context)
|
|
271
|
+
} catch (e) {
|
|
272
|
+
const error = e instanceof Error ? e : new Error(String(e))
|
|
273
|
+
console.error(`[RendererPlugin] ${renderer.name} draw error:`, error)
|
|
274
|
+
// 裁剪错误事件,不含大数据
|
|
275
|
+
errors.push({
|
|
276
|
+
name: renderer.name,
|
|
277
|
+
error: { message: error.message, stack: error.stack },
|
|
278
|
+
paneId: context.pane.id,
|
|
279
|
+
timestamp: Date.now(),
|
|
280
|
+
})
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
return errors
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/** 渲染指定名称的插件(带错误隔离,用于系统渲染器) */
|
|
288
|
+
renderPlugin(name: string, context: RenderContext): RendererErrorEvent[] {
|
|
289
|
+
const plugin = this.plugins.get(name)
|
|
290
|
+
if (!plugin) return []
|
|
291
|
+
|
|
292
|
+
// 检查启用状态
|
|
293
|
+
if (!this.isRendererEnabled(plugin)) return []
|
|
294
|
+
|
|
295
|
+
const errors: RendererErrorEvent[] = []
|
|
296
|
+
try {
|
|
297
|
+
plugin.draw(context)
|
|
298
|
+
} catch (e) {
|
|
299
|
+
const error = e instanceof Error ? e : new Error(String(e))
|
|
300
|
+
console.error(`[RendererPlugin] ${name} draw error:`, error)
|
|
301
|
+
errors.push({
|
|
302
|
+
name,
|
|
303
|
+
error: { message: error.message, stack: error.stack },
|
|
304
|
+
paneId: context.pane.id,
|
|
305
|
+
timestamp: Date.now(),
|
|
306
|
+
})
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return errors
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/** 启用/禁用渲染器(修改独立状态,不影响原始插件对象) */
|
|
313
|
+
setEnabled(name: string, enabled: boolean): void {
|
|
314
|
+
if (!this.plugins.has(name)) return
|
|
315
|
+
this.enabledState.set(name, enabled)
|
|
316
|
+
this.onInvalidate?.()
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/** 更新配置(自动触发重绘) */
|
|
320
|
+
updateConfig(name: string, config: Record<string, unknown>): boolean {
|
|
321
|
+
const plugin = this.plugins.get(name)
|
|
322
|
+
if (!plugin?.setConfig) return false
|
|
323
|
+
|
|
324
|
+
plugin.setConfig(config)
|
|
325
|
+
this.onInvalidate?.()
|
|
326
|
+
return true
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/** 获取所有渲染器插件 */
|
|
330
|
+
getAllPlugins(): RendererPlugin[] {
|
|
331
|
+
return Array.from(this.plugins.values())
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/** 获取指定渲染器 */
|
|
335
|
+
getPlugin<T extends RendererPlugin = RendererPlugin>(name: string): T | undefined {
|
|
336
|
+
return this.plugins.get(name) as T | undefined
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/* 调用 onDataUpdate 钩子通知数据更新 */
|
|
340
|
+
notifyDataUpdate(data: unknown[], range: { start: number; end: number }): void {
|
|
341
|
+
for (const plugin of this.plugins.values()) {
|
|
342
|
+
if (!plugin.onDataUpdate) continue
|
|
343
|
+
|
|
344
|
+
// 检查启用状态,跳过禁用的插件
|
|
345
|
+
if (!this.isRendererEnabled(plugin)) continue
|
|
346
|
+
|
|
347
|
+
try {
|
|
348
|
+
plugin.onDataUpdate(data, range)
|
|
349
|
+
} catch (e) {
|
|
350
|
+
console.error(`[RendererPlugin] ${plugin.name} onDataUpdate error:`, e)
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/** 通知尺寸变化 */
|
|
356
|
+
notifyResize(paneId: string, pane: PaneInfo): void {
|
|
357
|
+
const renderers = this.getMergedRenderers(paneId).filter((renderer) => this.isRendererEnabled(renderer))
|
|
358
|
+
for (const renderer of renderers) {
|
|
359
|
+
if (renderer.onResize) {
|
|
360
|
+
try {
|
|
361
|
+
renderer.onResize(pane)
|
|
362
|
+
} catch (e) {
|
|
363
|
+
console.error(`[RendererPlugin] ${renderer.name} onResize error:`, e)
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|