투자관리 차트탭 기능 수정
This commit is contained in:
@@ -264,6 +264,9 @@ export class ChartManager {
|
||||
/** 알림 목록 미니 차트 등 고정 높이 — pane 최소 px·비율 완화 */
|
||||
private _compactPaneLayout = false;
|
||||
|
||||
/** 캔들+거래량 그룹 vs 보조 pane 그룹 stretch 비율 (투자관리·백테스트 분석 차트) */
|
||||
private _paneAreaRatio: { candle: number; aux: number } | null = null;
|
||||
|
||||
constructor(
|
||||
container: HTMLElement,
|
||||
theme: Theme,
|
||||
@@ -2054,10 +2057,6 @@ export class ChartManager {
|
||||
private _viewportLwcHooked = false;
|
||||
private readonly _lwcViewportHandler = (): void => { this._notifyViewport(); };
|
||||
|
||||
/** 캔들 pane 시간축 — 드래그 패닝 중 transform 동기화용 */
|
||||
private _candleAxisPanActive = false;
|
||||
private _candleAxisPanOffsetPx = 0;
|
||||
|
||||
private _notifyViewport(): void {
|
||||
for (const cb of this._viewportListeners) {
|
||||
try { cb(); } catch { /* ok */ }
|
||||
@@ -2096,29 +2095,6 @@ export class ChartManager {
|
||||
this._notifyViewport();
|
||||
}
|
||||
|
||||
/** 캔들 pane 시간축 드래그 패닝 종료 — 라벨 위치를 최종 논리 범위로 재정렬 */
|
||||
endCandleAxisPan(): void {
|
||||
if (!this._candleAxisPanActive) return;
|
||||
this._candleAxisPanActive = false;
|
||||
this._candleAxisPanOffsetPx = 0;
|
||||
this._notifyViewport();
|
||||
}
|
||||
|
||||
isCandleAxisPanActive(): boolean {
|
||||
return this._candleAxisPanActive;
|
||||
}
|
||||
|
||||
getCandleAxisPanOffsetPx(): number {
|
||||
return this._candleAxisPanOffsetPx;
|
||||
}
|
||||
|
||||
private _ensureCandleAxisPan(): void {
|
||||
if (this._candleAxisPanActive) return;
|
||||
this._candleAxisPanActive = true;
|
||||
this._candleAxisPanOffsetPx = 0;
|
||||
this._notifyViewport();
|
||||
}
|
||||
|
||||
/** visible logical range → 플롯 X (LWC 좌표 API와 동일한 선형 매핑) */
|
||||
private _logicalToAxisX(logical: number, lr: { from: number; to: number }, plotWidth: number): number {
|
||||
const span = lr.to - lr.from;
|
||||
@@ -3040,9 +3016,6 @@ export class ChartManager {
|
||||
options?: { allowVerticalPan?: boolean },
|
||||
): void {
|
||||
if (deltaX !== 0) {
|
||||
this._ensureCandleAxisPan();
|
||||
this._candleAxisPanOffsetPx += deltaX;
|
||||
|
||||
const ts = this.chart.timeScale();
|
||||
const lr = ts.getVisibleLogicalRange();
|
||||
if (lr) {
|
||||
@@ -3272,6 +3245,11 @@ export class ChartManager {
|
||||
return this.rawBars.length;
|
||||
}
|
||||
|
||||
/** 현재 차트에 로드된 캔들 스냅샷 (과거 추가 로드·백테스트 재계산용) */
|
||||
getRawBars(): OHLCVBar[] {
|
||||
return this.rawBars.slice();
|
||||
}
|
||||
|
||||
/** 두 시각(초) 사이에 포함된 봉 개수 — 기간(날짜 범위) 측정 라벨용 */
|
||||
countBarsBetweenTime(t0: number, t1: number): number {
|
||||
const lo = Math.min(t0, t1);
|
||||
@@ -3296,15 +3274,15 @@ export class ChartManager {
|
||||
* 사용자가 보고 있던 구간이 유지되도록 합니다.
|
||||
* - 모든 보조지표를 전체 데이터 기준으로 재계산합니다.
|
||||
*/
|
||||
async prependBars(olderBars: OHLCVBar[]): Promise<void> {
|
||||
if (!this.mainSeries || olderBars.length === 0) return;
|
||||
async prependBars(olderBars: OHLCVBar[]): Promise<number> {
|
||||
if (!this.mainSeries || olderBars.length === 0) return 0;
|
||||
|
||||
const firstExistingTime = this.rawBars[0]?.time as number | undefined;
|
||||
const newBars = firstExistingTime !== undefined
|
||||
? olderBars.filter(b => (b.time as number) < firstExistingTime)
|
||||
: olderBars;
|
||||
|
||||
if (newBars.length === 0) return;
|
||||
if (newBars.length === 0) return 0;
|
||||
|
||||
// 현재 가시 논리 범위 저장 (prepend 후 복원용)
|
||||
const logicalRange = this.chart.timeScale().getVisibleLogicalRange();
|
||||
@@ -3349,6 +3327,7 @@ export class ChartManager {
|
||||
|
||||
// 보조지표 전체 재계산 (새 데이터가 왼쪽에 추가됐으므로 전체 갱신 필요)
|
||||
await this._refreshAllIndicatorsData();
|
||||
return newBars.length;
|
||||
}
|
||||
|
||||
/** 모든 보조지표를 현재 rawBars 기준으로 전체 재계산하고 시리즈 데이터를 교체합니다. */
|
||||
@@ -3628,6 +3607,21 @@ export class ChartManager {
|
||||
*
|
||||
* @param availableHeight 외부에서 측정한 실제 가용 높이(px). 스크롤 필요 여부 판단에만 사용.
|
||||
*/
|
||||
/**
|
||||
* 캔들 영역 vs 보조지표 영역 높이 비율 (예: 보조 1개 → 2:1, 2~5개 → 1:1, 6+ → 1:2)
|
||||
* auxWeight 가 0 이면 비율 해제.
|
||||
*/
|
||||
setPaneAreaRatio(candleWeight: number, auxWeight: number): void {
|
||||
if (auxWeight <= 0) {
|
||||
this._paneAreaRatio = null;
|
||||
} else {
|
||||
this._paneAreaRatio = {
|
||||
candle: Math.max(0.1, candleWeight),
|
||||
aux: Math.max(0.1, auxWeight),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private _volumeFrac(H: number): number {
|
||||
if (!this._volumeVisible || this._candleOnlyLayout) return 0;
|
||||
return Math.min(Math.max(60 / H, 0.04), 0.12);
|
||||
@@ -3750,7 +3744,15 @@ export class ChartManager {
|
||||
? this._lastLayoutAvailableHeight
|
||||
: this.container.clientHeight);
|
||||
const N = this._activeIndicatorPaneIndices().size;
|
||||
const { mainFrac } = this._paneHeightFractions(N, this._volumeFrac(H), H);
|
||||
const volFrac = this._volumeFrac(H);
|
||||
let mainFrac: number;
|
||||
if (this._paneAreaRatio && N > 0) {
|
||||
const total = this._paneAreaRatio.candle + this._paneAreaRatio.aux;
|
||||
const candleGroupFrac = this._paneAreaRatio.candle / total;
|
||||
mainFrac = Math.max(0.12, candleGroupFrac - volFrac);
|
||||
} else {
|
||||
mainFrac = this._paneHeightFractions(N, volFrac, H).mainFrac;
|
||||
}
|
||||
|
||||
return this._applyPaneStretchFactors(mainFrac, availableHeight);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user