전략평가 차트 전체화면
This commit is contained in:
@@ -181,6 +181,8 @@ const StrategyEvaluationChart: React.FC<Props> = ({
|
||||
const [backtestRunning, setBacktestRunning] = useState(false);
|
||||
const [backtestError, setBacktestError] = useState<string | null>(null);
|
||||
const [magnifierActive, setMagnifierActive] = useState(false);
|
||||
const [chartFullscreen, setChartFullscreen] = useState(false);
|
||||
const chartRootRef = useRef<HTMLDivElement>(null);
|
||||
const marketBtnRef = useRef<HTMLButtonElement>(null);
|
||||
const managerRef = useRef<ChartManager | null>(null);
|
||||
const [internalOverlayVisibility, setInternalOverlayVisibility] = useState<ChartOverlayVisibility>(
|
||||
@@ -680,8 +682,47 @@ const StrategyEvaluationChart: React.FC<Props> = ({
|
||||
|
||||
const selectedBar = bars[selectedBarIndex] ?? null;
|
||||
|
||||
useEffect(() => {
|
||||
const cls = 'seval-chart-fs-lock';
|
||||
if (chartFullscreen) {
|
||||
document.body.classList.add(cls);
|
||||
} else {
|
||||
document.body.classList.remove(cls);
|
||||
}
|
||||
return () => document.body.classList.remove(cls);
|
||||
}, [chartFullscreen]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!chartFullscreen) return;
|
||||
const onKey = (e: KeyboardEvent) => {
|
||||
if (e.key !== 'Escape' || isKeyboardTypingTarget(e.target)) return;
|
||||
setChartFullscreen(false);
|
||||
};
|
||||
document.addEventListener('keydown', onKey);
|
||||
return () => document.removeEventListener('keydown', onKey);
|
||||
}, [chartFullscreen]);
|
||||
|
||||
useEffect(() => {
|
||||
const raf = requestAnimationFrame(() => {
|
||||
requestAnimationFrame(() => {
|
||||
const root = chartRootRef.current;
|
||||
const mgr = managerRef.current;
|
||||
if (!root || !mgr) return;
|
||||
const wrap = root.querySelector('.tv-chart-wrap') as HTMLElement | null;
|
||||
const w = root.clientWidth;
|
||||
const h = wrap?.clientHeight ?? root.clientHeight;
|
||||
if (w > 0 && h > 0) mgr.resize(w, h);
|
||||
mgr.refreshPaneSeparatorOverlay();
|
||||
});
|
||||
});
|
||||
return () => cancelAnimationFrame(raf);
|
||||
}, [chartFullscreen, bars.length]);
|
||||
|
||||
return (
|
||||
<div className="seval-chart btd-analysis-chart">
|
||||
<div
|
||||
ref={chartRootRef}
|
||||
className={`seval-chart btd-analysis-chart${chartFullscreen ? ' seval-chart--fullscreen' : ''}`}
|
||||
>
|
||||
<div className="seval-chart-toolbar btd-analysis-toolbar">
|
||||
<div className="seval-chart-toolbar-run">
|
||||
<button
|
||||
@@ -737,6 +778,31 @@ const StrategyEvaluationChart: React.FC<Props> = ({
|
||||
)}
|
||||
</div>
|
||||
<div className="seval-chart-toolbar-actions">
|
||||
<button
|
||||
type="button"
|
||||
className={`btd-analysis-tool seval-chart-fullscreen-btn${chartFullscreen ? ' seval-chart-fullscreen-btn--active' : ''}`}
|
||||
title={chartFullscreen ? '전체화면 종료 (Esc)' : '차트 전체화면 (캔들·보조지표)'}
|
||||
aria-label={chartFullscreen ? '전체화면 종료' : '차트 전체화면'}
|
||||
aria-pressed={chartFullscreen}
|
||||
disabled={loading || bars.length === 0}
|
||||
onClick={() => setChartFullscreen(v => !v)}
|
||||
>
|
||||
{chartFullscreen ? (
|
||||
<svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden>
|
||||
<polyline points="6,6 1,1" />
|
||||
<polyline points="10,6 15,1" />
|
||||
<polyline points="6,10 1,15" />
|
||||
<polyline points="10,10 15,15" />
|
||||
</svg>
|
||||
) : (
|
||||
<svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden>
|
||||
<polyline points="1,6 1,1 6,1" />
|
||||
<polyline points="10,1 15,1 15,6" />
|
||||
<polyline points="15,10 15,15 10,15" />
|
||||
<polyline points="6,15 1,15 1,10" />
|
||||
</svg>
|
||||
)}
|
||||
</button>
|
||||
{onOpenAiVerify && (
|
||||
<button
|
||||
type="button"
|
||||
|
||||
Reference in New Issue
Block a user