실시간 차트 캔들차트 높이 조절
This commit is contained in:
@@ -250,6 +250,8 @@ const TradingChart: React.FC<TradingChartProps> = ({
|
||||
const candleOnlyModeRef = useRef(false);
|
||||
const paneAreaRatioRef = useRef(paneAreaRatio);
|
||||
paneAreaRatioRef.current = paneAreaRatio;
|
||||
/** 사용자 드래그로 설정한 pane 비율 — prop 변경 시 초기화 */
|
||||
const userDraggedRatioRef = useRef<{ candle: number; aux: number } | null>(null);
|
||||
const lastCrosshairPriceRef = useRef<number | null>(null);
|
||||
const onTradeOrderRequestRef = useRef(onTradeOrderRequest);
|
||||
onTradeOrderRequestRef.current = onTradeOrderRequest;
|
||||
@@ -276,6 +278,13 @@ const TradingChart: React.FC<TradingChartProps> = ({
|
||||
const indicatorSyncInFlightRef = useRef(false);
|
||||
const [paneLegendPaused, setPaneLegendPaused] = useState(false);
|
||||
const [chartBodyHeight, setChartBodyHeight] = useState(0);
|
||||
/** 캔들 pane 하단 Y 위치 (드래그 핸들용) — null 이면 보조지표 없음 */
|
||||
const [candlePaneBottomY, setCandlePaneBottomY] = useState<number | null>(null);
|
||||
const paneResizeDragRef = useRef<{
|
||||
startClientY: number;
|
||||
startCandleH: number;
|
||||
wrapperH: number;
|
||||
} | null>(null);
|
||||
const pendingIndicatorResyncRef = useRef(false);
|
||||
const indicatorReloadGenRef = useRef(0);
|
||||
const prevMarket = useRef<string>(market);
|
||||
@@ -324,6 +333,74 @@ const TradingChart: React.FC<TradingChartProps> = ({
|
||||
return () => ro.disconnect();
|
||||
}, [chartMgr]);
|
||||
|
||||
/** 캔들 pane 하단 Y 추적 — 보조지표 있을 때만 드래그 핸들 표시 */
|
||||
useEffect(() => {
|
||||
const mgr = managerRef.current;
|
||||
if (!mgr || !chartMgr) return;
|
||||
|
||||
const updateHandle = () => {
|
||||
const layouts = mgr.getPaneLayouts();
|
||||
const candle = layouts.find(l => l.paneIndex === 0);
|
||||
const hasAux = layouts.some(l => l.paneIndex >= 2 && l.height > 20);
|
||||
if (candle && candle.height > 20 && hasAux) {
|
||||
setCandlePaneBottomY(candle.topY + candle.height);
|
||||
} else {
|
||||
setCandlePaneBottomY(null);
|
||||
}
|
||||
};
|
||||
|
||||
updateHandle();
|
||||
return mgr.subscribePaneLayout(updateHandle);
|
||||
}, [chartMgr]);
|
||||
|
||||
/** 캔들/보조지표 영역 분리선 드래그 핸들러 */
|
||||
const onPaneResizePointerDown = useCallback((e: React.PointerEvent<HTMLDivElement>) => {
|
||||
const mgr = managerRef.current;
|
||||
const wrapper = wrapperRef.current;
|
||||
if (!mgr || !wrapper) return;
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
(e.currentTarget as HTMLDivElement).setPointerCapture(e.pointerId);
|
||||
const layouts = mgr.getPaneLayouts();
|
||||
const candle = layouts.find(l => l.paneIndex === 0);
|
||||
paneResizeDragRef.current = {
|
||||
startClientY: e.clientY,
|
||||
startCandleH: candle?.height ?? 200,
|
||||
wrapperH: wrapper.clientHeight,
|
||||
};
|
||||
}, []);
|
||||
|
||||
const onPaneResizePointerMove = useCallback((e: React.PointerEvent<HTMLDivElement>) => {
|
||||
const drag = paneResizeDragRef.current;
|
||||
const mgr = managerRef.current;
|
||||
const wrapper = wrapperRef.current;
|
||||
const container = containerRef.current;
|
||||
if (!drag || !mgr || !wrapper || !container) return;
|
||||
|
||||
const dy = e.clientY - drag.startClientY;
|
||||
const H = drag.wrapperH;
|
||||
const MIN_CANDLE = 100;
|
||||
const MIN_AUX = 60;
|
||||
const newCandleH = Math.max(MIN_CANDLE, Math.min(H - MIN_AUX, drag.startCandleH + dy));
|
||||
const newCandle = newCandleH / H;
|
||||
const newAux = 1 - newCandle;
|
||||
|
||||
mgr.setPaneAreaRatio(newCandle, newAux);
|
||||
// applyPaneLayout 이 ResizeObserver 로 재실행돼도 이 비율 유지
|
||||
userDraggedRatioRef.current = { candle: newCandle, aux: newAux };
|
||||
const required = mgr.resetPaneHeights(H);
|
||||
|
||||
// 스크롤 영역이 필요한 경우 컨테이너 확장
|
||||
const newContainerH = required > H + 4 ? required : H;
|
||||
if (container.style.height !== `${newContainerH}px`) {
|
||||
container.style.height = `${newContainerH}px`;
|
||||
}
|
||||
}, []);
|
||||
|
||||
const onPaneResizePointerUp = useCallback(() => {
|
||||
paneResizeDragRef.current = null;
|
||||
}, []);
|
||||
|
||||
const toggleCandleOnly = useCallback(() => {
|
||||
if (candleOnlyLocked) return;
|
||||
setCandleOnlyMode(v => !v);
|
||||
@@ -410,7 +487,8 @@ const TradingChart: React.FC<TradingChartProps> = ({
|
||||
if (mgr.isCandleOnlyLayout()) {
|
||||
mgr.restoreFromCandleFullscreen(wrapperH);
|
||||
}
|
||||
const ratio = paneAreaRatioRef.current;
|
||||
// 사용자 드래그 비율 우선, 없으면 prop 기반 비율
|
||||
const ratio = userDraggedRatioRef.current ?? paneAreaRatioRef.current;
|
||||
if (ratio && ratio.aux > 0) {
|
||||
mgr.setPaneAreaRatio(ratio.candle, ratio.aux);
|
||||
} else {
|
||||
@@ -443,6 +521,11 @@ const TradingChart: React.FC<TradingChartProps> = ({
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [paneLayoutClamp, paneAreaRatio]);
|
||||
|
||||
/** paneAreaRatio prop 이 외부에서 변경되면 드래그 비율 초기화 (전략 변경 등) */
|
||||
useEffect(() => {
|
||||
userDraggedRatioRef.current = null;
|
||||
}, [paneAreaRatio]);
|
||||
|
||||
/** pane 레이아웃 + 가격·시간축 정상화 (느린 네트워크·레이아웃 지연 후 복구용) */
|
||||
const normalizeChartViewport = useCallback((mgr: ChartManager) => {
|
||||
applyPaneLayout(mgr);
|
||||
@@ -1614,6 +1697,17 @@ const TradingChart: React.FC<TradingChartProps> = ({
|
||||
ref={containerRef}
|
||||
className="chart-container"
|
||||
/>
|
||||
{/* 캔들 pane 하단 드래그 핸들 — 캔들/보조지표 높이 비율 조절 */}
|
||||
{candlePaneBottomY != null && !candleOnlyMode && !paneLayoutClamp && chartPaintReady && (
|
||||
<div
|
||||
className="chart-pane-resize-handle"
|
||||
style={{ top: candlePaneBottomY }}
|
||||
onPointerDown={onPaneResizePointerDown}
|
||||
onPointerMove={onPaneResizePointerMove}
|
||||
onPointerUp={onPaneResizePointerUp}
|
||||
onPointerCancel={onPaneResizePointerUp}
|
||||
/>
|
||||
)}
|
||||
{chartMgr && !candleOnlyMode && showPaneLegend && chartPaintReady && (
|
||||
<ChartRightToolbar
|
||||
manager={chartMgr}
|
||||
|
||||
Reference in New Issue
Block a user