summaryrefslogtreecommitdiff
path: root/apps/web/src/hooks/use-timeline-zoom.ts
diff options
context:
space:
mode:
authorMaze <167211895+mazeincoding@users.noreply.github.com>2025-07-17 17:22:42 +0200
committerGitHub <noreply@github.com>2025-07-17 17:22:42 +0200
commitb97a30824e3d9758850281aa40e64d074126d1cb (patch)
tree6b3f3e246ee326adf3371861610433bb5c711014 /apps/web/src/hooks/use-timeline-zoom.ts
parent502725b98ec53b1668ceeae1a9f5463c64cdddf6 (diff)
parentfaf5a121ac271666a92218fc46be92e25c715ee3 (diff)
downloadopencut-b97a30824e3d9758850281aa40e64d074126d1cb.tar.gz
Merge pull request #283 from KhacTuanIT/feature/optimize-timeline-ruler
Optimize timeline performance
Diffstat (limited to 'apps/web/src/hooks/use-timeline-zoom.ts')
-rw-r--r--apps/web/src/hooks/use-timeline-zoom.ts103
1 files changed, 71 insertions, 32 deletions
diff --git a/apps/web/src/hooks/use-timeline-zoom.ts b/apps/web/src/hooks/use-timeline-zoom.ts
index ce32c9f0..c8780f9a 100644
--- a/apps/web/src/hooks/use-timeline-zoom.ts
+++ b/apps/web/src/hooks/use-timeline-zoom.ts
@@ -1,4 +1,5 @@
-import { useState, useCallback, useEffect, RefObject } from "react";
+import { TIMELINE_CONSTANTS } from "@/constants/timeline-constants";
+import { useState, useCallback, RefObject, useMemo } from "react";
interface UseTimelineZoomProps {
containerRef: RefObject<HTMLDivElement>;
@@ -7,48 +8,86 @@ interface UseTimelineZoomProps {
interface UseTimelineZoomReturn {
zoomLevel: number;
+ zoomStep: number;
setZoomLevel: (zoomLevel: number | ((prev: number) => number)) => void;
+ handleChangeZoomStep: (zoomStep: number) => void;
+ handleChangeZoomLevel: (zoomStep: number) => void;
handleWheel: (e: React.WheelEvent) => void;
}
-export function useTimelineZoom({
- containerRef,
- isInTimeline = false,
-}: UseTimelineZoomProps): UseTimelineZoomReturn {
+/**
+ * useTimelineZoom
+ *
+ * Custom hook to manage zoom logic for a timeline component.
+ * Handles zoom state, step calculation, level changes, and mouse wheel zooming (with ctrl/meta).
+ */
+export function useTimelineZoom(): UseTimelineZoomReturn {
+ // Current zoom level (1 = default)
const [zoomLevel, setZoomLevel] = useState(1);
+ /**
+ * Calculate the current zoom step based on the zoom level and a base step constant.
+ * Ensures minimum step is 1 (prevents zero or negative step).
+ */
+ const zoomStep = useMemo(
+ () =>
+ Math.max(1, Math.round(zoomLevel / TIMELINE_CONSTANTS.ZOOM_STEP_BASE)),
+ [zoomLevel]
+ );
+
+ /**
+ * Update the zoom level using a given step.
+ * The zoom level is clamped to a minimum value defined in constants.
+ */
+ const handleChangeZoomStep = useCallback((newStep: number) => {
+ setZoomLevel(
+ Math.max(
+ TIMELINE_CONSTANTS.ZOOM_LEVEL_MIN,
+ newStep * TIMELINE_CONSTANTS.ZOOM_STEP_BASE
+ )
+ );
+ }, []);
+
+ /**
+ * Update the zoom level directly.
+ * The new value is clamped between the defined minimum and maximum levels.
+ */
+ const handleChangeZoomLevel = useCallback((newLevel: number) => {
+ setZoomLevel(
+ Math.max(
+ TIMELINE_CONSTANTS.ZOOM_LEVEL_MIN,
+ Math.min(TIMELINE_CONSTANTS.ZOOM_LEVEL_MAX, newLevel)
+ )
+ );
+ }, []);
+
+ /**
+ * Handle zooming using mouse wheel + ctrl/meta key (like browser zoom).
+ * Prevents default browser behavior and updates zoom level accordingly.
+ */
const handleWheel = useCallback((e: React.WheelEvent) => {
- // Only zoom if user is using pinch gesture (ctrlKey or metaKey is true)
if (e.ctrlKey || e.metaKey) {
- e.preventDefault();
- const delta = e.deltaY > 0 ? -0.15 : 0.15;
- setZoomLevel((prev) => Math.max(0.1, Math.min(10, prev + delta)));
+ e.preventDefault?.();
+ const delta =
+ e.deltaY > 0
+ ? -TIMELINE_CONSTANTS.ZOOM_STEP_BASE
+ : TIMELINE_CONSTANTS.ZOOM_STEP_BASE;
+ setZoomLevel((prev) =>
+ Math.max(
+ TIMELINE_CONSTANTS.ZOOM_LEVEL_MIN,
+ Math.min(TIMELINE_CONSTANTS.ZOOM_LEVEL_MAX, prev + delta)
+ )
+ );
}
- // Otherwise, allow normal scrolling
}, []);
- // Prevent browser zooming in/out when in timeline
- useEffect(() => {
- const preventZoom = (e: WheelEvent) => {
- if (
- isInTimeline &&
- (e.ctrlKey || e.metaKey) &&
- containerRef.current?.contains(e.target as Node)
- ) {
- e.preventDefault();
- }
- };
-
- document.addEventListener("wheel", preventZoom, { passive: false });
-
- return () => {
- document.removeEventListener("wheel", preventZoom);
- };
- }, [isInTimeline, containerRef]);
-
+ // Return all handlers and state values for use in timeline components
return {
- zoomLevel,
- setZoomLevel,
- handleWheel,
+ zoomLevel, // Current zoom level
+ zoomStep, // Current zoom step (calculated from zoomLevel)
+ setZoomLevel, // Directly set the zoom level (accepts value or updater function)
+ handleChangeZoomStep, // Change zoom by step value
+ handleChangeZoomLevel, // Change zoom by level value
+ handleWheel, // Handler for mouse wheel zooming
};
}