From b266678fe4bb8c4053688fd037693fa2f930ac14 Mon Sep 17 00:00:00 2001 From: gantiro Date: Tue, 15 Jul 2025 22:51:38 +0700 Subject: Optimize timeline performance --- apps/web/src/hooks/use-timeline-zoom.ts | 74 ++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 29 deletions(-) (limited to 'apps/web/src/hooks/use-timeline-zoom.ts') diff --git a/apps/web/src/hooks/use-timeline-zoom.ts b/apps/web/src/hooks/use-timeline-zoom.ts index ce32c9f0..16d20d7e 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; @@ -7,48 +8,63 @@ 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 { +export function useTimelineZoom(): UseTimelineZoomReturn { const [zoomLevel, setZoomLevel] = useState(1); + const zoomStep = useMemo( + () => + Math.max(1, Math.round(zoomLevel / TIMELINE_CONSTANTS.ZOOM_STEP_BASE)), + [zoomLevel] + ); + + const handleChangeZoomStep = useCallback((newStep: number) => { + setZoomLevel( + Math.max( + TIMELINE_CONSTANTS.ZOOM_LEVEL_MIN, + newStep * TIMELINE_CONSTANTS.ZOOM_STEP_BASE + ) + ); + }, []); + + const handleChangeZoomLevel = useCallback((newLevel: number) => { + setZoomLevel( + Math.max( + TIMELINE_CONSTANTS.ZOOM_LEVEL_MIN, + Math.min(TIMELINE_CONSTANTS.ZOOM_LEVEL_MAX, newLevel) + ) + ); + }, []); + + // Mouse wheel zoom, ctrl/meta gesture 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 { zoomLevel, + zoomStep, setZoomLevel, + handleChangeZoomStep, + handleChangeZoomLevel, handleWheel, }; } -- cgit v1.3.1