전략평가 차트 전체화면
This commit is contained in:
@@ -181,6 +181,8 @@ const StrategyEvaluationChart: React.FC<Props> = ({
|
|||||||
const [backtestRunning, setBacktestRunning] = useState(false);
|
const [backtestRunning, setBacktestRunning] = useState(false);
|
||||||
const [backtestError, setBacktestError] = useState<string | null>(null);
|
const [backtestError, setBacktestError] = useState<string | null>(null);
|
||||||
const [magnifierActive, setMagnifierActive] = useState(false);
|
const [magnifierActive, setMagnifierActive] = useState(false);
|
||||||
|
const [chartFullscreen, setChartFullscreen] = useState(false);
|
||||||
|
const chartRootRef = useRef<HTMLDivElement>(null);
|
||||||
const marketBtnRef = useRef<HTMLButtonElement>(null);
|
const marketBtnRef = useRef<HTMLButtonElement>(null);
|
||||||
const managerRef = useRef<ChartManager | null>(null);
|
const managerRef = useRef<ChartManager | null>(null);
|
||||||
const [internalOverlayVisibility, setInternalOverlayVisibility] = useState<ChartOverlayVisibility>(
|
const [internalOverlayVisibility, setInternalOverlayVisibility] = useState<ChartOverlayVisibility>(
|
||||||
@@ -680,8 +682,47 @@ const StrategyEvaluationChart: React.FC<Props> = ({
|
|||||||
|
|
||||||
const selectedBar = bars[selectedBarIndex] ?? null;
|
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 (
|
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 btd-analysis-toolbar">
|
||||||
<div className="seval-chart-toolbar-run">
|
<div className="seval-chart-toolbar-run">
|
||||||
<button
|
<button
|
||||||
@@ -737,6 +778,31 @@ const StrategyEvaluationChart: React.FC<Props> = ({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="seval-chart-toolbar-actions">
|
<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 && (
|
{onOpenAiVerify && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@@ -503,6 +503,45 @@
|
|||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 차트 전체화면 — 캔들·보조지표 pane 전체 뷰포트 */
|
||||||
|
.seval-chart--fullscreen {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 10050;
|
||||||
|
background: var(--se-bg, var(--bg, #131722));
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.seval-chart--fullscreen .btd-analysis-main {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.seval-chart--fullscreen .seval-chart-body {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.seval-chart-fs-lock {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.seval-chart-fullscreen-btn {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.seval-chart-fullscreen-btn--active {
|
||||||
|
color: var(--se-accent, #3d9be9);
|
||||||
|
background: color-mix(in srgb, var(--se-accent, #3d9be9) 14%, transparent);
|
||||||
|
border-color: color-mix(in srgb, var(--se-accent, #3d9be9) 45%, var(--se-border, var(--border)));
|
||||||
|
}
|
||||||
|
|
||||||
.seval-chart-report-btn {
|
.seval-chart-report-btn {
|
||||||
width: 30px;
|
width: 30px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
|
|||||||
Reference in New Issue
Block a user