26 lines
1.2 KiB
TypeScript
26 lines
1.2 KiB
TypeScript
export interface SnapPoint { ms: number; label: string }
|
|||
|
|
|
||
|
|
/** Keep magnetic selection consistent with zoom without attracting distant audio. */
|
||
|
|
export function snapTimelineTime(ms: number, points: SnapPoint[], duration: number, width: number, bypass = false) {
|
||
|
|
const bounded = Math.round(Math.max(0, Math.min(duration, ms)));
|
||
|
|
const radius = Math.min(500, duration / Math.max(1, width) * 8);
|
||
|
|
let point: SnapPoint | null = null;
|
||
|
|
let distance = radius;
|
||
|
|
if (!bypass) {
|
||
|
|
for (const candidate of points) {
|
||
|
|
if (candidate.ms < 0 || candidate.ms > duration) continue;
|
||
|
|
const delta = Math.abs(candidate.ms - bounded);
|
||
|
|
if (delta <= distance && (!point || delta < distance)) { point = candidate; distance = delta; }
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return { ms: point?.ms ?? bounded, point };
|
||
|
|
}
|
||
|
|
|
||
|
|
/** A resized segment must stay in the recording and retain a positive duration. */
|
||
|
|
export function resizeTranscriptRange(start: number, end: number, edge: "start" | "end", ms: number, duration: number) {
|
||
|
|
const value = Math.round(ms);
|
||
|
|
return edge === "start"
|
||
|
|
? { start_ms: Math.max(0, Math.min(end - 1, value)), end_ms: end }
|
||
|
|
: { start_ms: start, end_ms: Math.max(start + 1, Math.min(duration, value)) };
|
||
|
|
}
|