From 4bd93cd0374a1f388ba7d6da0621454a04af50ce Mon Sep 17 00:00:00 2001 From: Macbook Date: Tue, 9 Jun 2026 15:33:56 +0900 Subject: [PATCH] =?UTF-8?q?=EC=B5=9C=EC=A2=85=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/utils/ChartManager.ts | 59 +++++++------------------ frontend/src/utils/indicatorRegistry.ts | 26 +---------- 2 files changed, 17 insertions(+), 68 deletions(-) diff --git a/frontend/src/utils/ChartManager.ts b/frontend/src/utils/ChartManager.ts index 45e6794..d56f02f 100644 --- a/frontend/src/utils/ChartManager.ts +++ b/frontend/src/utils/ChartManager.ts @@ -225,17 +225,6 @@ function sortDualLinePlotDefs(plotDefs: PlotDef[]): PlotDef[] { ); } -/** 이중 plot 지표 시리즈 추가 순서 — OBV는 plot1→plot0 순으로 본선이 위에 그려지게 */ -function sortPlotDefsForSeriesAdd(type: string, plotDefs: PlotDef[]): PlotDef[] { - const sorted = sortDualLinePlotDefs(plotDefs); - return type === 'OBV' ? [...sorted].reverse() : sorted; -} - -/** OBV 본선(plot0) — DB plotVisibility·투명색으로 숨김 방지 */ -function isDualLinePlotForcedVisible(type: string, plotId: string): boolean { - return type === 'OBV' && plotId === 'plot0'; -} - export class ChartManager { private chart: IChartApi; private container: HTMLElement; @@ -772,13 +761,13 @@ export class ChartManager { indicatorHidden: boolean, def: ReturnType, ): void { - const plotDefs = sortPlotDefsForSeriesAdd(config.type, config.plots ?? def?.plots ?? []); + const plotDefs = sortDualLinePlotDefs(config.plots ?? def?.plots ?? []); const existingIds = new Set(seriesMeta.map(m => m.plotId)); const indicatorPriceFormat = priceFormatForIndicatorPane(pane); for (const plotDef of plotDefs) { if (existingIds.has(plotDef.id)) continue; - if (config.plotVisibility?.[plotDef.id] === false && !isDualLinePlotForcedVisible(config.type, plotDef.id)) continue; + if (config.plotVisibility?.[plotDef.id] === false) continue; if (plotDef.type === 'histogram') continue; const plotData = result.plots[plotDef.id] as PlotData | undefined; @@ -787,21 +776,15 @@ export class ChartManager { if (filtered.length === 0) continue; const isPlotVisible = !indicatorHidden - && (isDualLinePlotForcedVisible(config.type, plotDef.id) - || (this._isCustomOverlayApplied() && (config.type === 'SMA' || config.type === 'BollingerBands' || config.type === 'IchimokuCloud') - ? isCustomPlotSelected(this._getAppliedCustomOverlaySelection(), config.type, plotDef.id) - : config.plotVisibility?.[plotDef.id] !== false)); + && (this._isCustomOverlayApplied() && (config.type === 'SMA' || config.type === 'BollingerBands' || config.type === 'IchimokuCloud') + ? isCustomPlotSelected(this._getAppliedCustomOverlaySelection(), config.type, plotDef.id) + : config.plotVisibility?.[plotDef.id] !== false); const showPriceLabel = this.shouldShowSeriesPriceLabel(config, true, pane); const showSeriesTitle = pane < 2 && showPriceLabel; const regPlot = def?.plots?.find(p => p.id === plotDef.id); - const fallbackColor = config.type === 'OBV' && plotDef.id === 'plot0' - ? (regPlot?.color ?? '#2196F3') - : (regPlot?.color ?? plotDef.color ?? '#2962FF'); const series = this.chart.addSeries(LineSeries, { - color: resolvePlotLineColor(plotDef.color, fallbackColor), - lineWidth: (config.type === 'OBV' && plotDef.id === 'plot0' - ? Math.max(2, plotDef.lineWidth ?? regPlot?.lineWidth ?? 2) - : Math.max(1, plotDef.lineWidth ?? 1)) as 1 | 2 | 3 | 4, + color: resolvePlotLineColor(plotDef.color, regPlot?.color ?? plotDef.color ?? '#2962FF'), + lineWidth: Math.max(1, plotDef.lineWidth ?? regPlot?.lineWidth ?? 1) as 1 | 2 | 3 | 4, lineStyle: plotSeriesLineStyle(plotDef.lineStyle), priceLineVisible: false, lastValueVisible: showPriceLabel, @@ -899,7 +882,7 @@ export class ChartManager { const plotDefsRaw = config.plots ?? def?.plots ?? []; const plotDefs = DUAL_LINE_INDICATOR_TYPES.has(config.type) - ? sortPlotDefsForSeriesAdd(config.type, plotDefsRaw) + ? sortDualLinePlotDefs(plotDefsRaw) : plotDefsRaw; for (const plotDef of plotDefs) { @@ -919,21 +902,15 @@ export class ChartManager { seriesMeta.push({ plotId: plotDef.id, isHistogram: true, color: plotDef.color }); } else { const isPlotVisible = !indicatorHidden - && (isDualLinePlotForcedVisible(config.type, plotDef.id) - || (this._isCustomOverlayApplied() && (config.type === 'SMA' || config.type === 'BollingerBands' || config.type === 'IchimokuCloud') - ? isCustomPlotSelected(this._getAppliedCustomOverlaySelection(), config.type, plotDef.id) - : config.plotVisibility?.[plotDef.id] !== false)); + && (this._isCustomOverlayApplied() && (config.type === 'SMA' || config.type === 'BollingerBands' || config.type === 'IchimokuCloud') + ? isCustomPlotSelected(this._getAppliedCustomOverlaySelection(), config.type, plotDef.id) + : config.plotVisibility?.[plotDef.id] !== false); const showPriceLabel = this.shouldShowSeriesPriceLabel(config, true, pane); const showSeriesTitle = pane < 2 && showPriceLabel; const regPlot = def?.plots?.find(p => p.id === plotDef.id); - const fallbackColor = config.type === 'OBV' && plotDef.id === 'plot0' - ? (regPlot?.color ?? '#2196F3') - : (regPlot?.color ?? plotDef.color ?? '#2962FF'); series = this.chart.addSeries(LineSeries, { - color: resolvePlotLineColor(plotDef.color, fallbackColor), - lineWidth: (config.type === 'OBV' && plotDef.id === 'plot0' - ? Math.max(2, plotDef.lineWidth ?? regPlot?.lineWidth ?? 2) - : Math.max(1, plotDef.lineWidth ?? 1)) as 1 | 2 | 3 | 4, + color: resolvePlotLineColor(plotDef.color, regPlot?.color ?? plotDef.color ?? '#2962FF'), + lineWidth: Math.max(1, plotDef.lineWidth ?? regPlot?.lineWidth ?? 1) as 1 | 2 | 3 | 4, lineStyle: plotSeriesLineStyle(plotDef.lineStyle), priceLineVisible: false, lastValueVisible: showPriceLabel, @@ -2695,7 +2672,6 @@ export class ChartManager { /** custom 미적용 시 지표 설정 plotVisibility, 적용 시 custom 선택만 반영 */ private _resolveSeriesVisible(config: IndicatorConfig, plotId: string | undefined): boolean { if (!plotId || !this._isIndicatorEffectivelyVisible(config)) return false; - if (isDualLinePlotForcedVisible(config.type, plotId)) return true; if (!this._isCustomOverlayApplied()) { return config.plotVisibility?.[plotId] !== false; } @@ -2926,13 +2902,8 @@ export class ChartManager { } if (!entry.seriesMeta[i]?.isHistogram) { const regPlot = def?.plots?.find(p => p.id === pid); - const fallbackColor = entry.type === 'OBV' && pid === 'plot0' - ? (regPlot?.color ?? '#2196F3') - : (regPlot?.color ?? plot.color ?? '#aaa'); - opts['color'] = resolvePlotLineColor(plot.color, fallbackColor); - opts['lineWidth'] = entry.type === 'OBV' && pid === 'plot0' - ? Math.max(2, plot.lineWidth ?? regPlot?.lineWidth ?? 2) - : Math.max(1, plot.lineWidth ?? regPlot?.lineWidth ?? 1); + opts['color'] = resolvePlotLineColor(plot.color, regPlot?.color ?? plot.color ?? '#aaa'); + opts['lineWidth'] = Math.max(1, plot.lineWidth ?? regPlot?.lineWidth ?? 1); opts['lineStyle'] = plotSeriesLineStyle(plot.lineStyle); let plotAllows = true; if (entry.type === 'IchimokuCloud') { diff --git a/frontend/src/utils/indicatorRegistry.ts b/frontend/src/utils/indicatorRegistry.ts index c0079d8..a18db6f 100644 --- a/frontend/src/utils/indicatorRegistry.ts +++ b/frontend/src/utils/indicatorRegistry.ts @@ -473,35 +473,13 @@ function normalizeSignalLineIndicatorPlots( const nextPlots = merged.map(p => { const reg = registryPlots.find(r => r.id === p.id); if (!reg) return p; - const normalized = normalizeDualLinePlotDef(p, reg); - // OBV 본선 — DB 저장색(투명·신호선과 동일) 무시, registry 기본색·굵기 유지 - if (p.id === 'plot0') { - return { - ...normalized, - type: 'line' as const, - color: reg.color, - lineWidth: Math.max(2, normalized.lineWidth ?? reg.lineWidth ?? 2), - lineStyle: 'solid' as const, - }; - } - // OBV 신호선 — 값이 본선과 거의 같더라도 점선으로 시각적 구분 보장 - if (p.id === 'plot1') { - return { - ...normalized, - lineStyle: 'dashed' as const, - }; - } - return normalized; + return normalizeDualLinePlotDef(p, reg); }); - // plot0(본선) → plot1(신호선) 순서 보장 nextPlots.sort((a, b) => { const order = ['plot0', 'plot1']; return order.indexOf(a.id) - order.indexOf(b.id); }); - return { - plots: nextPlots, - plotVisibility: { ...plotVisibility, plot0: true, plot1: true }, - }; + return { plots: nextPlots, plotVisibility: { ...plotVisibility } }; } const regSignal = registryPlots.find(p => p.id === 'plot1');