최종수정
This commit is contained in:
@@ -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 {
|
export class ChartManager {
|
||||||
private chart: IChartApi;
|
private chart: IChartApi;
|
||||||
private container: HTMLElement;
|
private container: HTMLElement;
|
||||||
@@ -772,13 +761,13 @@ export class ChartManager {
|
|||||||
indicatorHidden: boolean,
|
indicatorHidden: boolean,
|
||||||
def: ReturnType<typeof getIndicatorDef>,
|
def: ReturnType<typeof getIndicatorDef>,
|
||||||
): void {
|
): 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 existingIds = new Set(seriesMeta.map(m => m.plotId));
|
||||||
const indicatorPriceFormat = priceFormatForIndicatorPane(pane);
|
const indicatorPriceFormat = priceFormatForIndicatorPane(pane);
|
||||||
|
|
||||||
for (const plotDef of plotDefs) {
|
for (const plotDef of plotDefs) {
|
||||||
if (existingIds.has(plotDef.id)) continue;
|
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;
|
if (plotDef.type === 'histogram') continue;
|
||||||
|
|
||||||
const plotData = result.plots[plotDef.id] as PlotData | undefined;
|
const plotData = result.plots[plotDef.id] as PlotData | undefined;
|
||||||
@@ -787,21 +776,15 @@ export class ChartManager {
|
|||||||
if (filtered.length === 0) continue;
|
if (filtered.length === 0) continue;
|
||||||
|
|
||||||
const isPlotVisible = !indicatorHidden
|
const isPlotVisible = !indicatorHidden
|
||||||
&& (isDualLinePlotForcedVisible(config.type, plotDef.id)
|
&& (this._isCustomOverlayApplied() && (config.type === 'SMA' || config.type === 'BollingerBands' || config.type === 'IchimokuCloud')
|
||||||
|| (this._isCustomOverlayApplied() && (config.type === 'SMA' || config.type === 'BollingerBands' || config.type === 'IchimokuCloud')
|
|
||||||
? isCustomPlotSelected(this._getAppliedCustomOverlaySelection(), config.type, plotDef.id)
|
? isCustomPlotSelected(this._getAppliedCustomOverlaySelection(), config.type, plotDef.id)
|
||||||
: config.plotVisibility?.[plotDef.id] !== false));
|
: config.plotVisibility?.[plotDef.id] !== false);
|
||||||
const showPriceLabel = this.shouldShowSeriesPriceLabel(config, true, pane);
|
const showPriceLabel = this.shouldShowSeriesPriceLabel(config, true, pane);
|
||||||
const showSeriesTitle = pane < 2 && showPriceLabel;
|
const showSeriesTitle = pane < 2 && showPriceLabel;
|
||||||
const regPlot = def?.plots?.find(p => p.id === plotDef.id);
|
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, {
|
const series = this.chart.addSeries(LineSeries, {
|
||||||
color: resolvePlotLineColor(plotDef.color, fallbackColor),
|
color: resolvePlotLineColor(plotDef.color, regPlot?.color ?? plotDef.color ?? '#2962FF'),
|
||||||
lineWidth: (config.type === 'OBV' && plotDef.id === 'plot0'
|
lineWidth: Math.max(1, plotDef.lineWidth ?? regPlot?.lineWidth ?? 1) as 1 | 2 | 3 | 4,
|
||||||
? Math.max(2, plotDef.lineWidth ?? regPlot?.lineWidth ?? 2)
|
|
||||||
: Math.max(1, plotDef.lineWidth ?? 1)) as 1 | 2 | 3 | 4,
|
|
||||||
lineStyle: plotSeriesLineStyle(plotDef.lineStyle),
|
lineStyle: plotSeriesLineStyle(plotDef.lineStyle),
|
||||||
priceLineVisible: false,
|
priceLineVisible: false,
|
||||||
lastValueVisible: showPriceLabel,
|
lastValueVisible: showPriceLabel,
|
||||||
@@ -899,7 +882,7 @@ export class ChartManager {
|
|||||||
|
|
||||||
const plotDefsRaw = config.plots ?? def?.plots ?? [];
|
const plotDefsRaw = config.plots ?? def?.plots ?? [];
|
||||||
const plotDefs = DUAL_LINE_INDICATOR_TYPES.has(config.type)
|
const plotDefs = DUAL_LINE_INDICATOR_TYPES.has(config.type)
|
||||||
? sortPlotDefsForSeriesAdd(config.type, plotDefsRaw)
|
? sortDualLinePlotDefs(plotDefsRaw)
|
||||||
: plotDefsRaw;
|
: plotDefsRaw;
|
||||||
|
|
||||||
for (const plotDef of plotDefs) {
|
for (const plotDef of plotDefs) {
|
||||||
@@ -919,21 +902,15 @@ export class ChartManager {
|
|||||||
seriesMeta.push({ plotId: plotDef.id, isHistogram: true, color: plotDef.color });
|
seriesMeta.push({ plotId: plotDef.id, isHistogram: true, color: plotDef.color });
|
||||||
} else {
|
} else {
|
||||||
const isPlotVisible = !indicatorHidden
|
const isPlotVisible = !indicatorHidden
|
||||||
&& (isDualLinePlotForcedVisible(config.type, plotDef.id)
|
&& (this._isCustomOverlayApplied() && (config.type === 'SMA' || config.type === 'BollingerBands' || config.type === 'IchimokuCloud')
|
||||||
|| (this._isCustomOverlayApplied() && (config.type === 'SMA' || config.type === 'BollingerBands' || config.type === 'IchimokuCloud')
|
|
||||||
? isCustomPlotSelected(this._getAppliedCustomOverlaySelection(), config.type, plotDef.id)
|
? isCustomPlotSelected(this._getAppliedCustomOverlaySelection(), config.type, plotDef.id)
|
||||||
: config.plotVisibility?.[plotDef.id] !== false));
|
: config.plotVisibility?.[plotDef.id] !== false);
|
||||||
const showPriceLabel = this.shouldShowSeriesPriceLabel(config, true, pane);
|
const showPriceLabel = this.shouldShowSeriesPriceLabel(config, true, pane);
|
||||||
const showSeriesTitle = pane < 2 && showPriceLabel;
|
const showSeriesTitle = pane < 2 && showPriceLabel;
|
||||||
const regPlot = def?.plots?.find(p => p.id === plotDef.id);
|
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, {
|
series = this.chart.addSeries(LineSeries, {
|
||||||
color: resolvePlotLineColor(plotDef.color, fallbackColor),
|
color: resolvePlotLineColor(plotDef.color, regPlot?.color ?? plotDef.color ?? '#2962FF'),
|
||||||
lineWidth: (config.type === 'OBV' && plotDef.id === 'plot0'
|
lineWidth: Math.max(1, plotDef.lineWidth ?? regPlot?.lineWidth ?? 1) as 1 | 2 | 3 | 4,
|
||||||
? Math.max(2, plotDef.lineWidth ?? regPlot?.lineWidth ?? 2)
|
|
||||||
: Math.max(1, plotDef.lineWidth ?? 1)) as 1 | 2 | 3 | 4,
|
|
||||||
lineStyle: plotSeriesLineStyle(plotDef.lineStyle),
|
lineStyle: plotSeriesLineStyle(plotDef.lineStyle),
|
||||||
priceLineVisible: false,
|
priceLineVisible: false,
|
||||||
lastValueVisible: showPriceLabel,
|
lastValueVisible: showPriceLabel,
|
||||||
@@ -2695,7 +2672,6 @@ export class ChartManager {
|
|||||||
/** custom 미적용 시 지표 설정 plotVisibility, 적용 시 custom 선택만 반영 */
|
/** custom 미적용 시 지표 설정 plotVisibility, 적용 시 custom 선택만 반영 */
|
||||||
private _resolveSeriesVisible(config: IndicatorConfig, plotId: string | undefined): boolean {
|
private _resolveSeriesVisible(config: IndicatorConfig, plotId: string | undefined): boolean {
|
||||||
if (!plotId || !this._isIndicatorEffectivelyVisible(config)) return false;
|
if (!plotId || !this._isIndicatorEffectivelyVisible(config)) return false;
|
||||||
if (isDualLinePlotForcedVisible(config.type, plotId)) return true;
|
|
||||||
if (!this._isCustomOverlayApplied()) {
|
if (!this._isCustomOverlayApplied()) {
|
||||||
return config.plotVisibility?.[plotId] !== false;
|
return config.plotVisibility?.[plotId] !== false;
|
||||||
}
|
}
|
||||||
@@ -2926,13 +2902,8 @@ export class ChartManager {
|
|||||||
}
|
}
|
||||||
if (!entry.seriesMeta[i]?.isHistogram) {
|
if (!entry.seriesMeta[i]?.isHistogram) {
|
||||||
const regPlot = def?.plots?.find(p => p.id === pid);
|
const regPlot = def?.plots?.find(p => p.id === pid);
|
||||||
const fallbackColor = entry.type === 'OBV' && pid === 'plot0'
|
opts['color'] = resolvePlotLineColor(plot.color, regPlot?.color ?? plot.color ?? '#aaa');
|
||||||
? (regPlot?.color ?? '#2196F3')
|
opts['lineWidth'] = Math.max(1, plot.lineWidth ?? regPlot?.lineWidth ?? 1);
|
||||||
: (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['lineStyle'] = plotSeriesLineStyle(plot.lineStyle);
|
opts['lineStyle'] = plotSeriesLineStyle(plot.lineStyle);
|
||||||
let plotAllows = true;
|
let plotAllows = true;
|
||||||
if (entry.type === 'IchimokuCloud') {
|
if (entry.type === 'IchimokuCloud') {
|
||||||
|
|||||||
@@ -473,35 +473,13 @@ function normalizeSignalLineIndicatorPlots(
|
|||||||
const nextPlots = merged.map(p => {
|
const nextPlots = merged.map(p => {
|
||||||
const reg = registryPlots.find(r => r.id === p.id);
|
const reg = registryPlots.find(r => r.id === p.id);
|
||||||
if (!reg) return p;
|
if (!reg) return p;
|
||||||
const normalized = normalizeDualLinePlotDef(p, reg);
|
return 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;
|
|
||||||
});
|
});
|
||||||
// plot0(본선) → plot1(신호선) 순서 보장
|
|
||||||
nextPlots.sort((a, b) => {
|
nextPlots.sort((a, b) => {
|
||||||
const order = ['plot0', 'plot1'];
|
const order = ['plot0', 'plot1'];
|
||||||
return order.indexOf(a.id) - order.indexOf(b.id);
|
return order.indexOf(a.id) - order.indexOf(b.id);
|
||||||
});
|
});
|
||||||
return {
|
return { plots: nextPlots, plotVisibility: { ...plotVisibility } };
|
||||||
plots: nextPlots,
|
|
||||||
plotVisibility: { ...plotVisibility, plot0: true, plot1: true },
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const regSignal = registryPlots.find(p => p.id === 'plot1');
|
const regSignal = registryPlots.find(p => p.id === 'plot1');
|
||||||
|
|||||||
Reference in New Issue
Block a user