summaryrefslogtreecommitdiff
path: root/apps/web/src/hooks/use-timeline-snapping.ts
diff options
context:
space:
mode:
Diffstat (limited to 'apps/web/src/hooks/use-timeline-snapping.ts')
-rw-r--r--apps/web/src/hooks/use-timeline-snapping.ts292
1 files changed, 146 insertions, 146 deletions
diff --git a/apps/web/src/hooks/use-timeline-snapping.ts b/apps/web/src/hooks/use-timeline-snapping.ts
index f7f96392..e51f6a22 100644
--- a/apps/web/src/hooks/use-timeline-snapping.ts
+++ b/apps/web/src/hooks/use-timeline-snapping.ts
@@ -3,176 +3,176 @@ import { TimelineTrack } from "@/types/timeline";
import { TIMELINE_CONSTANTS } from "@/constants/timeline-constants";
export interface SnapPoint {
- time: number;
- type: "element-start" | "element-end" | "playhead";
- elementId?: string;
- trackId?: string;
+ time: number;
+ type: "element-start" | "element-end" | "playhead";
+ elementId?: string;
+ trackId?: string;
}
export interface SnapResult {
- snappedTime: number;
- snapPoint: SnapPoint | null;
- snapDistance: number;
+ snappedTime: number;
+ snapPoint: SnapPoint | null;
+ snapDistance: number;
}
export interface UseTimelineSnappingOptions {
- snapThreshold?: number; // Distance in pixels to trigger snapping
- enableElementSnapping?: boolean;
- enablePlayheadSnapping?: boolean;
+ snapThreshold?: number; // Distance in pixels to trigger snapping
+ enableElementSnapping?: boolean;
+ enablePlayheadSnapping?: boolean;
}
export function useTimelineSnapping({
- snapThreshold = 10,
- enableElementSnapping = true,
- enablePlayheadSnapping = true,
+ snapThreshold = 10,
+ enableElementSnapping = true,
+ enablePlayheadSnapping = true,
}: UseTimelineSnappingOptions = {}) {
- const findSnapPoints = useCallback(
- (
- tracks: TimelineTrack[],
- currentTime: number,
- playheadTime: number,
- zoomLevel: number,
- excludeElementId?: string
- ): SnapPoint[] => {
- const snapPoints: SnapPoint[] = [];
+ const findSnapPoints = useCallback(
+ (
+ tracks: TimelineTrack[],
+ currentTime: number,
+ playheadTime: number,
+ zoomLevel: number,
+ excludeElementId?: string,
+ ): SnapPoint[] => {
+ const snapPoints: SnapPoint[] = [];
- // Add element snap points
- if (enableElementSnapping) {
- tracks.forEach((track) => {
- track.elements.forEach((element) => {
- // Skip the element being dragged
- if (element.id === excludeElementId) return;
+ // Add element snap points
+ if (enableElementSnapping) {
+ tracks.forEach((track) => {
+ track.elements.forEach((element) => {
+ // Skip the element being dragged
+ if (element.id === excludeElementId) return;
- const elementStart = element.startTime;
- const elementEnd =
- element.startTime +
- (element.duration - element.trimStart - element.trimEnd);
+ const elementStart = element.startTime;
+ const elementEnd =
+ element.startTime +
+ (element.duration - element.trimStart - element.trimEnd);
- snapPoints.push(
- {
- time: elementStart,
- type: "element-start",
- elementId: element.id,
- trackId: track.id,
- },
- {
- time: elementEnd,
- type: "element-end",
- elementId: element.id,
- trackId: track.id,
- }
- );
- });
- });
- }
+ snapPoints.push(
+ {
+ time: elementStart,
+ type: "element-start",
+ elementId: element.id,
+ trackId: track.id,
+ },
+ {
+ time: elementEnd,
+ type: "element-end",
+ elementId: element.id,
+ trackId: track.id,
+ },
+ );
+ });
+ });
+ }
- // Add playhead snap point
- if (enablePlayheadSnapping) {
- snapPoints.push({
- time: playheadTime,
- type: "playhead",
- });
- }
+ // Add playhead snap point
+ if (enablePlayheadSnapping) {
+ snapPoints.push({
+ time: playheadTime,
+ type: "playhead",
+ });
+ }
- return snapPoints;
- },
- [enableElementSnapping, enablePlayheadSnapping]
- );
+ return snapPoints;
+ },
+ [enableElementSnapping, enablePlayheadSnapping],
+ );
- const snapToNearestPoint = useCallback(
- (
- targetTime: number,
- snapPoints: SnapPoint[],
- zoomLevel: number
- ): SnapResult => {
- const pixelsPerSecond = TIMELINE_CONSTANTS.PIXELS_PER_SECOND * zoomLevel;
- const thresholdInSeconds = snapThreshold / pixelsPerSecond;
+ const snapToNearestPoint = useCallback(
+ (
+ targetTime: number,
+ snapPoints: SnapPoint[],
+ zoomLevel: number,
+ ): SnapResult => {
+ const pixelsPerSecond = TIMELINE_CONSTANTS.PIXELS_PER_SECOND * zoomLevel;
+ const thresholdInSeconds = snapThreshold / pixelsPerSecond;
- let closestSnapPoint: SnapPoint | null = null;
- let closestDistance = Infinity;
+ let closestSnapPoint: SnapPoint | null = null;
+ let closestDistance = Infinity;
- snapPoints.forEach((snapPoint) => {
- const distance = Math.abs(targetTime - snapPoint.time);
- if (distance < thresholdInSeconds && distance < closestDistance) {
- closestDistance = distance;
- closestSnapPoint = snapPoint;
- }
- });
+ snapPoints.forEach((snapPoint) => {
+ const distance = Math.abs(targetTime - snapPoint.time);
+ if (distance < thresholdInSeconds && distance < closestDistance) {
+ closestDistance = distance;
+ closestSnapPoint = snapPoint;
+ }
+ });
- return {
- snappedTime: closestSnapPoint
- ? (closestSnapPoint as SnapPoint).time
- : targetTime,
- snapPoint: closestSnapPoint,
- snapDistance: closestDistance,
- };
- },
- [snapThreshold]
- );
+ return {
+ snappedTime: closestSnapPoint
+ ? (closestSnapPoint as SnapPoint).time
+ : targetTime,
+ snapPoint: closestSnapPoint,
+ snapDistance: closestDistance,
+ };
+ },
+ [snapThreshold],
+ );
- const snapElementPosition = useCallback(
- (
- targetTime: number,
- tracks: TimelineTrack[],
- playheadTime: number,
- zoomLevel: number,
- excludeElementId?: string
- ): SnapResult => {
- const snapPoints = findSnapPoints(
- tracks,
- targetTime,
- playheadTime,
- zoomLevel,
- excludeElementId
- );
+ const snapElementPosition = useCallback(
+ (
+ targetTime: number,
+ tracks: TimelineTrack[],
+ playheadTime: number,
+ zoomLevel: number,
+ excludeElementId?: string,
+ ): SnapResult => {
+ const snapPoints = findSnapPoints(
+ tracks,
+ targetTime,
+ playheadTime,
+ zoomLevel,
+ excludeElementId,
+ );
- return snapToNearestPoint(targetTime, snapPoints, zoomLevel);
- },
- [findSnapPoints, snapToNearestPoint]
- );
+ return snapToNearestPoint(targetTime, snapPoints, zoomLevel);
+ },
+ [findSnapPoints, snapToNearestPoint],
+ );
- const snapElementEdge = useCallback(
- (
- targetTime: number,
- elementDuration: number,
- tracks: TimelineTrack[],
- playheadTime: number,
- zoomLevel: number,
- excludeElementId?: string,
- snapToStart = true // true for start edge, false for end edge
- ): SnapResult => {
- const snapPoints = findSnapPoints(
- tracks,
- targetTime,
- playheadTime,
- zoomLevel,
- excludeElementId
- );
+ const snapElementEdge = useCallback(
+ (
+ targetTime: number,
+ elementDuration: number,
+ tracks: TimelineTrack[],
+ playheadTime: number,
+ zoomLevel: number,
+ excludeElementId?: string,
+ snapToStart = true, // true for start edge, false for end edge
+ ): SnapResult => {
+ const snapPoints = findSnapPoints(
+ tracks,
+ targetTime,
+ playheadTime,
+ zoomLevel,
+ excludeElementId,
+ );
- // For end edge snapping, we need to account for element duration
- const effectiveTargetTime = snapToStart
- ? targetTime
- : targetTime + elementDuration;
- const snapResult = snapToNearestPoint(
- effectiveTargetTime,
- snapPoints,
- zoomLevel
- );
+ // For end edge snapping, we need to account for element duration
+ const effectiveTargetTime = snapToStart
+ ? targetTime
+ : targetTime + elementDuration;
+ const snapResult = snapToNearestPoint(
+ effectiveTargetTime,
+ snapPoints,
+ zoomLevel,
+ );
- // Adjust the snapped time back for end edge
- if (!snapToStart && snapResult.snapPoint) {
- snapResult.snappedTime = snapResult.snappedTime - elementDuration;
- }
+ // Adjust the snapped time back for end edge
+ if (!snapToStart && snapResult.snapPoint) {
+ snapResult.snappedTime = snapResult.snappedTime - elementDuration;
+ }
- return snapResult;
- },
- [findSnapPoints, snapToNearestPoint]
- );
+ return snapResult;
+ },
+ [findSnapPoints, snapToNearestPoint],
+ );
- return {
- snapElementPosition,
- snapElementEdge,
- findSnapPoints,
- snapToNearestPoint,
- };
+ return {
+ snapElementPosition,
+ snapElementEdge,
+ findSnapPoints,
+ snapToNearestPoint,
+ };
}