종목변경 시 캔들차트 사라지는 현상 수정
This commit is contained in:
@@ -15,6 +15,8 @@ import { DEFAULT_DISPLAY_TIMEZONE } from '../utils/timezone';
|
||||
|
||||
interface TradingChartProps {
|
||||
bars: OHLCVBar[];
|
||||
/** bars 가 현재 market 과 일치할 때만 전달 (없으면 bars.length>0 이면 준비된 것으로 간주) */
|
||||
barsMarket?: string | null;
|
||||
/** BB 등 다른 심볼 계산용 */
|
||||
market?: string;
|
||||
timeframe?: Timeframe;
|
||||
@@ -78,7 +80,7 @@ interface TradingChartProps {
|
||||
}
|
||||
|
||||
const TradingChart: React.FC<TradingChartProps> = ({
|
||||
bars, market = '', timeframe = '1D', chartType, theme, mode, indicators, drawingTool, drawings,
|
||||
bars, barsMarket, market = '', timeframe = '1D', chartType, theme, mode, indicators, drawingTool, drawings,
|
||||
logScale, drawingsLocked = false, drawingsVisible = true,
|
||||
onCrosshair, onManagerReady, onAddDrawing,
|
||||
onSeriesClick, onSeriesDoubleClick,
|
||||
@@ -255,6 +257,8 @@ const TradingChart: React.FC<TradingChartProps> = ({
|
||||
|
||||
// ── 전체 재로드 (데이터 + 인디케이터) ─────────────────────────────────────
|
||||
const reloadSafetyTimers = useRef<ReturnType<typeof setTimeout>[]>([]);
|
||||
const reloadGenRef = useRef(0);
|
||||
const reloadRetryRef = useRef(0);
|
||||
|
||||
const reloadAll = useCallback(async (
|
||||
mgr: ChartManager,
|
||||
@@ -266,10 +270,50 @@ const TradingChart: React.FC<TradingChartProps> = ({
|
||||
) => {
|
||||
if (newBars.length === 0) return;
|
||||
|
||||
const gen = ++reloadGenRef.current;
|
||||
|
||||
reloadSafetyTimers.current.forEach(clearTimeout);
|
||||
reloadSafetyTimers.current = [];
|
||||
|
||||
barsRef.current = newBars;
|
||||
barsRef.current = newBars;
|
||||
|
||||
mgr.setData(newBars, ct, th);
|
||||
if (gen !== reloadGenRef.current) {
|
||||
prevBarsKey.current = '';
|
||||
return;
|
||||
}
|
||||
mgr.setTheme(th);
|
||||
mgr.setLogScale(ls);
|
||||
mgr.setDisplayTimezone(displayTimezone, timeframe);
|
||||
|
||||
for (const ind of inds) {
|
||||
if (gen !== reloadGenRef.current) {
|
||||
prevBarsKey.current = '';
|
||||
return;
|
||||
}
|
||||
await mgr.addIndicator(ind);
|
||||
}
|
||||
|
||||
if (gen !== reloadGenRef.current) {
|
||||
prevBarsKey.current = '';
|
||||
return;
|
||||
}
|
||||
|
||||
const expectIndicators = inds.some(i => i.hidden !== true);
|
||||
if (expectIndicators && mgr.getIndicatorCount() === 0) {
|
||||
prevBarsKey.current = '';
|
||||
if (reloadRetryRef.current < 3) {
|
||||
reloadRetryRef.current += 1;
|
||||
requestAnimationFrame(() => {
|
||||
if (managerRef.current) {
|
||||
void reloadAll(managerRef.current, newBars, ct, th, ls, inds);
|
||||
}
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
reloadRetryRef.current = 0;
|
||||
prevChartType.current = ct;
|
||||
prevTheme.current = th;
|
||||
prevLogScale.current = ls;
|
||||
@@ -277,15 +321,6 @@ const TradingChart: React.FC<TradingChartProps> = ({
|
||||
prevIndKey.current = indKey(inds);
|
||||
prevSortedPKRef.current = sortedParamKey(inds);
|
||||
|
||||
mgr.setData(newBars, ct, th);
|
||||
mgr.setTheme(th);
|
||||
mgr.setLogScale(ls);
|
||||
mgr.setDisplayTimezone(displayTimezone, timeframe);
|
||||
|
||||
for (const ind of inds) {
|
||||
await mgr.addIndicator(ind);
|
||||
}
|
||||
|
||||
await new Promise<void>(resolve => requestAnimationFrame(() => requestAnimationFrame(() => {
|
||||
applyPaneLayout(mgr);
|
||||
requestAnimationFrame(() => {
|
||||
@@ -295,6 +330,11 @@ const TradingChart: React.FC<TradingChartProps> = ({
|
||||
});
|
||||
})));
|
||||
|
||||
if (gen !== reloadGenRef.current) {
|
||||
prevBarsKey.current = '';
|
||||
return;
|
||||
}
|
||||
|
||||
onDataLoaded?.();
|
||||
|
||||
reloadSafetyTimers.current = [300, 700, 1400].map(delay =>
|
||||
@@ -611,6 +651,12 @@ const TradingChart: React.FC<TradingChartProps> = ({
|
||||
prevMarket.current = market;
|
||||
prevMarketTf.current = timeframe;
|
||||
prevBarsKey.current = '';
|
||||
prevIndKey.current = '';
|
||||
reloadRetryRef.current = 0;
|
||||
reloadGenRef.current += 1;
|
||||
reloadSafetyTimers.current.forEach(clearTimeout);
|
||||
reloadSafetyTimers.current = [];
|
||||
managerRef.current?.cancelPendingIndicatorUpdates();
|
||||
}, [market, timeframe]);
|
||||
|
||||
// ── 데이터/인디케이터 동기화 ─────────────────────────────────────────────
|
||||
@@ -618,6 +664,11 @@ const TradingChart: React.FC<TradingChartProps> = ({
|
||||
const mgr = managerRef.current;
|
||||
if (!mgr || !chartMgr || bars.length === 0) return;
|
||||
|
||||
const barsReady = barsMarket === undefined
|
||||
? true
|
||||
: barsMarket === market;
|
||||
if (!barsReady) return;
|
||||
|
||||
// manager 준비 전 bars 가 먼저 도착한 경우(로그인 직후 등) 메인 시리즈 누락 방지
|
||||
if (!mgr.hasMainSeries()) {
|
||||
void reloadAll(mgr, bars, chartType, theme, logScale, indicators);
|
||||
@@ -631,12 +682,16 @@ const TradingChart: React.FC<TradingChartProps> = ({
|
||||
const ctChanged = chartType !== prevChartType.current;
|
||||
const thChanged = theme !== prevTheme.current;
|
||||
const lsChanged = logScale !== prevLogScale.current;
|
||||
const expectIndicators = indicators.some(i => i.hidden !== true);
|
||||
const indicatorsIncomplete = expectIndicators
|
||||
&& mgr.hasMainSeries()
|
||||
&& mgr.getIndicatorCount() === 0;
|
||||
|
||||
if (!barsChanged && !indChanged && !ctChanged && !thChanged && !lsChanged) return;
|
||||
if (!barsChanged && !indChanged && !ctChanged && !thChanged && !lsChanged && !indicatorsIncomplete) return;
|
||||
|
||||
if (barsChanged || ctChanged || thChanged) {
|
||||
// 데이터 또는 차트 형식 변경 → 전체 재로드
|
||||
reloadAll(mgr, bars, chartType, theme, logScale, indicators);
|
||||
if (barsChanged || ctChanged || thChanged || indicatorsIncomplete) {
|
||||
// 데이터·차트 형식 변경 또는 지표 누락 → 전체 재로드
|
||||
void reloadAll(mgr, bars, chartType, theme, logScale, indicators);
|
||||
} else if (lsChanged) {
|
||||
prevLogScale.current = logScale;
|
||||
mgr.setLogScale(logScale);
|
||||
@@ -715,7 +770,26 @@ const TradingChart: React.FC<TradingChartProps> = ({
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [chartMgr, bars, chartType, theme, logScale, indicators]);
|
||||
}, [chartMgr, bars, barsMarket, market, chartType, theme, logScale, indicators]);
|
||||
|
||||
// 종목 전환 직후 reloadAll 이 중단되어 캔들만 남은 경우 자동 복구
|
||||
useEffect(() => {
|
||||
const mgr = managerRef.current;
|
||||
if (!mgr || !chartMgr || bars.length === 0) return;
|
||||
if (barsMarket !== undefined && barsMarket !== market) return;
|
||||
|
||||
const expectIndicators = indicators.some(i => i.hidden !== true);
|
||||
if (!expectIndicators) return;
|
||||
|
||||
const t = window.setTimeout(() => {
|
||||
const m = managerRef.current;
|
||||
if (!m || !m.hasMainSeries() || m.getIndicatorCount() > 0) return;
|
||||
prevBarsKey.current = '';
|
||||
void reloadAll(m, bars, chartType, theme, logScale, indicators);
|
||||
}, 120);
|
||||
|
||||
return () => window.clearTimeout(t);
|
||||
}, [chartMgr, bars, barsMarket, market, chartType, theme, logScale, indicators, reloadAll]);
|
||||
|
||||
// cursor 모드에서 드로잉 위에 있으면 pointer 커서로 변경
|
||||
const handleWrapperMouseMove = useCallback((e: React.PointerEvent) => {
|
||||
|
||||
Reference in New Issue
Block a user