summaryrefslogtreecommitdiff
path: root/apps/web/src/hooks/use-timeline-zoom.ts
blob: 16d20d7e15a4994e61a1bc5542013234fc09d876 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import { TIMELINE_CONSTANTS } from "@/constants/timeline-constants";
import { useState, useCallback, RefObject, useMemo } from "react";

interface UseTimelineZoomProps {
  containerRef: RefObject<HTMLDivElement>;
  isInTimeline?: boolean;
}

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(): 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) => {
    if (e.ctrlKey || e.metaKey) {
      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)
        )
      );
    }
  }, []);

  return {
    zoomLevel,
    zoomStep,
    setZoomLevel,
    handleChangeZoomStep,
    handleChangeZoomLevel,
    handleWheel,
  };
}