diff options
Diffstat (limited to 'apps/web/src/components/editor/timeline/timeline-scroll-sync.tsx')
| -rw-r--r-- | apps/web/src/components/editor/timeline/timeline-scroll-sync.tsx | 68 |
1 files changed, 13 insertions, 55 deletions
diff --git a/apps/web/src/components/editor/timeline/timeline-scroll-sync.tsx b/apps/web/src/components/editor/timeline/timeline-scroll-sync.tsx index 2318f977..473c6f3e 100644 --- a/apps/web/src/components/editor/timeline/timeline-scroll-sync.tsx +++ b/apps/web/src/components/editor/timeline/timeline-scroll-sync.tsx @@ -3,20 +3,16 @@ import { useEffect, useRef } from "react"; export interface TimelineScrollSyncProps { rulerScrollRef: React.RefObject<HTMLDivElement>; tracksScrollRef: React.RefObject<HTMLDivElement>; - trackLabelsScrollRef: React.RefObject<HTMLDivElement>; } export function useTimelineScrollSync({ rulerScrollRef, tracksScrollRef, - trackLabelsScrollRef, }: TimelineScrollSyncProps) { const isUpdatingRef = useRef(false); - const lastRulerSync = useRef(0); - const lastTracksSync = useRef(0); - const lastVerticalSync = useRef(0); + const lastSyncRef = useRef(0); - // --- Scroll synchronization effect --- + // --- Horizontal scroll synchronization between ruler and tracks --- useEffect(() => { const rulerViewport = rulerScrollRef.current?.querySelector( "[data-radix-scroll-area-viewport]" @@ -24,76 +20,38 @@ export function useTimelineScrollSync({ const tracksViewport = tracksScrollRef.current?.querySelector( "[data-radix-scroll-area-viewport]" ) as HTMLElement; - const trackLabelsViewport = trackLabelsScrollRef.current?.querySelector( - "[data-radix-scroll-area-viewport]" - ) as HTMLElement; if (!rulerViewport || !tracksViewport) return; - // Horizontal scroll synchronization between ruler and tracks + // Throttled scroll handlers for better performance const handleRulerScroll = () => { const now = Date.now(); - if (isUpdatingRef.current || now - lastRulerSync.current < 16) return; - lastRulerSync.current = now; + if (isUpdatingRef.current || now - lastSyncRef.current < 16) return; // 60fps throttling + lastSyncRef.current = now; + isUpdatingRef.current = true; tracksViewport.scrollLeft = rulerViewport.scrollLeft; isUpdatingRef.current = false; }; + const handleTracksScroll = () => { const now = Date.now(); - if (isUpdatingRef.current || now - lastTracksSync.current < 16) return; - lastTracksSync.current = now; + if (isUpdatingRef.current || now - lastSyncRef.current < 16) return; // 60fps throttling + lastSyncRef.current = now; + isUpdatingRef.current = true; rulerViewport.scrollLeft = tracksViewport.scrollLeft; isUpdatingRef.current = false; }; - rulerViewport.addEventListener("scroll", handleRulerScroll); - tracksViewport.addEventListener("scroll", handleTracksScroll); - - // Vertical scroll synchronization between track labels and tracks content - if (trackLabelsViewport) { - const handleTrackLabelsScroll = () => { - const now = Date.now(); - if (isUpdatingRef.current || now - lastVerticalSync.current < 16) - return; - lastVerticalSync.current = now; - isUpdatingRef.current = true; - tracksViewport.scrollTop = trackLabelsViewport.scrollTop; - isUpdatingRef.current = false; - }; - const handleTracksVerticalScroll = () => { - const now = Date.now(); - if (isUpdatingRef.current || now - lastVerticalSync.current < 16) - return; - lastVerticalSync.current = now; - isUpdatingRef.current = true; - trackLabelsViewport.scrollTop = tracksViewport.scrollTop; - isUpdatingRef.current = false; - }; - - trackLabelsViewport.addEventListener("scroll", handleTrackLabelsScroll); - tracksViewport.addEventListener("scroll", handleTracksVerticalScroll); - - return () => { - rulerViewport.removeEventListener("scroll", handleRulerScroll); - tracksViewport.removeEventListener("scroll", handleTracksScroll); - trackLabelsViewport.removeEventListener( - "scroll", - handleTrackLabelsScroll - ); - tracksViewport.removeEventListener( - "scroll", - handleTracksVerticalScroll - ); - }; - } + rulerViewport.addEventListener("scroll", handleRulerScroll, { passive: true }); + tracksViewport.addEventListener("scroll", handleTracksScroll, { passive: true }); return () => { rulerViewport.removeEventListener("scroll", handleRulerScroll); tracksViewport.removeEventListener("scroll", handleTracksScroll); }; - }, []); + }, [rulerScrollRef, tracksScrollRef]); return null; } |
