/** Shared timeline zoom/pan math for Timeline and MovementBands. */ export function zoomTimelineView( clientX: number, rectLeft: number, rectWidth: number, deltaY: number, viewStart: number, viewEnd: number, absoluteMin: number, absoluteMax: number ): { start: number; end: number } { const span = viewEnd - viewStart; const ratio = (clientX - rectLeft) / rectWidth; const centerYear = viewStart + ratio * span; const factor = deltaY > 0 ? 1.15 : 0.85; const newSpan = Math.max(10, Math.min(absoluteMax - absoluteMin, span * factor)); let newStart = centerYear - ratio * newSpan; let newEnd = centerYear + (1 - ratio) * newSpan; if (newStart < absoluteMin) { newEnd += absoluteMin - newStart; newStart = absoluteMin; } if (newEnd > absoluteMax) { newStart -= newEnd - absoluteMax; newEnd = absoluteMax; } return { start: Math.round(newStart), end: Math.round(newEnd) }; } export function panTimelineView( deltaX: number, rectWidth: number, viewStart: number, viewEnd: number, absoluteMin: number, absoluteMax: number ): { start: number; end: number } { const span = viewEnd - viewStart; const yearDelta = (deltaX / rectWidth) * span; let newStart = viewStart - yearDelta; let newEnd = viewEnd - yearDelta; if (newStart < absoluteMin) { newEnd += absoluteMin - newStart; newStart = absoluteMin; } if (newEnd > absoluteMax) { newStart -= newEnd - absoluteMax; newEnd = absoluteMax; } return { start: Math.round(newStart), end: Math.round(newEnd) }; }