diff --git a/frontend/src/components/virtual/VirtualTargetCard.tsx b/frontend/src/components/virtual/VirtualTargetCard.tsx index 4d3c519..dee57f2 100644 --- a/frontend/src/components/virtual/VirtualTargetCard.tsx +++ b/frontend/src/components/virtual/VirtualTargetCard.tsx @@ -2,7 +2,6 @@ import React, { memo, useMemo } from 'react'; import type { StrategyDto } from '../../utils/backendApi'; import { resolveVirtualTargetNames, - resolveVirtualTargetStrategyDisplayName, } from '../../utils/virtualTargetNames'; import { resolveVirtualTargetStrategyId } from '../../utils/virtualTargetStrategy'; import type { VirtualIndicatorSnapshot } from '../../hooks/useVirtualIndicatorSnapshots'; @@ -100,11 +99,6 @@ const VirtualTargetCard: React.FC = ({ koreanName ?? ticker?.koreanName, englishName, ); - const strategyDisplayName = resolveVirtualTargetStrategyDisplayName( - strategy, - strategies, - readOnlyStrategyLabel, - ); const rows = snapshot?.rows ?? []; const effectiveStrategyId = resolveVirtualTargetStrategyId( { strategyId }, @@ -160,10 +154,7 @@ const VirtualTargetCard: React.FC = ({
{isChart ? ( - <> - {strategyDisplayName} - {displayKo} - + {displayKo} ) : ( <> {displayKo} diff --git a/frontend/src/components/virtual/VirtualTargetCardChart.tsx b/frontend/src/components/virtual/VirtualTargetCardChart.tsx index fadf84d..c50214c 100644 --- a/frontend/src/components/virtual/VirtualTargetCardChart.tsx +++ b/frontend/src/components/virtual/VirtualTargetCardChart.tsx @@ -16,7 +16,7 @@ import { useHistoryLoader } from '../../hooks/useHistoryLoader'; import { useIndicatorSettings } from '../../hooks/useIndicatorSettings'; import type { ChartManager } from '../../utils/ChartManager'; import { - buildVirtualTradingCardChartIndicators, + buildStrategyChartIndicators, buildVirtualTradingChartIndicators, resolveStrategyPrimaryTimeframe, resolveStrategyTimeframes, @@ -73,7 +73,7 @@ const VirtualTargetCardChart: React.FC = ({ const indicators = useMemo(() => ( fillHeight ? buildVirtualTradingChartIndicators(strategy, getParams, getVisualConfig) - : buildVirtualTradingCardChartIndicators(strategy, getParams, getVisualConfig) + : buildStrategyChartIndicators(strategy, getParams, getVisualConfig) ), [strategy, getParams, getVisualConfig, fillHeight]); const effectiveIndicators = useMemo( @@ -91,6 +91,17 @@ const VirtualTargetCardChart: React.FC = ({ const marketRef = useRef(market); marketRef.current = market; + const syncChartLayout = useCallback(() => { + const wrap = canvasWrapRef.current; + const mgr = managerRef.current; + if (!wrap || !mgr?.hasMainSeries()) return; + const chartWrap = wrap.querySelector('.tv-chart-wrap'); + const w = chartWrap?.clientWidth ?? wrap.clientWidth; + const h = chartWrap?.clientHeight ?? wrap.clientHeight; + if (w <= 0 || h <= 0) return; + mgr.syncLayout(w, h); + }, []); + const handleCandlesReady = useCallback(() => { chartLiveReadyRef.current = true; const pending = pendingBarRef.current; @@ -98,11 +109,8 @@ const VirtualTargetCardChart: React.FC = ({ if (!pending || !mgr || barsMarketRef.current !== marketRef.current) return; pendingBarRef.current = null; mgr.updateBar(pending); - const wrap = canvasWrapRef.current; - if (wrap && wrap.clientHeight > 0) { - mgr.applyCandleOnlyLayout(true, wrap.clientHeight); - } - }, []); + syncChartLayout(); + }, [syncChartLayout]); const applyRealtimeBar = useCallback((bar: OHLCVBar, append: boolean) => { if (barsMarketRef.current !== marketRef.current) return; @@ -147,12 +155,6 @@ const VirtualTargetCardChart: React.FC = ({ const barsReady = bars.length >= 2 && barsMarket === market; - const applyPaneHeights = useCallback(() => { - const wrap = canvasWrapRef.current; - const mgr = managerRef.current; - if (!wrap || wrap.clientHeight <= 0 || !mgr?.hasMainSeries()) return; - mgr.applyCandleOnlyLayout(true, wrap.clientHeight); - }, []); const requestChartReload = useCallback(() => { chartReloadTriggeredRef.current = true; @@ -169,38 +171,36 @@ const VirtualTargetCardChart: React.FC = ({ const wrap = canvasWrapRef.current; if (!wrap) return; - const timers = [100, 300, 800, 1500, 2500].map(delay => + const timers = [200, 600, 1200].map(delay => setTimeout(() => { if (!canvasWrapRef.current) return; - const h = canvasWrapRef.current.clientHeight; - if (h <= 0) return; if (managerRef.current?.hasMainSeries()) { - managerRef.current.applyCandleOnlyLayout(true, h); - } else if (!chartReloadTriggeredRef.current && delay >= 800 && barsReady) { + syncChartLayout(); + } else if (!chartReloadTriggeredRef.current && delay >= 600 && barsReady) { requestChartReload(); } }, delay), ); - const ro = new ResizeObserver(() => applyPaneHeights()); + const ro = new ResizeObserver(() => syncChartLayout()); ro.observe(wrap); return () => { timers.forEach(clearTimeout); ro.disconnect(); }; - }, [market, timeframe, barsReady, applyPaneHeights, requestChartReload]); + }, [market, timeframe, barsReady, syncChartLayout, requestChartReload]); useEffect(() => { if (!barsReady) return; if (managerRef.current?.hasMainSeries()) { - applyPaneHeights(); + syncChartLayout(); return; } if (!chartReloadTriggeredRef.current) { requestChartReload(); } - }, [barsReady, applyPaneHeights, requestChartReload]); + }, [barsReady, syncChartLayout, requestChartReload]); useEffect(() => { if (!streamActive) return; @@ -265,9 +265,10 @@ const VirtualTargetCardChart: React.FC = ({ volumeVisible={false} paneLayoutClamp showHoverToolbar={false} - showPaneLegend={false} + showPaneLegend + showChartRightToolbar={false} showCandlePaneControls={false} - defaultCandleOnly + crosshairInfoVisible={false} candleAreaPriceLabelsEnabled={chartCandleAreaPriceLabels} indicatorAreaPriceLabelsEnabled={chartSeriesPriceLabels} paneSeparatorOptions={chartPaneSeparator} diff --git a/frontend/src/styles/virtualTradingDashboard.css b/frontend/src/styles/virtualTradingDashboard.css index 0031f66..81a21f4 100644 --- a/frontend/src/styles/virtualTradingDashboard.css +++ b/frontend/src/styles/virtualTradingDashboard.css @@ -1608,6 +1608,22 @@ display: none !important; } +/* 보조지표 pane 좌측 상단 지표명 */ +.vtd-card-chart-canvas .pane-legend-item { + right: 46px; + width: auto; + max-width: none; +} + +.vtd-card-chart-canvas .pane-legend-name { + font-size: 10px; + flex: 0 0 auto; + max-width: none; + overflow: visible; + text-overflow: clip; + white-space: nowrap; +} + .vtd-card-chart-canvas > .tv-chart-wrap { flex: 1; min-height: 0;