차트 세로크로스헤어 교차점 on off

This commit is contained in:
Macbook
2026-06-22 12:17:03 +09:00
parent 4a3538fb35
commit a1812922a0
13 changed files with 179 additions and 8 deletions
+75 -8
View File
@@ -347,6 +347,8 @@ export class ChartManager {
private _candleAreaPriceLabelsEnabled = true;
/** 하단 보조지표 pane(2+) — 우측 가격축 라벨·설명 */
private _indicatorAreaPriceLabelsEnabled = true;
/** 세로 크로스헤어와 선 그래프 교차점 점 표시 */
private _crosshairMarkersVisible = true;
/** 차트 하단 거래량 pane 표시 */
private _volumeVisible = true;
@@ -596,15 +598,23 @@ export class ChartManager {
borderUpColor: t.upColor, borderDownColor: t.downColor,
wickUpColor: t.upColor, wickDownColor: t.downColor,
priceFormat: MAIN_PRICE_FORMAT,
...this._crosshairMarkerSeriesOptions(),
});
case 'bar':
return this.chart.addSeries(BarSeries, { upColor: t.upColor, downColor: t.downColor, priceFormat: MAIN_PRICE_FORMAT });
return this.chart.addSeries(BarSeries, {
upColor: t.upColor, downColor: t.downColor, priceFormat: MAIN_PRICE_FORMAT,
...this._crosshairMarkerSeriesOptions(),
});
case 'line':
return this.chart.addSeries(LineSeries, { color: '#2962FF', lineWidth: 2, crosshairMarkerVisible: true, priceFormat: MAIN_PRICE_FORMAT });
return this.chart.addSeries(LineSeries, {
color: '#2962FF', lineWidth: 2, priceFormat: MAIN_PRICE_FORMAT,
...this._crosshairMarkerSeriesOptions(),
});
case 'area':
return this.chart.addSeries(AreaSeries, {
lineColor: '#2962FF', topColor: '#2962FF44', bottomColor: '#2962FF00', lineWidth: 2,
priceFormat: MAIN_PRICE_FORMAT,
...this._crosshairMarkerSeriesOptions(),
});
case 'baseline':
return this.chart.addSeries(BaselineSeries, {
@@ -612,6 +622,7 @@ export class ChartManager {
topLineColor: '#26a69a', topFillColor1: '#26a69a44', topFillColor2: '#26a69a00',
bottomLineColor: '#ef5350', bottomFillColor1: '#ef535000', bottomFillColor2: '#ef535044',
priceFormat: MAIN_PRICE_FORMAT,
...this._crosshairMarkerSeriesOptions(),
});
default:
return this.chart.addSeries(CandlestickSeries, {
@@ -619,6 +630,7 @@ export class ChartManager {
borderUpColor: t.upColor, borderDownColor: t.downColor,
wickUpColor: t.upColor, wickDownColor: t.downColor,
priceFormat: MAIN_PRICE_FORMAT,
...this._crosshairMarkerSeriesOptions(),
});
}
}
@@ -979,8 +991,7 @@ export class ChartManager {
lineStyle: plotSeriesLineStyle(plotDef.lineStyle),
priceLineVisible: false,
lastValueVisible: showPriceLabel,
crosshairMarkerVisible: true,
crosshairMarkerRadius: plotId === 'plot0' ? 4 : 3,
...this._crosshairMarkerSeriesOptions(plotId === 'plot0' ? 4 : 3),
title: showSeriesTitle ? this.seriesTitleForPlot(enriched, plotDef) : '',
visible: isPlotVisible,
priceScaleId: obvScaleId,
@@ -1046,7 +1057,7 @@ export class ChartManager {
lineWidth: Math.max(1, plotDef.lineWidth ?? regPlot?.lineWidth ?? 1) as 1 | 2 | 3 | 4,
lineStyle: plotSeriesLineStyle(plotDef.lineStyle),
priceLineVisible: false,
crosshairMarkerVisible: true,
...this._crosshairMarkerSeriesOptions(),
lastValueVisible: showPriceLabel,
title: showSeriesTitle ? this.seriesTitleForPlot(config, plotDef) : '',
visible: isPlotVisible,
@@ -1100,6 +1111,7 @@ export class ChartManager {
lastValueVisible: showPriceLabel,
title: showSeriesTitle ? this.seriesTitleForPlot(config, plotDef) : '',
visible: isPlotVisible,
...this._crosshairMarkerSeriesOptions(),
...(indicatorPriceFormat ? { priceFormat: indicatorPriceFormat } : {}),
}, pane);
series.setData(filtered.map(p => ({ time: p.time as Time, value: p.value })));
@@ -1277,7 +1289,7 @@ export class ChartManager {
lineWidth: Math.max(1, plotDef.lineWidth ?? regPlot?.lineWidth ?? 1) as 1 | 2 | 3 | 4,
lineStyle: plotSeriesLineStyle(plotDef.lineStyle),
priceLineVisible: false,
crosshairMarkerVisible: true,
...this._crosshairMarkerSeriesOptions(),
lastValueVisible: showPriceLabel,
title: showSeriesTitle ? this.seriesTitleForPlot(config, plotDef) : '',
visible: isPlotVisible,
@@ -2089,6 +2101,7 @@ export class ChartManager {
lastValueVisible: showPriceLabel && lineVisible,
title: showPriceLabel && lineVisible ? info.title : '',
visible: lineVisible,
...this._crosshairMarkerSeriesOptions(),
}, pane);
series.setData(seriesData);
seriesList.push(series);
@@ -3544,6 +3557,57 @@ export class ChartManager {
return this._indicatorAreaPriceLabelsEnabled;
}
setCrosshairMarkersVisible(enabled: boolean): void {
if (this._crosshairMarkersVisible === enabled) return;
this._crosshairMarkersVisible = enabled;
this._refreshCrosshairMarkerStyles();
}
getCrosshairMarkersVisible(): boolean {
return this._crosshairMarkersVisible;
}
private _crosshairMarkerSeriesOptions(radius?: number): {
crosshairMarkerVisible: boolean;
crosshairMarkerRadius?: number;
} {
return {
crosshairMarkerVisible: this._crosshairMarkersVisible,
...(radius != null ? { crosshairMarkerRadius: radius } : {}),
};
}
private _refreshCrosshairMarkerStyles(): void {
const visible = this._crosshairMarkersVisible;
if (this.mainSeries) {
try {
this.mainSeries.applyOptions({ crosshairMarkerVisible: visible } as Parameters<ISeriesApi<SeriesType>['applyOptions']>[0]);
} catch { /* ok */ }
}
for (const s of this.compareSeriesMap.values()) {
try {
s.applyOptions({ crosshairMarkerVisible: visible } as Parameters<ISeriesApi<SeriesType>['applyOptions']>[0]);
} catch { /* ok */ }
}
for (const entry of this.indicators.values()) {
entry.seriesList.forEach((series, i) => {
if (entry.seriesMeta[i]?.isHistogram) return;
const pid = entry.seriesMeta[i]?.plotId;
const radius = entry.type === 'OBV' && pid === 'plot0'
? 4
: entry.type === 'OBV' && pid === 'plot1'
? 3
: undefined;
try {
series.applyOptions({
crosshairMarkerVisible: visible,
...(radius != null ? { crosshairMarkerRadius: radius } : {}),
} as Parameters<ISeriesApi<SeriesType>['applyOptions']>[0]);
} catch { /* ok */ }
});
}
}
private _refreshPriceLabelStyles(): void {
for (const entry of this.indicators.values()) {
this.applyIndicatorStyle(entry.config);
@@ -3649,7 +3713,7 @@ export class ChartManager {
: Math.max(1, plot.lineWidth ?? regPlot?.lineWidth ?? 1)) as 1 | 2 | 3 | 4)
: Math.max(1, plot.lineWidth ?? regPlot?.lineWidth ?? 1);
opts['lineStyle'] = plotSeriesLineStyle(plot.lineStyle);
opts['crosshairMarkerVisible'] = true;
opts['crosshairMarkerVisible'] = this._crosshairMarkersVisible;
let plotAllows = true;
if (entry.type === 'IchimokuCloud') {
plotAllows = entry.seriesMeta[i]?.plotId !== 'plot2';
@@ -4980,7 +5044,10 @@ export class ChartManager {
// ─── Compare overlay ──────────────────────────────────────────────────────
addCompareSeries(symbol: string, bars: OHLCVBar[], color: string): void {
if (this.compareSeriesMap.has(symbol)) return;
const s = this.chart.addSeries(LineSeries, { color, lineWidth: 2, priceLineVisible: false });
const s = this.chart.addSeries(LineSeries, {
color, lineWidth: 2, priceLineVisible: false,
...this._crosshairMarkerSeriesOptions(),
});
const base = bars[0]?.close ?? 1;
s.setData(bars.map(b => ({ time: b.time as Time, value: (b.close / base - 1) * 100 })));
this.compareSeriesMap.set(symbol, s);
+2
View File
@@ -526,6 +526,8 @@ export interface AppSettingsDto {
chartLiveReceiveHighlight?: boolean;
/** 크로스헤어 이동 시 OHLC·보조지표 수치 표시 (기본 true) */
chartCrosshairInfoVisible?: boolean;
/** 세로 크로스헤어와 지표 선 교차점 점 표시 (기본 true) */
chartCrosshairMarkersVisible?: boolean;
/** 차트 마우스오버 줌·이동 플로팅 툴바 표시 (기본 true) */
chartHoverToolbarVisible?: boolean;
/** 차트 상단 범례(tv-legend) 항목별 표시 옵션 */