지표추가시 겹침문제
This commit is contained in:
@@ -441,6 +441,11 @@ const TradingChart: React.FC<TradingChartProps> = ({
|
||||
try {
|
||||
await mgr.addIndicatorsBatch(missing);
|
||||
afterIndicatorPaneMutation(mgr);
|
||||
mgr.notifyPaneLayoutChanged();
|
||||
requestAnimationFrame(() => requestAnimationFrame(() => {
|
||||
afterIndicatorPaneMutation(mgr);
|
||||
mgr.notifyPaneLayoutChanged();
|
||||
}));
|
||||
} finally {
|
||||
indicatorSyncInFlightRef.current = false;
|
||||
}
|
||||
@@ -1178,10 +1183,38 @@ const TradingChart: React.FC<TradingChartProps> = ({
|
||||
indicatorSyncInFlightRef.current = true;
|
||||
mgr.removeIndicators(removedIds);
|
||||
afterIndicatorPaneMutation(mgr);
|
||||
mgr.notifyPaneLayoutChanged();
|
||||
restoreLogicalRange(mgr, savedLR);
|
||||
syncIndicatorTrackingRefs(indicators);
|
||||
indicatorSyncInFlightRef.current = false;
|
||||
requestAnimationFrame(() => requestAnimationFrame(() => {
|
||||
afterIndicatorPaneMutation(mgr);
|
||||
mgr.notifyPaneLayoutChanged();
|
||||
}));
|
||||
void repairMissingIndicators(mgr, indicators);
|
||||
} else if (
|
||||
addedConfigs.length > 0
|
||||
&& removedIds.length > 0
|
||||
&& paramsChangedConfigs.length === 0
|
||||
) {
|
||||
/** 지표 교체(제거+추가 동시) — CCI 제거 후 재추가 등 orphan pane·pane index 어긋남 방지 */
|
||||
const savedLR = mgr.getVisibleLogicalRange();
|
||||
indicatorSyncInFlightRef.current = true;
|
||||
mgr.removeIndicators(removedIds);
|
||||
void mgr.addIndicatorsBatch(addedConfigs).then(() => {
|
||||
afterIndicatorPaneMutation(mgr);
|
||||
mgr.notifyPaneLayoutChanged();
|
||||
restoreLogicalRange(mgr, savedLR);
|
||||
syncIndicatorTrackingRefs(indicators);
|
||||
indicatorSyncInFlightRef.current = false;
|
||||
requestAnimationFrame(() => requestAnimationFrame(() => {
|
||||
afterIndicatorPaneMutation(mgr);
|
||||
mgr.notifyPaneLayoutChanged();
|
||||
[50, 150, 350].forEach(ms => {
|
||||
setTimeout(() => mgr.notifyPaneLayoutChanged(), ms);
|
||||
});
|
||||
}));
|
||||
});
|
||||
} else if (
|
||||
addedConfigs.length > 0
|
||||
&& removedIds.length === 0
|
||||
@@ -1191,9 +1224,17 @@ const TradingChart: React.FC<TradingChartProps> = ({
|
||||
indicatorSyncInFlightRef.current = true;
|
||||
void mgr.addIndicatorsBatch(addedConfigs).then(() => {
|
||||
afterIndicatorPaneMutation(mgr);
|
||||
mgr.notifyPaneLayoutChanged();
|
||||
restoreLogicalRange(mgr, savedLR);
|
||||
syncIndicatorTrackingRefs(indicators);
|
||||
indicatorSyncInFlightRef.current = false;
|
||||
requestAnimationFrame(() => requestAnimationFrame(() => {
|
||||
afterIndicatorPaneMutation(mgr);
|
||||
mgr.notifyPaneLayoutChanged();
|
||||
[50, 150, 350].forEach(ms => {
|
||||
setTimeout(() => mgr.notifyPaneLayoutChanged(), ms);
|
||||
});
|
||||
}));
|
||||
});
|
||||
} else if (
|
||||
paramsChangedConfigs.length > 0
|
||||
|
||||
@@ -652,6 +652,9 @@ export class ChartManager {
|
||||
return;
|
||||
}
|
||||
this.indicators.set(config.id, { id: config.id, type: config.type, seriesList, seriesMeta: ichiMeta, paneIndex: pane, alertLines: [], hlineRefs: [], config, cloudPlugin });
|
||||
const ichiPane = this._readSeriesPaneIndex(seriesList[0]);
|
||||
const ichiEntry = this.indicators.get(config.id);
|
||||
if (ichiEntry && ichiPane >= 2) ichiEntry.paneIndex = ichiPane;
|
||||
this.applyIndicatorStyle(config);
|
||||
return;
|
||||
}
|
||||
@@ -738,6 +741,8 @@ export class ChartManager {
|
||||
id: config.id, type: config.type, seriesList, seriesMeta,
|
||||
paneIndex: pane, alertLines: [], hlineRefs, fillPrimitive, config,
|
||||
};
|
||||
const actualPane = this._readSeriesPaneIndex(seriesList[0]);
|
||||
if (actualPane >= 2) entry.paneIndex = actualPane;
|
||||
if (this._indicatorLoadStale(dataGenAtStart) || this.indicators.has(config.id)) {
|
||||
this._discardIndicatorSeries(seriesList, { fillPrimitive });
|
||||
return;
|
||||
@@ -751,13 +756,19 @@ export class ChartManager {
|
||||
} catch (e) {
|
||||
console.error(`[Indicator] ${config.type} error:`, e);
|
||||
} finally {
|
||||
if (
|
||||
!options?.skipLayout
|
||||
&& this._activeIndicatorPaneIndices().size > 0
|
||||
) {
|
||||
if (!options?.skipLayout) {
|
||||
this._finalizeIndicatorPaneLayout();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 지표 추가·제거 후 pane index 동기화 + stretch 재배분 */
|
||||
private _finalizeIndicatorPaneLayout(): void {
|
||||
if (this._activeIndicatorPaneIndices().size === 0) return;
|
||||
this._removeOrphanSubPanes();
|
||||
this._resyncIndicatorPaneIndices();
|
||||
this.resetPaneHeights(this._lastLayoutAvailableHeight);
|
||||
}
|
||||
}
|
||||
this._notifyPaneLayout();
|
||||
}
|
||||
|
||||
/** 여러 지표 추가 후 pane 레이아웃을 한 번만 갱신 */
|
||||
@@ -765,11 +776,8 @@ export class ChartManager {
|
||||
for (const config of configs) {
|
||||
await this.addIndicator(config, { skipLayout: true });
|
||||
}
|
||||
if (configs.length > 0 && this._activeIndicatorPaneIndices().size > 0) {
|
||||
this._removeOrphanSubPanes();
|
||||
this._resyncIndicatorPaneIndices();
|
||||
this.resetPaneHeights(this._lastLayoutAvailableHeight);
|
||||
this._notifyPaneLayout();
|
||||
if (configs.length > 0) {
|
||||
this._finalizeIndicatorPaneLayout();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -831,11 +839,7 @@ export class ChartManager {
|
||||
|
||||
if (this._indicatorLoadStale(loadGen)) return;
|
||||
|
||||
// 시리즈 제거 후 남은 빈 sub-pane 제거 (상단 orphan pane → 레이블·그래프 어긋남 방지)
|
||||
this._removeOrphanSubPanes();
|
||||
// 빈 pane stretch 정리 + 캔들 pane 비율 복구
|
||||
this.resetPaneHeights();
|
||||
this._notifyPaneLayout();
|
||||
this._finalizeIndicatorPaneLayout();
|
||||
}
|
||||
|
||||
removeIndicator(id: string): void {
|
||||
@@ -849,7 +853,9 @@ export class ChartManager {
|
||||
if (this._detachIndicatorEntry(id)) any = true;
|
||||
}
|
||||
if (!any) return;
|
||||
this._removeOrphanSubPanes();
|
||||
this._trimTrailingEmptySubPanes();
|
||||
this._resyncIndicatorPaneIndices();
|
||||
this.resetPaneHeights(this._lastLayoutAvailableHeight);
|
||||
this._notifyPaneLayout();
|
||||
}
|
||||
@@ -876,12 +882,7 @@ export class ChartManager {
|
||||
}
|
||||
if (this._indicatorLoadStale(loadGen)) return;
|
||||
|
||||
this._removeOrphanSubPanes();
|
||||
this._resyncIndicatorPaneIndices();
|
||||
if (this._activeIndicatorPaneIndices().size > 0) {
|
||||
this.resetPaneHeights(this._lastLayoutAvailableHeight);
|
||||
this._notifyPaneLayout();
|
||||
}
|
||||
this._finalizeIndicatorPaneLayout();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1332,8 +1333,36 @@ export class ChartManager {
|
||||
return [...historical, ...future];
|
||||
}
|
||||
|
||||
private _readSeriesPaneIndex(series: ISeriesApi<SeriesType> | undefined): number {
|
||||
if (!series) return -1;
|
||||
try {
|
||||
return series.getPane().paneIndex();
|
||||
} catch {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/** LWC 시리즈가 실제로 붙어 있는 sub-pane index (2+) */
|
||||
private _collectUsedSubPaneIndices(): Set<number> {
|
||||
const indices = new Set<number>();
|
||||
for (const entry of this.indicators.values()) {
|
||||
let found = false;
|
||||
for (const series of entry.seriesList) {
|
||||
const pi = this._readSeriesPaneIndex(series);
|
||||
if (pi >= 2) {
|
||||
indices.add(pi);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found && entry.paneIndex != null && entry.paneIndex >= 2) {
|
||||
indices.add(entry.paneIndex);
|
||||
}
|
||||
}
|
||||
return indices;
|
||||
}
|
||||
|
||||
private _getNextSubPane(): number {
|
||||
const used = new Set(Array.from(this.indicators.values()).map(e => e.paneIndex).filter(Boolean));
|
||||
const used = this._collectUsedSubPaneIndices();
|
||||
let pane = 2;
|
||||
while (used.has(pane)) pane++;
|
||||
return pane;
|
||||
@@ -2091,7 +2120,7 @@ export class ChartManager {
|
||||
let y = 0;
|
||||
for (let i = 0; i < paneCount; i++) {
|
||||
const h = Math.round((panes[i].getStretchFactor() / totalFactor) * chartAreaH);
|
||||
result.push({ paneIndex: i, topY: y, height: h });
|
||||
result.push({ paneIndex: panes[i].paneIndex(), topY: y, height: h });
|
||||
y += h + (i < paneCount - 1 ? SEP_H : 0);
|
||||
}
|
||||
return result;
|
||||
@@ -2673,12 +2702,7 @@ export class ChartManager {
|
||||
|
||||
/** 실제 보조지표가 붙어 있는 pane index 집합 (2+) */
|
||||
private _activeIndicatorPaneIndices(): Set<number> {
|
||||
const indices = new Set<number>();
|
||||
for (const entry of this.indicators.values()) {
|
||||
const p = entry.paneIndex;
|
||||
if (p != null && p >= 2) indices.add(p);
|
||||
}
|
||||
return indices;
|
||||
return this._collectUsedSubPaneIndices();
|
||||
}
|
||||
|
||||
/** pane 2+ 빈 sub-pane 제거 — reloadIndicatorsOnly 전용 (모든 지표 시리즈 제거 후) */
|
||||
@@ -2713,11 +2737,13 @@ export class ChartManager {
|
||||
|
||||
/** 활성 지표가 없는 맨 끝 sub-pane 만 제거 — 단일 지표 제거 시 나머지 pane 유지 */
|
||||
private _trimTrailingEmptySubPanes(): void {
|
||||
const active = this._activeIndicatorPaneIndices();
|
||||
for (;;) {
|
||||
const panes = this.chart.panes();
|
||||
if (panes.length <= 2) return;
|
||||
const last = panes.length - 1;
|
||||
if (this._activeIndicatorPaneIndices().has(last)) return;
|
||||
const paneIndex = panes[last].paneIndex();
|
||||
if (active.has(paneIndex)) return;
|
||||
try {
|
||||
this.chart.removePane(last);
|
||||
} catch {
|
||||
@@ -3524,11 +3550,12 @@ export class ChartManager {
|
||||
: ORPHAN_STRETCH;
|
||||
|
||||
for (let i = 0; i < panes.length; i++) {
|
||||
if (i === 0) {
|
||||
const paneIndex = panes[i].paneIndex();
|
||||
if (paneIndex === 0) {
|
||||
panes[i].setStretchFactor(mainWeight);
|
||||
} else if (i === 1) {
|
||||
} else if (paneIndex === 1) {
|
||||
panes[i].setStretchFactor(volumeShown ? volWeight : ORPHAN_STRETCH);
|
||||
} else if (activeIndPanes.has(i)) {
|
||||
} else if (activeIndPanes.has(paneIndex)) {
|
||||
panes[i].setStretchFactor(indWeight);
|
||||
} else {
|
||||
panes[i].setStretchFactor(ORPHAN_STRETCH);
|
||||
|
||||
Reference in New Issue
Block a user