import { type TimelineState, xToTime } from './renderer'; export type { TimelineState }; const MIN_VISIBLE_RANGE = 0.1; const MIN_ZOOM = 1; export function clampZoom(zoom: number, duration: number): number { const maxZoom = duration / MIN_VISIBLE_RANGE; return Math.max(MIN_ZOOM, Math.min(zoom, maxZoom)); } export function computeZoom( state: TimelineState, anchorTime: number, factor: number, duration: number ): { visibleStart: number; visibleEnd: number; zoom: number } { const currentRange = state.visibleEnd - state.visibleStart; if (currentRange <= 0) { return { visibleStart: state.visibleStart, visibleEnd: state.visibleEnd, zoom: state.zoom, }; } const newRange = currentRange / factor; const clampedRange = Math.max(MIN_VISIBLE_RANGE, Math.min(newRange, duration)); const anchorRatio = (anchorTime - state.visibleStart) / currentRange; let newStart = anchorTime - anchorRatio * clampedRange; let newEnd = newStart + clampedRange; if (newStart < 0) { newStart = 0; newEnd = clampedRange; } if (newEnd > duration) { newEnd = duration; newStart = Math.max(0, newEnd - clampedRange); } const newZoom = clampZoom(duration / clampedRange, duration); return { visibleStart: newStart, visibleEnd: newEnd, zoom: newZoom }; } export function handleClick( x: number, state: TimelineState, duration: number ): number { const time = xToTime(x, state); return Math.max(0, Math.min(time, duration)); }