import type { MouseEvent } from 'react'; export interface TimelineControlProps { currentTime: number; maxTime: number; isPlaying: boolean; playbackSpeed: number; onTimeChange: (time: number) => void; onPlayPause: () => void; onSpeedChange: (speed: number) => void; simulationStartTime?: string; stepSize?: number; tickInterval?: number; majorTickEvery?: number; timeUnitLabel?: string; formatOffset?: (t: number) => string; formatAbsolute?: (t: number, base: Date) => string; showSpeedToggle?: boolean; } export function TimelineControl({ currentTime, maxTime, isPlaying, playbackSpeed, onTimeChange, onPlayPause, onSpeedChange, simulationStartTime, stepSize = 6, tickInterval = 6, majorTickEvery = 12, timeUnitLabel = 'h', formatOffset, formatAbsolute, showSpeedToggle = true, }: TimelineControlProps) { const progressPercent = maxTime > 0 ? (currentTime / maxTime) * 100 : 0; const handleRewind = () => onTimeChange(Math.max(0, currentTime - stepSize)); const handleForward = () => onTimeChange(Math.min(maxTime, currentTime + stepSize)); const handleStart = () => onTimeChange(0); const handleEnd = () => onTimeChange(maxTime); const toggleSpeed = () => { const speeds = [1, 2, 4]; const currentIndex = speeds.indexOf(playbackSpeed); onSpeedChange(speeds[(currentIndex + 1) % speeds.length]); }; const handleTimelineClick = (e: MouseEvent) => { const rect = e.currentTarget.getBoundingClientRect(); const percent = (e.clientX - rect.left) / rect.width; onTimeChange(Math.max(0, Math.min(maxTime, Math.round(percent * maxTime)))); }; const timeLabels: number[] = []; for (let t = 0; t <= maxTime; t += tickInterval) { timeLabels.push(t); } const defaultOffset = (t: number) => `+${t.toFixed(0)}${timeUnitLabel}`; const defaultAbsolute = (t: number, base: Date) => { const d = new Date(base.getTime() + t * 3600 * 1000); return `${String(d.getMonth() + 1).padStart(2, '0')}/${String(d.getDate()).padStart(2, '0')} ${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')} KST`; }; const offsetStr = (formatOffset ?? defaultOffset)(currentTime); const baseDate = simulationStartTime ? new Date(simulationStartTime) : new Date(); const absoluteStr = (formatAbsolute ?? defaultAbsolute)(currentTime, baseDate); return (
{isPlaying ? '⏸' : '▶'}
▶▶
{showSpeedToggle && ( <>
{playbackSpeed}×
)}
{timeLabels.map((t) => ( {t} {timeUnitLabel} ))}
{timeLabels.map((t) => (
))}
{offsetStr} — {absoluteStr}
진행률 {progressPercent.toFixed(0)}%
{showSpeedToggle && (
속도 {playbackSpeed}×
)}
시간 {currentTime.toFixed(0)}/{maxTime} {timeUnitLabel}
); }