// 时间线标尺:按缩放渲染刻度与播放头,点击/拖拽设置播放头时间。 import { useMemo, useRef } from "react"; import { formatTimelineTime, getRulerTickStep } from "@/lib/timeline/timeline-view"; import type { CanvasTheme } from "@/lib/canvas-theme"; type CanvasTimelineRulerProps = { pxPerMs: number; durationMs: number; playheadMs: number; width: number; theme: CanvasTheme; onSeek: (ms: number) => void; }; export function CanvasTimelineRuler({ pxPerMs, durationMs, playheadMs, width, theme, onSeek }: CanvasTimelineRulerProps) { const barRef = useRef(null); const draggingRef = useRef(false); const ticks = useMemo(() => { const stepMs = getRulerTickStep(pxPerMs); const count = Math.max(1, Math.ceil(durationMs / stepMs)); return Array.from({ length: count + 1 }, (_, index) => { const ms = index * stepMs; const x = Math.round(ms * pxPerMs); return { ms, x, major: index % 5 === 0 }; }); }, [durationMs, pxPerMs]); const seekFromEvent = (clientX: number) => { const rect = barRef.current?.getBoundingClientRect(); if (!rect) return; const ratio = Math.min(1, Math.max(0, (clientX - rect.left) / Math.max(1, rect.width))); onSeek(Math.round(ratio * durationMs)); }; return (
{ draggingRef.current = true; event.currentTarget.setPointerCapture(event.pointerId); seekFromEvent(event.clientX); }} onPointerMove={(event) => { if (draggingRef.current) seekFromEvent(event.clientX); }} onPointerUp={(event) => { draggingRef.current = false; event.currentTarget.releasePointerCapture(event.pointerId); }} > {ticks.map((tick) => (
{tick.major ? ( {formatTimelineTime(tick.ms)} ) : null}
))}
{formatTimelineTime(playheadMs)}
); }