From ac43a5a73fa905cdac905bc956763b6093d6738e Mon Sep 17 00:00:00 2001 From: Maze Winther Date: Wed, 15 Apr 2026 05:43:29 +0200 Subject: feat: move/resize multiple elements --- apps/web/src/lib/timeline/group-move/snap.ts | 71 ++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 apps/web/src/lib/timeline/group-move/snap.ts (limited to 'apps/web/src/lib/timeline/group-move/snap.ts') diff --git a/apps/web/src/lib/timeline/group-move/snap.ts b/apps/web/src/lib/timeline/group-move/snap.ts new file mode 100644 index 00000000..3502ae30 --- /dev/null +++ b/apps/web/src/lib/timeline/group-move/snap.ts @@ -0,0 +1,71 @@ +import type { SceneTracks } from "@/lib/timeline"; +import { + findSnapPoints, + snapToNearestPoint, + type SnapPoint, +} from "@/lib/timeline/snap-utils"; +import type { MoveGroup } from "./types"; + +export function snapGroupEdges({ + group, + anchorStartTime, + tracks, + playheadTime, + zoomLevel, +}: { + group: MoveGroup; + anchorStartTime: number; + tracks: SceneTracks; + playheadTime: number; + zoomLevel: number; +}): { + snappedAnchorStartTime: number; + snapPoint: SnapPoint | null; +} { + const snapPoints = findSnapPoints({ + tracks, + playheadTime, + excludeElementIds: new Set(group.members.map((member) => member.elementId)), + }); + + let closestSnapDistance = Infinity; + let snappedAnchorStartTime = anchorStartTime; + let snapPoint: SnapPoint | null = null; + + for (const member of group.members) { + const memberStartTime = anchorStartTime + member.timeOffset; + const memberStartSnap = snapToNearestPoint({ + targetTime: memberStartTime, + snapPoints, + zoomLevel, + }); + if ( + memberStartSnap.snapPoint && + memberStartSnap.snapDistance < closestSnapDistance + ) { + closestSnapDistance = memberStartSnap.snapDistance; + snappedAnchorStartTime = memberStartSnap.snappedTime - member.timeOffset; + snapPoint = memberStartSnap.snapPoint; + } + + const memberEndSnap = snapToNearestPoint({ + targetTime: memberStartTime + member.duration, + snapPoints, + zoomLevel, + }); + if ( + memberEndSnap.snapPoint && + memberEndSnap.snapDistance < closestSnapDistance + ) { + closestSnapDistance = memberEndSnap.snapDistance; + snappedAnchorStartTime = + memberEndSnap.snappedTime - member.duration - member.timeOffset; + snapPoint = memberEndSnap.snapPoint; + } + } + + return { + snappedAnchorStartTime, + snapPoint, + }; +} -- cgit v1.3.1