@363045841yyt/klinechart-core 0.7.5-alpha.2 → 0.7.6
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 +8 -8
- package/README.zh-CN.md +8 -8
- package/dist/controllers/createChartController.d.ts.map +1 -1
- package/dist/controllers/createChartController.js +145 -21
- package/dist/controllers/createChartController.js.map +1 -1
- package/dist/controllers/index.d.ts +10 -1
- package/dist/controllers/index.d.ts.map +1 -1
- package/dist/controllers/index.js +10 -0
- package/dist/controllers/index.js.map +1 -1
- package/dist/controllers/types.d.ts +65 -8
- package/dist/controllers/types.d.ts.map +1 -1
- package/dist/engine/chart.d.ts +13 -31
- package/dist/engine/chart.d.ts.map +1 -1
- package/dist/engine/chart.js +120 -140
- package/dist/engine/chart.js.map +1 -1
- package/dist/engine/controller/interaction.d.ts +1 -1
- package/dist/engine/controller/interaction.d.ts.map +1 -1
- package/dist/engine/controller/interaction.js +10 -2
- package/dist/engine/controller/interaction.js.map +1 -1
- package/dist/engine/drawing/interaction.d.ts +3 -3
- package/dist/engine/drawing/interaction.d.ts.map +1 -1
- package/dist/engine/drawing/interaction.js +38 -46
- package/dist/engine/drawing/interaction.js.map +1 -1
- package/dist/engine/renderers/Indicator/indicatorData.d.ts +1 -0
- package/dist/engine/renderers/Indicator/indicatorData.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/indicatorData.js +1 -1
- package/dist/engine/renderers/Indicator/indicatorData.js.map +1 -1
- package/dist/engine/renderers/paneTitle.d.ts +5 -24
- package/dist/engine/renderers/paneTitle.d.ts.map +1 -1
- package/dist/engine/renderers/paneTitle.js +10 -5
- package/dist/engine/renderers/paneTitle.js.map +1 -1
- package/dist/engine/renderers/webgl/candleSurface.d.ts +4 -4
- package/dist/engine/renderers/webgl/candleSurface.d.ts.map +1 -1
- package/dist/engine/renderers/webgl/candleSurface.js +36 -56
- package/dist/engine/renderers/webgl/candleSurface.js.map +1 -1
- package/dist/engine/subPaneManager.d.ts +6 -0
- package/dist/engine/subPaneManager.d.ts.map +1 -1
- package/dist/engine/subPaneManager.js +38 -1
- package/dist/engine/subPaneManager.js.map +1 -1
- package/dist/semantic/controller.d.ts +1 -2
- package/dist/semantic/controller.d.ts.map +1 -1
- package/dist/semantic/index.d.ts +1 -1
- package/dist/semantic/index.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +6 -6
- package/src/controllers/createChartController.ts +158 -29
- package/src/controllers/index.ts +34 -0
- package/src/controllers/types.ts +79 -8
- package/src/engine/chart.ts +133 -154
- package/src/engine/controller/interaction.ts +9 -2
- package/src/engine/drawing/interaction.ts +38 -47
- package/src/engine/renderers/Indicator/indicatorData.ts +1 -1
- package/src/engine/renderers/paneTitle.ts +16 -25
- package/src/engine/renderers/webgl/candleSurface.ts +40 -56
- package/src/engine/subPaneManager.ts +43 -1
- package/src/semantic/controller.ts +1 -1
- package/src/semantic/index.ts +1 -1
- package/src/version.ts +1 -1
- package/dist/engine/chart-store.d.ts +0 -75
- package/dist/engine/chart-store.d.ts.map +0 -1
- package/dist/engine/chart-store.js +0 -88
- package/dist/engine/chart-store.js.map +0 -1
- package/src/engine/chart-store.ts +0 -121
package/dist/engine/chart.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createSignal } from '../reactivity/signal';
|
|
1
|
+
import { createSignal, computed } from '../reactivity/signal';
|
|
2
2
|
import { getVisibleRange } from './viewport/viewport';
|
|
3
3
|
import { Pane, UpdateLevel } from './layout/pane';
|
|
4
4
|
import { InteractionController } from './controller/interaction';
|
|
@@ -6,7 +6,6 @@ import { PaneRenderer } from './paneRenderer';
|
|
|
6
6
|
import { SharedWebGLSurface } from './renderers/webgl/sharedWebGLSurface';
|
|
7
7
|
import { MarkerManager } from './marker/registry';
|
|
8
8
|
import { getPhysicalKLineConfig, calcKWidthPx } from './utils/klineConfig';
|
|
9
|
-
import { computeContentWidth } from './chart-store';
|
|
10
9
|
import { computeZoom } from './utils/zoom';
|
|
11
10
|
import { IndicatorScheduler } from './indicators/scheduler';
|
|
12
11
|
import { getRegisteredIndicatorDefinitions } from './indicators/indicatorDefinitionRegistry';
|
|
@@ -74,16 +73,10 @@ export class Chart {
|
|
|
74
73
|
settings = {};
|
|
75
74
|
/** pane ratio 状态(按 paneId 维护,sum=1 仅对可见 pane) */
|
|
76
75
|
_internalPaneRatios = new Map();
|
|
77
|
-
/** 视口变化回调(供外部同步 DPR/尺寸) */
|
|
78
|
-
onViewportChange;
|
|
79
76
|
/** 共享 X 轴上下文缓存 */
|
|
80
77
|
xAxisCtx = null;
|
|
81
78
|
/** Chart 级共享 WebGL canvas/context */
|
|
82
79
|
sharedWebGLSurface;
|
|
83
|
-
/** pane 布局回流回调(Chart -> UI 单向) */
|
|
84
|
-
onPaneLayoutChange;
|
|
85
|
-
/** 数据变化回调(供外部同步 dataLength) */
|
|
86
|
-
onDataChange;
|
|
87
80
|
/** 当前缩放级别(1 ~ zoomLevelCount) */
|
|
88
81
|
currentZoomLevel = 1;
|
|
89
82
|
/** 缩放级别总数 */
|
|
@@ -97,11 +90,11 @@ export class Chart {
|
|
|
97
90
|
/** Overlay 帧复用的最近主渲染结果 */
|
|
98
91
|
cachedDrawFrame = null;
|
|
99
92
|
/** 副图管理器 */
|
|
100
|
-
subPaneManager;
|
|
101
|
-
/**
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
|
|
93
|
+
subPaneManager = new SubPaneManager();
|
|
94
|
+
/** 主图指标激活状态与参数(存在即激活,默认参数在 enable 时初始化) */
|
|
95
|
+
_mainIndicatorsSignal = createSignal(new Map());
|
|
96
|
+
/** 主图指标默认参数 */
|
|
97
|
+
static DEFAULT_MAIN_PARAMS = {
|
|
105
98
|
MA: { ma5: true, ma10: true, ma20: true, ma30: true, ma60: true },
|
|
106
99
|
BOLL: { period: 20, multiplier: 2, showUpper: true, showMiddle: true, showLower: true, showBand: true },
|
|
107
100
|
EXPMA: { fastPeriod: 12, slowPeriod: 50 },
|
|
@@ -133,26 +126,29 @@ export class Chart {
|
|
|
133
126
|
console.warn(`[Chart] 未知的主图指标: ${indicatorId}`);
|
|
134
127
|
return false;
|
|
135
128
|
}
|
|
136
|
-
|
|
129
|
+
const map = this._mainIndicatorsSignal.peek();
|
|
130
|
+
const existing = map.get(id);
|
|
131
|
+
if (existing) {
|
|
137
132
|
// 已启用,更新参数
|
|
138
133
|
if (params) {
|
|
139
|
-
|
|
134
|
+
const next = new Map(map);
|
|
135
|
+
next.set(id, { params: { ...existing.params, ...params } });
|
|
136
|
+
this._mainIndicatorsSignal.set(next);
|
|
140
137
|
this.updateIndicatorSchedulerConfig(id);
|
|
141
|
-
this.syncIndicatorsSignal();
|
|
142
138
|
}
|
|
143
139
|
return true;
|
|
144
140
|
}
|
|
145
|
-
this.activeMainIndicators.add(id);
|
|
146
141
|
// 合并默认参数和传入参数
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
142
|
+
const defaults = Chart.DEFAULT_MAIN_PARAMS[id] ?? {};
|
|
143
|
+
const merged = params ? { ...defaults, ...params } : defaults;
|
|
144
|
+
const next = new Map(map);
|
|
145
|
+
next.set(id, { params: merged });
|
|
146
|
+
this._mainIndicatorsSignal.set(next);
|
|
150
147
|
// 启用对应的渲染器
|
|
151
148
|
this.enableMainIndicatorRenderer(id);
|
|
152
149
|
// 更新调度器配置
|
|
153
150
|
this.updateIndicatorSchedulerConfig(id);
|
|
154
151
|
this.scheduleDraw();
|
|
155
|
-
this.syncIndicatorsSignal();
|
|
156
152
|
return true;
|
|
157
153
|
}
|
|
158
154
|
/**
|
|
@@ -162,15 +158,17 @@ export class Chart {
|
|
|
162
158
|
*/
|
|
163
159
|
disableMainIndicator(indicatorId) {
|
|
164
160
|
const id = indicatorId.toUpperCase();
|
|
165
|
-
|
|
161
|
+
const map = this._mainIndicatorsSignal.peek();
|
|
162
|
+
if (!map.has(id))
|
|
166
163
|
return false;
|
|
167
|
-
|
|
164
|
+
const next = new Map(map);
|
|
165
|
+
next.delete(id);
|
|
166
|
+
this._mainIndicatorsSignal.set(next);
|
|
168
167
|
// 禁用对应的渲染器
|
|
169
168
|
this.disableMainIndicatorRenderer(id);
|
|
170
169
|
// 更新调度器配置
|
|
171
170
|
this.updateIndicatorSchedulerConfig(id);
|
|
172
171
|
this.scheduleDraw();
|
|
173
|
-
this.syncIndicatorsSignal();
|
|
174
172
|
return true;
|
|
175
173
|
}
|
|
176
174
|
/**
|
|
@@ -191,14 +189,14 @@ export class Chart {
|
|
|
191
189
|
* @returns 激活的指标ID数组
|
|
192
190
|
*/
|
|
193
191
|
getActiveMainIndicators() {
|
|
194
|
-
return
|
|
192
|
+
return [...this._mainIndicatorsSignal.peek().keys()];
|
|
195
193
|
}
|
|
196
194
|
/**
|
|
197
195
|
* 检查主图指标是否激活
|
|
198
196
|
* @param indicatorId 指标ID
|
|
199
197
|
*/
|
|
200
198
|
isMainIndicatorActive(indicatorId) {
|
|
201
|
-
return this.
|
|
199
|
+
return this._mainIndicatorsSignal.peek().has(indicatorId.toUpperCase());
|
|
202
200
|
}
|
|
203
201
|
/**
|
|
204
202
|
* 更新主图指标参数
|
|
@@ -207,38 +205,41 @@ export class Chart {
|
|
|
207
205
|
*/
|
|
208
206
|
updateMainIndicatorParams(indicatorId, params) {
|
|
209
207
|
const id = indicatorId.toUpperCase();
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
208
|
+
const map = this._mainIndicatorsSignal.peek();
|
|
209
|
+
const entry = map.get(id);
|
|
210
|
+
if (!entry)
|
|
211
|
+
return;
|
|
212
|
+
const merged = { ...entry.params, ...params };
|
|
213
|
+
const next = new Map(map);
|
|
214
|
+
next.set(id, { params: merged });
|
|
215
|
+
this._mainIndicatorsSignal.set(next);
|
|
214
216
|
// 同步更新渲染器配置
|
|
215
217
|
const rendererName = id.toLowerCase();
|
|
216
218
|
const renderer = this.getRenderer(rendererName);
|
|
217
219
|
if (renderer && renderer.setConfig) {
|
|
218
|
-
renderer.setConfig(
|
|
220
|
+
renderer.setConfig(merged);
|
|
219
221
|
}
|
|
220
222
|
// 更新调度器
|
|
221
223
|
this.updateIndicatorSchedulerConfig(id);
|
|
222
224
|
this.scheduleDraw();
|
|
223
|
-
this.syncIndicatorsSignal();
|
|
224
225
|
}
|
|
225
226
|
/**
|
|
226
227
|
* 获取主图指标参数
|
|
227
228
|
* @param indicatorId 指标ID
|
|
228
229
|
*/
|
|
229
230
|
getMainIndicatorParams(indicatorId) {
|
|
230
|
-
return this.
|
|
231
|
+
return this._mainIndicatorsSignal.peek().get(indicatorId.toUpperCase())?.params ?? null;
|
|
231
232
|
}
|
|
232
233
|
/**
|
|
233
234
|
* 清除所有主图指标
|
|
234
235
|
*/
|
|
235
236
|
clearMainIndicators() {
|
|
236
|
-
|
|
237
|
+
const map = this._mainIndicatorsSignal.peek();
|
|
238
|
+
for (const id of map.keys()) {
|
|
237
239
|
this.disableMainIndicatorRenderer(id);
|
|
238
240
|
}
|
|
239
|
-
this.
|
|
241
|
+
this._mainIndicatorsSignal.set(new Map());
|
|
240
242
|
this.scheduleDraw();
|
|
241
|
-
this.syncIndicatorsSignal();
|
|
242
243
|
}
|
|
243
244
|
/**
|
|
244
245
|
* 启用主图指标渲染器(内部方法)
|
|
@@ -395,8 +396,9 @@ export class Chart {
|
|
|
395
396
|
* 更新调度器配置(内部方法)
|
|
396
397
|
*/
|
|
397
398
|
updateIndicatorSchedulerConfig(indicatorId) {
|
|
398
|
-
const
|
|
399
|
-
const
|
|
399
|
+
const entry = this._mainIndicatorsSignal.peek().get(indicatorId);
|
|
400
|
+
const isActive = entry !== undefined;
|
|
401
|
+
const params = entry?.params ?? {};
|
|
400
402
|
switch (indicatorId) {
|
|
401
403
|
case 'MA':
|
|
402
404
|
this.indicatorScheduler.updateMAConfig({
|
|
@@ -475,7 +477,7 @@ export class Chart {
|
|
|
475
477
|
setActiveMainIndicators(indicators) {
|
|
476
478
|
// 计算需要启用和禁用的指标
|
|
477
479
|
const newSet = new Set(indicators.map(i => i.toUpperCase()));
|
|
478
|
-
const currentSet = new Set(this.
|
|
480
|
+
const currentSet = new Set(this._mainIndicatorsSignal.peek().keys());
|
|
479
481
|
// 禁用不再激活的
|
|
480
482
|
for (const id of currentSet) {
|
|
481
483
|
if (!newSet.has(id)) {
|
|
@@ -523,11 +525,20 @@ export class Chart {
|
|
|
523
525
|
this.indicatorScheduler.registerIndicator(definition);
|
|
524
526
|
}
|
|
525
527
|
this.indicatorScheduler.setInvalidateCallback(() => this.scheduleDraw());
|
|
526
|
-
// 初始化副图管理器
|
|
527
|
-
this.subPaneManager = new SubPaneManager();
|
|
528
528
|
// 注册副图活跃列表提供者,调度器据此只计算启用的副图
|
|
529
529
|
this.indicatorScheduler.setActiveSubPaneProvider(() => this.subPaneManager.getPaneIds());
|
|
530
530
|
this.initPanes();
|
|
531
|
+
// dev: 主副图状态变更日志
|
|
532
|
+
if (import.meta.env?.MODE !== 'production') {
|
|
533
|
+
this._indicatorsComputed.subscribe(() => {
|
|
534
|
+
const instances = this._indicatorsComputed.peek();
|
|
535
|
+
console.log('[Chart] indicators signal changed:', instances);
|
|
536
|
+
});
|
|
537
|
+
this._subPanesComputed.subscribe(() => {
|
|
538
|
+
const subPanes = this._subPanesComputed.peek();
|
|
539
|
+
console.log('[Chart] subPanes signal changed:', subPanes);
|
|
540
|
+
});
|
|
541
|
+
}
|
|
531
542
|
// 注册绘图主插件(负责绘制 shape,layer: 'main')
|
|
532
543
|
this.useRenderer(createDrawingRendererPlugin({ store: this.drawingStore }));
|
|
533
544
|
// 注册绘图标签插件(负责推送选中绘图的轴标签,layer: 'overlay')
|
|
@@ -707,7 +718,7 @@ export class Chart {
|
|
|
707
718
|
// 3. 更新交互控制器坐标映射
|
|
708
719
|
this.interaction.setKLinePositions(kLinePositions, range, kWidthPx);
|
|
709
720
|
// 4. 通知调度器当前活跃主图指标 + 获取价格范围
|
|
710
|
-
this.indicatorScheduler.setActiveMainIndicators(
|
|
721
|
+
this.indicatorScheduler.setActiveMainIndicators([...this._mainIndicatorsSignal.peek().keys()]);
|
|
711
722
|
const mainIndicatorRange = useCachedFrame ? null : this.indicatorScheduler.getMainIndicatorPriceRange();
|
|
712
723
|
const hasCrosshair = this.interaction.getCrosshairIndex() !== null;
|
|
713
724
|
// 5. 遍历所有 Pane 渲染主层 / overlay / Y 轴
|
|
@@ -936,18 +947,6 @@ export class Chart {
|
|
|
936
947
|
getZoomLevelCount() {
|
|
937
948
|
return this.zoomLevelCount;
|
|
938
949
|
}
|
|
939
|
-
/** 注册视口变化回调 */
|
|
940
|
-
setOnViewportChange(cb) {
|
|
941
|
-
this.onViewportChange = cb;
|
|
942
|
-
}
|
|
943
|
-
/** 注册 pane 布局回流回调 */
|
|
944
|
-
setOnPaneLayoutChange(cb) {
|
|
945
|
-
this.onPaneLayoutChange = cb;
|
|
946
|
-
}
|
|
947
|
-
/** 注册数据变化回调 */
|
|
948
|
-
setOnDataChange(cb) {
|
|
949
|
-
this.onDataChange = cb;
|
|
950
|
-
}
|
|
951
950
|
/** 获取所有 PaneRenderer */
|
|
952
951
|
getPaneRenderers() {
|
|
953
952
|
return this.paneRenderers;
|
|
@@ -1101,8 +1100,7 @@ export class Chart {
|
|
|
1101
1100
|
ratios[id] = ratio;
|
|
1102
1101
|
});
|
|
1103
1102
|
this._paneRatiosSignal.set(ratios);
|
|
1104
|
-
this.
|
|
1105
|
-
this.onPaneLayoutChange?.(this.getPaneLayoutSpecs());
|
|
1103
|
+
this._paneLayoutSignal.set(this.getPaneLayoutSpecs());
|
|
1106
1104
|
}
|
|
1107
1105
|
applyPaneLayoutSpecs(panes) {
|
|
1108
1106
|
this.opt.panes = panes.map((spec) => ({ ...spec }));
|
|
@@ -1257,8 +1255,6 @@ export class Chart {
|
|
|
1257
1255
|
}
|
|
1258
1256
|
this.upsertPane({ id: paneId, ratio: this._internalPaneRatios.get(paneId) ?? 1, visible: true, role: 'indicator' });
|
|
1259
1257
|
const success = this.subPaneManager.create(this, paneId, indicatorId, params ?? this.getDefaultSubPaneParams(indicatorId));
|
|
1260
|
-
this.syncIndicatorsSignal();
|
|
1261
|
-
this.syncSubPanesSignal();
|
|
1262
1258
|
return success;
|
|
1263
1259
|
}
|
|
1264
1260
|
/**
|
|
@@ -1267,9 +1263,6 @@ export class Chart {
|
|
|
1267
1263
|
*/
|
|
1268
1264
|
removeSubPane(paneId) {
|
|
1269
1265
|
this.subPaneManager.remove(this, paneId);
|
|
1270
|
-
this._internalPaneRatios.delete(paneId);
|
|
1271
|
-
this.syncIndicatorsSignal();
|
|
1272
|
-
this.syncSubPanesSignal();
|
|
1273
1266
|
}
|
|
1274
1267
|
/**
|
|
1275
1268
|
* 替换副图的指标类型
|
|
@@ -1279,8 +1272,6 @@ export class Chart {
|
|
|
1279
1272
|
*/
|
|
1280
1273
|
replaceSubPaneIndicator(paneId, newIndicatorId, params) {
|
|
1281
1274
|
this.subPaneManager.replaceIndicator(this, paneId, newIndicatorId, params ?? this.getDefaultSubPaneParams(newIndicatorId));
|
|
1282
|
-
this.syncIndicatorsSignal();
|
|
1283
|
-
this.syncSubPanesSignal();
|
|
1284
1275
|
}
|
|
1285
1276
|
/**
|
|
1286
1277
|
* 更新副图指标参数
|
|
@@ -1289,7 +1280,6 @@ export class Chart {
|
|
|
1289
1280
|
*/
|
|
1290
1281
|
updateSubPaneParams(paneId, params) {
|
|
1291
1282
|
this.subPaneManager.updateParams(this, paneId, params);
|
|
1292
|
-
this.syncIndicatorsSignal();
|
|
1293
1283
|
}
|
|
1294
1284
|
/**
|
|
1295
1285
|
* 清除所有副图面板
|
|
@@ -1307,8 +1297,6 @@ export class Chart {
|
|
|
1307
1297
|
}
|
|
1308
1298
|
// 更新布局,移除所有副图 pane
|
|
1309
1299
|
this.applyPaneLayoutSpecs(this.opt.panes.filter((spec) => !subPaneIds.includes(spec.id)));
|
|
1310
|
-
this.syncIndicatorsSignal();
|
|
1311
|
-
this.syncSubPanesSignal();
|
|
1312
1300
|
}
|
|
1313
1301
|
/**
|
|
1314
1302
|
* 获取当前所有副图指标类型
|
|
@@ -1424,7 +1412,6 @@ export class Chart {
|
|
|
1424
1412
|
updateData(data) {
|
|
1425
1413
|
this._internalData = data ?? [];
|
|
1426
1414
|
this._dataSignal.set([...this._internalData]);
|
|
1427
|
-
this.onDataChange?.(this._internalData);
|
|
1428
1415
|
// 重算 DOM scrollLeft 状态, 防止左右滚动超出数据长度范围
|
|
1429
1416
|
const container = this.dom.container;
|
|
1430
1417
|
if (container) {
|
|
@@ -1482,13 +1469,17 @@ export class Chart {
|
|
|
1482
1469
|
}
|
|
1483
1470
|
/** 获取内容总宽度(用于外部 scroll-content 撑开 scrollWidth) */
|
|
1484
1471
|
getContentWidth() {
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1472
|
+
const dataLength = this._internalData.length;
|
|
1473
|
+
if (dataLength === 0)
|
|
1474
|
+
return 0;
|
|
1475
|
+
const kWidth = this.opt.kWidth;
|
|
1476
|
+
const kGap = this.opt.kGap;
|
|
1477
|
+
const viewWidth = this._internalViewport?.plotWidth ?? 0;
|
|
1478
|
+
const dpr = this.getEffectiveDpr();
|
|
1479
|
+
const TRAILING_DRAWING_SLOTS = 24;
|
|
1480
|
+
const { startXPx, unitPx } = getPhysicalKLineConfig(kWidth, kGap, dpr);
|
|
1481
|
+
const dataPlotWidth = (startXPx + (dataLength + TRAILING_DRAWING_SLOTS) * unitPx) / dpr;
|
|
1482
|
+
return Math.max(dataPlotWidth, viewWidth);
|
|
1492
1483
|
}
|
|
1493
1484
|
/** 容器尺寸变化时调用 */
|
|
1494
1485
|
resize() {
|
|
@@ -1559,8 +1550,6 @@ export class Chart {
|
|
|
1559
1550
|
this.sharedWebGLSurface.destroy();
|
|
1560
1551
|
// 清理渲染器插件管理器(会调用所有 onUninstall)
|
|
1561
1552
|
this.rendererPluginManager.clear();
|
|
1562
|
-
this.onViewportChange = undefined;
|
|
1563
|
-
this.onPaneLayoutChange = undefined;
|
|
1564
1553
|
this.indicatorScheduler.destroy();
|
|
1565
1554
|
await this.pluginHost.destroy();
|
|
1566
1555
|
}
|
|
@@ -1829,7 +1818,18 @@ export class Chart {
|
|
|
1829
1818
|
|| prevViewport.dpr !== vp.dpr;
|
|
1830
1819
|
this._internalViewport = vp;
|
|
1831
1820
|
if (viewportChanged) {
|
|
1832
|
-
this.
|
|
1821
|
+
const current = this._viewportSignal.peek();
|
|
1822
|
+
this._viewportSignal.set({
|
|
1823
|
+
zoomLevel: current.zoomLevel,
|
|
1824
|
+
plotWidth: vp.plotWidth,
|
|
1825
|
+
plotHeight: vp.plotHeight,
|
|
1826
|
+
dpr: vp.dpr > 0 ? vp.dpr : current.dpr,
|
|
1827
|
+
visibleFrom: current.visibleFrom,
|
|
1828
|
+
visibleTo: current.visibleTo,
|
|
1829
|
+
desiredScrollLeft: current.desiredScrollLeft,
|
|
1830
|
+
kWidth: current.kWidth,
|
|
1831
|
+
kGap: current.kGap,
|
|
1832
|
+
});
|
|
1833
1833
|
}
|
|
1834
1834
|
return vp;
|
|
1835
1835
|
}
|
|
@@ -1848,11 +1848,10 @@ export class Chart {
|
|
|
1848
1848
|
});
|
|
1849
1849
|
_dataSignal = createSignal([]);
|
|
1850
1850
|
_themeSignal = createSignal('light');
|
|
1851
|
-
_indicatorsSignal = createSignal([]);
|
|
1852
|
-
_subPanesSignal = createSignal([]);
|
|
1853
1851
|
_drawingToolSignal = createSignal(null);
|
|
1854
1852
|
_drawingsSignal = createSignal([]);
|
|
1855
1853
|
_paneRatiosSignal = createSignal({});
|
|
1854
|
+
_paneLayoutSignal = createSignal([]);
|
|
1856
1855
|
_interactionSignal = createSignal({
|
|
1857
1856
|
crosshairPos: null,
|
|
1858
1857
|
crosshairIndex: null,
|
|
@@ -1869,6 +1868,35 @@ export class Chart {
|
|
|
1869
1868
|
hoveredPaneBoundaryId: null,
|
|
1870
1869
|
isHoveringRightAxis: false,
|
|
1871
1870
|
});
|
|
1871
|
+
_indicatorsComputed = computed(() => {
|
|
1872
|
+
const mainIndicators = [...this._mainIndicatorsSignal().entries()].map(([id, entry]) => ({
|
|
1873
|
+
id,
|
|
1874
|
+
definitionId: id,
|
|
1875
|
+
label: id,
|
|
1876
|
+
name: id,
|
|
1877
|
+
role: 'main',
|
|
1878
|
+
params: { ...entry.params },
|
|
1879
|
+
}));
|
|
1880
|
+
const subIndicators = this.subPaneManager.entriesSignal().map(entry => ({
|
|
1881
|
+
id: entry.paneId,
|
|
1882
|
+
definitionId: entry.indicatorId,
|
|
1883
|
+
label: entry.indicatorId,
|
|
1884
|
+
name: entry.indicatorId,
|
|
1885
|
+
role: 'sub',
|
|
1886
|
+
paneId: entry.paneId,
|
|
1887
|
+
params: { ...entry.params },
|
|
1888
|
+
}));
|
|
1889
|
+
return [...mainIndicators, ...subIndicators];
|
|
1890
|
+
});
|
|
1891
|
+
_subPanesComputed = computed(() => {
|
|
1892
|
+
const ratios = this._paneRatiosSignal();
|
|
1893
|
+
return this.subPaneManager.entriesSignal().map(entry => ({
|
|
1894
|
+
paneId: entry.paneId,
|
|
1895
|
+
indicatorId: entry.indicatorId,
|
|
1896
|
+
params: { ...entry.params },
|
|
1897
|
+
ratio: ratios[entry.paneId] ?? 1,
|
|
1898
|
+
}));
|
|
1899
|
+
});
|
|
1872
1900
|
/** 视口状态信号 */
|
|
1873
1901
|
get viewport() {
|
|
1874
1902
|
return this._viewportSignal;
|
|
@@ -1881,13 +1909,13 @@ export class Chart {
|
|
|
1881
1909
|
get theme() {
|
|
1882
1910
|
return this._themeSignal;
|
|
1883
1911
|
}
|
|
1884
|
-
/**
|
|
1912
|
+
/** 指标实例列表信号(派生信号,自动随主/副图状态更新) */
|
|
1885
1913
|
get indicators() {
|
|
1886
|
-
return this.
|
|
1914
|
+
return this._indicatorsComputed;
|
|
1887
1915
|
}
|
|
1888
|
-
/**
|
|
1916
|
+
/** 子图信息信号(派生信号,自动随副图条目/比例更新) */
|
|
1889
1917
|
get subPanes() {
|
|
1890
|
-
return this.
|
|
1918
|
+
return this._subPanesComputed;
|
|
1891
1919
|
}
|
|
1892
1920
|
/** 当前绘图工具信号 */
|
|
1893
1921
|
get drawingTool() {
|
|
@@ -1901,6 +1929,9 @@ export class Chart {
|
|
|
1901
1929
|
get paneRatios() {
|
|
1902
1930
|
return this._paneRatiosSignal;
|
|
1903
1931
|
}
|
|
1932
|
+
get paneLayout() {
|
|
1933
|
+
return this._paneLayoutSignal;
|
|
1934
|
+
}
|
|
1904
1935
|
/** 交互状态信号 */
|
|
1905
1936
|
get interactionState() {
|
|
1906
1937
|
return this._interactionSignal;
|
|
@@ -2120,8 +2151,6 @@ export class Chart {
|
|
|
2120
2151
|
const success = this.enableMainIndicator(definitionId, params);
|
|
2121
2152
|
if (!success)
|
|
2122
2153
|
return null;
|
|
2123
|
-
// 更新 indicators signal
|
|
2124
|
-
this.syncIndicatorsSignal();
|
|
2125
2154
|
return definitionId.toUpperCase();
|
|
2126
2155
|
}
|
|
2127
2156
|
else {
|
|
@@ -2130,9 +2159,6 @@ export class Chart {
|
|
|
2130
2159
|
const success = this.createSubPane(paneId, definitionId, params);
|
|
2131
2160
|
if (!success)
|
|
2132
2161
|
return null;
|
|
2133
|
-
// 更新 signals
|
|
2134
|
-
this.syncIndicatorsSignal();
|
|
2135
|
-
this.syncSubPanesSignal();
|
|
2136
2162
|
return paneId;
|
|
2137
2163
|
}
|
|
2138
2164
|
}
|
|
@@ -2143,23 +2169,16 @@ export class Chart {
|
|
|
2143
2169
|
*/
|
|
2144
2170
|
removeIndicator(instanceId) {
|
|
2145
2171
|
const id = instanceId.toUpperCase();
|
|
2146
|
-
//
|
|
2147
|
-
if (this.
|
|
2148
|
-
|
|
2149
|
-
if (success) {
|
|
2150
|
-
this.syncIndicatorsSignal();
|
|
2151
|
-
}
|
|
2152
|
-
return success;
|
|
2172
|
+
// 先尝试作为主图指标移除
|
|
2173
|
+
if (this._mainIndicatorsSignal.peek().has(id)) {
|
|
2174
|
+
return this.disableMainIndicator(instanceId);
|
|
2153
2175
|
}
|
|
2154
|
-
//
|
|
2176
|
+
// 再尝试作为副图指标移除
|
|
2155
2177
|
const subPaneEntry = this.getSubPaneEntry(instanceId);
|
|
2156
2178
|
if (subPaneEntry) {
|
|
2157
2179
|
this.removeSubPane(instanceId);
|
|
2158
|
-
this.syncIndicatorsSignal();
|
|
2159
|
-
this.syncSubPanesSignal();
|
|
2160
2180
|
return true;
|
|
2161
2181
|
}
|
|
2162
|
-
// 都没找到,返回 false
|
|
2163
2182
|
return false;
|
|
2164
2183
|
}
|
|
2165
2184
|
/**
|
|
@@ -2170,20 +2189,17 @@ export class Chart {
|
|
|
2170
2189
|
*/
|
|
2171
2190
|
updateIndicatorParams(instanceId, params) {
|
|
2172
2191
|
const id = instanceId.toUpperCase();
|
|
2173
|
-
//
|
|
2174
|
-
if (this.
|
|
2192
|
+
// 先尝试作为主图指标更新
|
|
2193
|
+
if (this._mainIndicatorsSignal.peek().has(id)) {
|
|
2175
2194
|
this.updateMainIndicatorParams(instanceId, params);
|
|
2176
|
-
this.syncIndicatorsSignal();
|
|
2177
2195
|
return true;
|
|
2178
2196
|
}
|
|
2179
2197
|
// 再尝试作为副图指标更新
|
|
2180
2198
|
const subPaneEntry = this.getSubPaneEntry(instanceId);
|
|
2181
2199
|
if (subPaneEntry) {
|
|
2182
2200
|
this.updateSubPaneParams(instanceId, params);
|
|
2183
|
-
this.syncIndicatorsSignal();
|
|
2184
2201
|
return true;
|
|
2185
2202
|
}
|
|
2186
|
-
// 都没找到
|
|
2187
2203
|
return false;
|
|
2188
2204
|
}
|
|
2189
2205
|
/**
|
|
@@ -2197,42 +2213,6 @@ export class Chart {
|
|
|
2197
2213
|
console.warn('[Chart] reorderIndicators not fully implemented yet');
|
|
2198
2214
|
return false;
|
|
2199
2215
|
}
|
|
2200
|
-
/**
|
|
2201
|
-
* 同步 indicators signal
|
|
2202
|
-
*/
|
|
2203
|
-
syncIndicatorsSignal() {
|
|
2204
|
-
const mainIndicators = this.getActiveMainIndicators().map(id => ({
|
|
2205
|
-
id,
|
|
2206
|
-
definitionId: id,
|
|
2207
|
-
label: id,
|
|
2208
|
-
name: id,
|
|
2209
|
-
role: 'main',
|
|
2210
|
-
params: this.getMainIndicatorParams(id) ?? {},
|
|
2211
|
-
}));
|
|
2212
|
-
const subIndicators = this.getSubPaneEntries().map(entry => ({
|
|
2213
|
-
id: entry.paneId,
|
|
2214
|
-
definitionId: entry.indicatorId,
|
|
2215
|
-
label: entry.indicatorId,
|
|
2216
|
-
name: entry.indicatorId,
|
|
2217
|
-
role: 'sub',
|
|
2218
|
-
paneId: entry.paneId,
|
|
2219
|
-
params: entry.params,
|
|
2220
|
-
}));
|
|
2221
|
-
this._indicatorsSignal.set([...mainIndicators, ...subIndicators]);
|
|
2222
|
-
}
|
|
2223
|
-
/**
|
|
2224
|
-
* 同步 sub panes signal
|
|
2225
|
-
*/
|
|
2226
|
-
syncSubPanesSignal() {
|
|
2227
|
-
const entries = this.getSubPaneEntries();
|
|
2228
|
-
const subPanes = entries.map(entry => ({
|
|
2229
|
-
paneId: entry.paneId,
|
|
2230
|
-
indicatorId: entry.indicatorId,
|
|
2231
|
-
params: entry.params,
|
|
2232
|
-
ratio: this._internalPaneRatios.get(entry.paneId) ?? 1,
|
|
2233
|
-
}));
|
|
2234
|
-
this._subPanesSignal.set(subPanes);
|
|
2235
|
-
}
|
|
2236
2216
|
// ---------- Sub Panes ----------
|
|
2237
2217
|
/**
|
|
2238
2218
|
* 调整子图大小(高层 API)
|