File size: 3,716 Bytes
bc18ad5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import { findIndex } from "./search";
import {
  FRAME_INTERVAL,
  PREVIEW_FRAME_WIDTH,
  TIMELINE_OFFSET_X
} from "../constants/constants";
import { ITimelineScaleState } from "@designcombo/types";
import { TIMELINE_ZOOM_LEVELS } from "../constants/scale";

export function getPreviousZoomLevel(
  currentZoom: ITimelineScaleState
): ITimelineScaleState {
  const previousZoom = getPreviousZoom(currentZoom);

  return previousZoom || TIMELINE_ZOOM_LEVELS[0];
}

export function getZoomByIndex(index: number) {
  return TIMELINE_ZOOM_LEVELS[index];
}
export function getNextZoomLevel(
  currentZoom: ITimelineScaleState
): ITimelineScaleState {
  const nextZoom = getNextZoom(currentZoom);

  return nextZoom || TIMELINE_ZOOM_LEVELS[TIMELINE_ZOOM_LEVELS.length - 1];
}

export const getPreviousZoom = (
  currentZoom: ITimelineScaleState
): ITimelineScaleState | null => {
  // Filter zoom levels that are smaller than the current zoom
  const smallerZoomLevels = TIMELINE_ZOOM_LEVELS.filter(
    (level) => level.zoom < currentZoom.zoom
  );

  // If there are no smaller zoom levels, return null (no previous zoom)
  if (smallerZoomLevels.length === 0) {
    return null;
  }

  // Get the zoom level with the largest zoom value that's still smaller than the current zoom
  const previousZoom = smallerZoomLevels.reduce((prev, curr) =>
    curr.zoom > prev.zoom ? curr : prev
  );

  return previousZoom;
};

export const getNextZoom = (
  currentZoom: ITimelineScaleState
): ITimelineScaleState | null => {
  // Filter zoom levels that are larger than the current zoom
  const largerZoomLevels = TIMELINE_ZOOM_LEVELS.filter(
    (level) => level.zoom > currentZoom.zoom
  );

  // If there are no larger zoom levels, return null (no next zoom)
  if (largerZoomLevels.length === 0) {
    return null;
  }

  // Get the zoom level with the smallest zoom value that's still larger than the current zoom
  const nextZoom = largerZoomLevels.reduce((prev, curr) =>
    curr.zoom < prev.zoom ? curr : prev
  );

  return nextZoom;
};

export function getFitZoomLevel(
  totalLengthMs: number,
  zoom = 1,
  scrollOffset = 8 // Default fallback value
): ITimelineScaleState {
  const getVisibleWidth = () => {
    const clampedScrollOffset = Math.max(0, scrollOffset);

    const timelineCanvas = document.getElementById(
      "designcombo-timeline-canvas"
    ) as HTMLElement;
    const offsetWidth =
      timelineCanvas?.offsetWidth ?? document.body.offsetWidth;

    // Use 1 to prevent NaN because of dividing by 0.
    return Math.max(1, offsetWidth - clampedScrollOffset);
  };

  const getFullWidth = () => {
    if (typeof totalLengthMs === "number") {
      return timeMsToUnits(totalLengthMs, zoom);
    }

    return calculateTimelineWidth(totalLengthMs, zoom);
  };

  const multiplier = getVisibleWidth() / getFullWidth();
  const targetZoom = zoom * multiplier;

  const fitZoomIndex = findIndex(TIMELINE_ZOOM_LEVELS, (level) => {
    return level.zoom > targetZoom;
  });

  // const clampedIndex = clamp(fitZoomIndex, 0, TIMELINE_ZOOM_LEVELS.length - 1);

  return {
    segments: 5,
    index: fitZoomIndex,
    zoom: targetZoom,
    unit: 1 / targetZoom
  };
}

export function timeMsToUnits(timeMs: number, zoom = 1): number {
  const zoomedFrameWidth = PREVIEW_FRAME_WIDTH * zoom;
  const frames = timeMs * (60 / 1000);

  return frames * zoomedFrameWidth;
}

export function unitsToTimeMs(units: number, zoom = 1): number {
  const zoomedFrameWidth = PREVIEW_FRAME_WIDTH * zoom;

  const frames = units / zoomedFrameWidth;

  return frames * FRAME_INTERVAL;
}

export function calculateTimelineWidth(
  totalLengthMs: number,
  zoom = 1
): number {
  return timeMsToUnits(totalLengthMs, zoom);
}