diff --git a/frontend/src/utils/ChartManager.ts b/frontend/src/utils/ChartManager.ts index 05c69ea..7e48981 100644 --- a/frontend/src/utils/ChartManager.ts +++ b/frontend/src/utils/ChartManager.ts @@ -164,10 +164,6 @@ interface IndicatorEntry { bbFillPrimitive?: BollingerBandFillPrimitive; config: IndicatorConfig; cloudPlugin?: IchimokuCloudPlugin; // 일목균형표 구름 플러그인 - /** pane 'right' 축 오염 방지용 전용 priceScaleId (OBV 제외 서브 pane 지표) */ - isolatedScaleId?: string; - /** isolatedScale autoscaleInfoProvider 초기 min/max */ - plotAutoscaleBounds?: { min: number; max: number }; } interface AlertEntry { price: number; label: string; line: IPriceLine; } @@ -1022,7 +1018,7 @@ export class ChartManager { pane: number, indicatorHidden: boolean, def: ReturnType, - scaleOpts: ReturnType = null, + scaleOpts: ReturnType = null, ): void { const plotDefs = this._dualLinePlotDefsForRender(config, def); const indicatorPriceFormat = priceFormatForIndicatorSeries(def); @@ -1222,7 +1218,7 @@ export class ChartManager { const plotDefsRaw = config.plots ?? def?.plots ?? []; const plotRange = this._computePlotsValueRange(result.plots as Record); - const scaleOpts = this._isolatedScaleSeriesOptions(config, plotRange); + const scaleOpts = this._autoscaleSeriesOptions(config, plotRange); const indicatorPriceFormat = priceFormatForIndicatorSeries(def); if (config.type === 'OBV') { @@ -1350,15 +1346,10 @@ export class ChartManager { const entry: IndicatorEntry = { id: config.id, type: config.type, seriesList, seriesMeta, paneIndex: pane, alertLines: [], hlineRefs, fillPrimitive, config, - isolatedScaleId: scaleOpts?.priceScaleId, - plotAutoscaleBounds: plotRange ?? undefined, }; const actualPane = this._readSeriesPaneIndex(seriesList[0]); const minSub = this._minIndicatorSubPane(); if (actualPane >= minSub) entry.paneIndex = actualPane; - if (entry.isolatedScaleId != null && entry.paneIndex != null && entry.paneIndex >= minSub) { - this._applyIsolatedScalePaneOptions(entry.isolatedScaleId, entry.paneIndex); - } if (this._indicatorLoadStale(dataGenAtStart) || this.indicators.has(config.id)) { this._discardIndicatorSeries(seriesList, { fillPrimitive }); return; @@ -2226,11 +2217,7 @@ export class ChartManager { } } - private _indicatorScaleId(configId: string): string { - return `ind-${configId}`; - } - - /** plot 데이터 min/max — 전용 가격축 autoscale 용 */ + /** plot 데이터 min/max — autoscaleInfoProvider 용 */ private _computePlotsValueRange( plots: Record, plotIds?: string[], @@ -2250,14 +2237,14 @@ export class ChartManager { return { min: lo, max: hi }; } - /** OBV 제외 서브 pane 지표 — pane 공유 'right' 축 오염(종가·타 지표 값 혼입) 방지 */ - private _usesIsolatedPriceScale(type: string): boolean { + /** OBV 제외 서브 pane — pane 기본 'right' 축 + autoscale (overlay priceScaleId 는 UI·크로스헤어 라벨 없음) */ + private _usesAutoscaleProvider(type: string): boolean { if (type === 'OBV') return false; const def = getIndicatorDef(type); return !!(def && !def.overlay && !def.returnsMarkers); } - private _makeIsolatedAutoscaleProvider(lo: number, hi: number) { + private _makeAutoscaleProvider(lo: number, hi: number) { return (baseImpl: () => { priceRange: { minValue: number; maxValue: number } } | null) => { let minV = lo; let maxV = hi; @@ -2273,37 +2260,19 @@ export class ChartManager { }; } - private _isolatedScaleSeriesOptions( + private _autoscaleSeriesOptions( config: IndicatorConfig, plotRange: { min: number; max: number } | null, - ): { - priceScaleId: string; - autoscaleInfoProvider?: ReturnType; - } | null { - if (!this._usesIsolatedPriceScale(config.type)) return null; - const scaleId = this._indicatorScaleId(config.id); - if (!plotRange || plotRange.max <= plotRange.min) { - return { priceScaleId: scaleId }; - } + ): { autoscaleInfoProvider: ReturnType } | null { + if (!this._usesAutoscaleProvider(config.type)) return null; + if (!plotRange || plotRange.max <= plotRange.min) return null; let { min, max } = plotRange; const def = getIndicatorDef(config.type); if (def?.hlines?.some(h => h.price === 0)) { min = Math.min(min, 0); max = Math.max(max, 0); } - return { - priceScaleId: scaleId, - autoscaleInfoProvider: this._makeIsolatedAutoscaleProvider(min, max), - }; - } - - private _applyIsolatedScalePaneOptions(scaleId: string, pane: number): void { - try { - this.chart.priceScale(scaleId, pane).applyOptions({ - visible: true, - scaleMargins: { top: 0.12, bottom: 0.12 }, - }); - } catch { /* ok */ } + return { autoscaleInfoProvider: this._makeAutoscaleProvider(min, max) }; } /** 볼륨 pane(1)이 실제로 표시되는지 여부 */ @@ -2430,7 +2399,7 @@ export class ChartManager { if (!moved && entry.paneIndex === target) continue; entry.paneIndex = target; - // 통일된 pane 에서 OBV·전용축 지표 옵션 재확정 (이동 중 손실 방지) + // 통일된 pane 에서 OBV 전용 축 옵션 재확정 (이동 중 손실 방지) if (entry.type === 'OBV' && entry.config) { try { this.chart.priceScale(`obv-${entry.config.id}`, target).applyOptions({ @@ -2438,8 +2407,6 @@ export class ChartManager { scaleMargins: { top: 0.12, bottom: 0.12 }, }); } catch { /* ok */ } - } else if (entry.isolatedScaleId) { - this._applyIsolatedScalePaneOptions(entry.isolatedScaleId, target); } } }