@remotion/studio 4.0.444 → 4.0.445
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Canvas.js +197 -42
- package/dist/components/Timeline/Timeline.js +8 -5
- package/dist/components/Timeline/TimelinePinchZoom.d.ts +2 -0
- package/dist/components/Timeline/TimelinePinchZoom.js +240 -0
- package/dist/components/Timeline/TimelineSlider.js +22 -8
- package/dist/components/Timeline/TimelineZoomControls.js +6 -3
- package/dist/components/Timeline/timeline-scroll-logic.d.ts +13 -1
- package/dist/components/Timeline/timeline-scroll-logic.js +20 -6
- package/dist/esm/{chunk-1zvzzrkf.js → chunk-bqd9dhnk.js} +1991 -1539
- package/dist/esm/internals.mjs +1991 -1539
- package/dist/esm/previewEntry.mjs +1948 -1496
- package/dist/esm/renderEntry.mjs +1 -1
- package/dist/helpers/get-effective-translation.d.ts +13 -1
- package/dist/helpers/get-effective-translation.js +45 -1
- package/dist/state/timeline-zoom.d.ts +5 -1
- package/dist/state/timeline-zoom.js +21 -16
- package/package.json +9 -9
|
@@ -21,13 +21,14 @@ const use_is_ruler_visible_1 = require("./EditorRuler/use-is-ruler-visible");
|
|
|
21
21
|
const layout_1 = require("./layout");
|
|
22
22
|
const Preview_1 = require("./Preview");
|
|
23
23
|
const ResetZoomButton_1 = require("./ResetZoomButton");
|
|
24
|
-
const
|
|
24
|
+
const getContainerStyle = (editorZoomGestures) => ({
|
|
25
25
|
flex: 1,
|
|
26
26
|
display: 'flex',
|
|
27
27
|
overflow: 'hidden',
|
|
28
28
|
position: 'relative',
|
|
29
29
|
backgroundColor: colors_1.BACKGROUND,
|
|
30
|
-
}
|
|
30
|
+
...(editorZoomGestures ? { touchAction: 'none' } : {}),
|
|
31
|
+
});
|
|
31
32
|
const resetZoom = {
|
|
32
33
|
position: 'absolute',
|
|
33
34
|
top: layout_1.SPACING_UNIT * 2,
|
|
@@ -37,6 +38,14 @@ const ZOOM_PX_FACTOR = 0.003;
|
|
|
37
38
|
const Canvas = ({ canvasContent, size }) => {
|
|
38
39
|
const { setSize, size: previewSize } = (0, react_1.useContext)(remotion_1.Internals.PreviewSizeContext);
|
|
39
40
|
const { editorZoomGestures } = (0, react_1.useContext)(editor_zoom_gestures_1.EditorZoomGesturesContext);
|
|
41
|
+
const previewSnapshotRef = (0, react_1.useRef)({
|
|
42
|
+
previewSize,
|
|
43
|
+
canvasSize: size,
|
|
44
|
+
contentDimensions: null,
|
|
45
|
+
});
|
|
46
|
+
const pinchBaseZoomRef = (0, react_1.useRef)(null);
|
|
47
|
+
const suppressWheelFromWebKitPinchRef = (0, react_1.useRef)(false);
|
|
48
|
+
const touchPinchRef = (0, react_1.useRef)(null);
|
|
40
49
|
const keybindings = (0, use_keybinding_1.useKeybinding)();
|
|
41
50
|
const config = remotion_1.Internals.useUnsafeVideoConfig();
|
|
42
51
|
const areRulersVisible = (0, use_is_ruler_visible_1.useIsRulerVisible)();
|
|
@@ -56,7 +65,13 @@ const Canvas = ({ canvasContent, size }) => {
|
|
|
56
65
|
return null;
|
|
57
66
|
}, [assetResolution, config, canvasContent]);
|
|
58
67
|
const isFit = previewSize.size === 'auto';
|
|
68
|
+
previewSnapshotRef.current = {
|
|
69
|
+
previewSize,
|
|
70
|
+
canvasSize: size,
|
|
71
|
+
contentDimensions,
|
|
72
|
+
};
|
|
59
73
|
const onWheel = (0, react_1.useCallback)((e) => {
|
|
74
|
+
const ev = e;
|
|
60
75
|
if (!editorZoomGestures) {
|
|
61
76
|
return;
|
|
62
77
|
}
|
|
@@ -66,11 +81,15 @@ const Canvas = ({ canvasContent, size }) => {
|
|
|
66
81
|
if (!contentDimensions || contentDimensions === 'none') {
|
|
67
82
|
return;
|
|
68
83
|
}
|
|
69
|
-
const wantsToZoom =
|
|
84
|
+
const wantsToZoom = ev.ctrlKey || ev.metaKey;
|
|
70
85
|
if (!wantsToZoom && isFit) {
|
|
71
86
|
return;
|
|
72
87
|
}
|
|
73
|
-
|
|
88
|
+
if (suppressWheelFromWebKitPinchRef.current && wantsToZoom) {
|
|
89
|
+
ev.preventDefault();
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
ev.preventDefault();
|
|
74
93
|
setSize((prevSize) => {
|
|
75
94
|
const scale = remotion_1.Internals.calculateScale({
|
|
76
95
|
canvasSize: size,
|
|
@@ -78,41 +97,20 @@ const Canvas = ({ canvasContent, size }) => {
|
|
|
78
97
|
compositionWidth: contentDimensions.width,
|
|
79
98
|
previewSize: prevSize.size,
|
|
80
99
|
});
|
|
81
|
-
// Zoom in/out
|
|
82
100
|
if (wantsToZoom) {
|
|
83
101
|
const oldSize = prevSize.size === 'auto' ? scale : prevSize.size;
|
|
84
102
|
const smoothened = (0, smooth_zoom_1.smoothenZoom)(oldSize);
|
|
85
|
-
const added = smoothened +
|
|
103
|
+
const added = smoothened + ev.deltaY * ZOOM_PX_FACTOR;
|
|
86
104
|
const unsmoothened = (0, smooth_zoom_1.unsmoothenZoom)(added);
|
|
87
|
-
|
|
88
|
-
size,
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
105
|
+
return (0, get_effective_translation_1.applyZoomAroundFocalPoint)({
|
|
106
|
+
canvasSize: size,
|
|
107
|
+
contentDimensions,
|
|
108
|
+
previewSizeBefore: prevSize,
|
|
109
|
+
oldNumericSize: oldSize,
|
|
110
|
+
newNumericSize: unsmoothened,
|
|
111
|
+
clientX: ev.clientX,
|
|
112
|
+
clientY: ev.clientY,
|
|
95
113
|
});
|
|
96
|
-
const zoomDifference = unsmoothened - oldSize;
|
|
97
|
-
const uvCoordinatesX = centerX / contentDimensions.width;
|
|
98
|
-
const uvCoordinatesY = centerY / contentDimensions.height;
|
|
99
|
-
const correctionLeft = -uvCoordinatesX * (zoomDifference * contentDimensions.width) +
|
|
100
|
-
(1 - uvCoordinatesX) * zoomDifference * contentDimensions.width;
|
|
101
|
-
const correctionTop = -uvCoordinatesY * (zoomDifference * contentDimensions.height) +
|
|
102
|
-
(1 - uvCoordinatesY) * zoomDifference * contentDimensions.height;
|
|
103
|
-
return {
|
|
104
|
-
translation: (0, get_effective_translation_1.getEffectiveTranslation)({
|
|
105
|
-
translation: {
|
|
106
|
-
x: prevSize.translation.x - correctionLeft / 2,
|
|
107
|
-
y: prevSize.translation.y - correctionTop / 2,
|
|
108
|
-
},
|
|
109
|
-
canvasSize: size,
|
|
110
|
-
compositionHeight: contentDimensions.height,
|
|
111
|
-
compositionWidth: contentDimensions.width,
|
|
112
|
-
scale,
|
|
113
|
-
}),
|
|
114
|
-
size: unsmoothened,
|
|
115
|
-
};
|
|
116
114
|
}
|
|
117
115
|
const effectiveTranslation = (0, get_effective_translation_1.getEffectiveTranslation)({
|
|
118
116
|
translation: prevSize.translation,
|
|
@@ -121,13 +119,12 @@ const Canvas = ({ canvasContent, size }) => {
|
|
|
121
119
|
compositionWidth: contentDimensions.width,
|
|
122
120
|
scale,
|
|
123
121
|
});
|
|
124
|
-
// Pan
|
|
125
122
|
return {
|
|
126
123
|
...prevSize,
|
|
127
124
|
translation: (0, get_effective_translation_1.getEffectiveTranslation)({
|
|
128
125
|
translation: {
|
|
129
|
-
x: effectiveTranslation.x +
|
|
130
|
-
y: effectiveTranslation.y +
|
|
126
|
+
x: effectiveTranslation.x + ev.deltaX,
|
|
127
|
+
y: effectiveTranslation.y + ev.deltaY,
|
|
131
128
|
},
|
|
132
129
|
canvasSize: size,
|
|
133
130
|
compositionHeight: contentDimensions.height,
|
|
@@ -143,12 +140,170 @@ const Canvas = ({ canvasContent, size }) => {
|
|
|
143
140
|
return;
|
|
144
141
|
}
|
|
145
142
|
current.addEventListener('wheel', onWheel, { passive: false });
|
|
146
|
-
return () =>
|
|
147
|
-
|
|
148
|
-
|
|
143
|
+
return () => {
|
|
144
|
+
current.removeEventListener('wheel', onWheel);
|
|
145
|
+
};
|
|
146
|
+
}, [onWheel]);
|
|
147
|
+
const supportsWebKitPinch = typeof window !== 'undefined' && 'GestureEvent' in window;
|
|
148
|
+
(0, react_1.useEffect)(() => {
|
|
149
|
+
const { current } = canvas_ref_1.canvasRef;
|
|
150
|
+
if (!current || !editorZoomGestures || !supportsWebKitPinch) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
const endWebKitPinch = () => {
|
|
154
|
+
pinchBaseZoomRef.current = null;
|
|
155
|
+
suppressWheelFromWebKitPinchRef.current = false;
|
|
156
|
+
};
|
|
157
|
+
const onGestureStart = (event) => {
|
|
158
|
+
const e = event;
|
|
159
|
+
const snap = previewSnapshotRef.current;
|
|
160
|
+
const canvasSz = snap.canvasSize;
|
|
161
|
+
const cdim = snap.contentDimensions;
|
|
162
|
+
if (!canvasSz || !cdim || cdim === 'none') {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
e.preventDefault();
|
|
166
|
+
suppressWheelFromWebKitPinchRef.current = true;
|
|
167
|
+
const fitted = remotion_1.Internals.calculateScale({
|
|
168
|
+
canvasSize: canvasSz,
|
|
169
|
+
compositionHeight: cdim.height,
|
|
170
|
+
compositionWidth: cdim.width,
|
|
171
|
+
previewSize: snap.previewSize.size,
|
|
172
|
+
});
|
|
173
|
+
pinchBaseZoomRef.current =
|
|
174
|
+
snap.previewSize.size === 'auto' ? fitted : snap.previewSize.size;
|
|
175
|
+
};
|
|
176
|
+
const onGestureChange = (event) => {
|
|
177
|
+
const e = event;
|
|
178
|
+
const base = pinchBaseZoomRef.current;
|
|
179
|
+
const snap = previewSnapshotRef.current;
|
|
180
|
+
const canvasSz = snap.canvasSize;
|
|
181
|
+
const cdim = snap.contentDimensions;
|
|
182
|
+
if (base === null || !canvasSz || !cdim || cdim === 'none') {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
const dimensions = cdim;
|
|
186
|
+
e.preventDefault();
|
|
187
|
+
setSize((prevSize) => {
|
|
188
|
+
const scale = remotion_1.Internals.calculateScale({
|
|
189
|
+
canvasSize: canvasSz,
|
|
190
|
+
compositionHeight: dimensions.height,
|
|
191
|
+
compositionWidth: dimensions.width,
|
|
192
|
+
previewSize: prevSize.size,
|
|
193
|
+
});
|
|
194
|
+
const oldNumeric = prevSize.size === 'auto' ? scale : prevSize.size;
|
|
195
|
+
return (0, get_effective_translation_1.applyZoomAroundFocalPoint)({
|
|
196
|
+
canvasSize: canvasSz,
|
|
197
|
+
contentDimensions: dimensions,
|
|
198
|
+
previewSizeBefore: prevSize,
|
|
199
|
+
oldNumericSize: oldNumeric,
|
|
200
|
+
newNumericSize: base * e.scale,
|
|
201
|
+
clientX: e.clientX,
|
|
202
|
+
clientY: e.clientY,
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
};
|
|
206
|
+
const onGestureEnd = () => {
|
|
207
|
+
endWebKitPinch();
|
|
208
|
+
};
|
|
209
|
+
current.addEventListener('gesturestart', onGestureStart, {
|
|
149
210
|
passive: false,
|
|
150
211
|
});
|
|
151
|
-
|
|
212
|
+
current.addEventListener('gesturechange', onGestureChange, {
|
|
213
|
+
passive: false,
|
|
214
|
+
});
|
|
215
|
+
current.addEventListener('gestureend', onGestureEnd);
|
|
216
|
+
current.addEventListener('gesturecancel', onGestureEnd);
|
|
217
|
+
return () => {
|
|
218
|
+
current.removeEventListener('gesturestart', onGestureStart);
|
|
219
|
+
current.removeEventListener('gesturechange', onGestureChange);
|
|
220
|
+
current.removeEventListener('gestureend', onGestureEnd);
|
|
221
|
+
current.removeEventListener('gesturecancel', onGestureEnd);
|
|
222
|
+
};
|
|
223
|
+
}, [editorZoomGestures, setSize, supportsWebKitPinch]);
|
|
224
|
+
(0, react_1.useEffect)(() => {
|
|
225
|
+
const { current } = canvas_ref_1.canvasRef;
|
|
226
|
+
if (!current || !editorZoomGestures) {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
const onTouchStart = (event) => {
|
|
230
|
+
if (event.touches.length !== 2) {
|
|
231
|
+
touchPinchRef.current = null;
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
const snap = previewSnapshotRef.current;
|
|
235
|
+
if (!snap.canvasSize ||
|
|
236
|
+
!snap.contentDimensions ||
|
|
237
|
+
snap.contentDimensions === 'none') {
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
const [t0, t1] = [event.touches[0], event.touches[1]];
|
|
241
|
+
const initialDistance = Math.hypot(t1.clientX - t0.clientX, t1.clientY - t0.clientY);
|
|
242
|
+
if (initialDistance < 1e-6) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
const fitted = remotion_1.Internals.calculateScale({
|
|
246
|
+
canvasSize: snap.canvasSize,
|
|
247
|
+
compositionHeight: snap.contentDimensions.height,
|
|
248
|
+
compositionWidth: snap.contentDimensions.width,
|
|
249
|
+
previewSize: snap.previewSize.size,
|
|
250
|
+
});
|
|
251
|
+
const initialZoom = snap.previewSize.size === 'auto' ? fitted : snap.previewSize.size;
|
|
252
|
+
touchPinchRef.current = { initialDistance, initialZoom };
|
|
253
|
+
};
|
|
254
|
+
const onTouchMove = (event) => {
|
|
255
|
+
const pinch = touchPinchRef.current;
|
|
256
|
+
const snap = previewSnapshotRef.current;
|
|
257
|
+
if (pinch === null ||
|
|
258
|
+
event.touches.length !== 2 ||
|
|
259
|
+
!snap.canvasSize ||
|
|
260
|
+
!snap.contentDimensions ||
|
|
261
|
+
snap.contentDimensions === 'none') {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
event.preventDefault();
|
|
265
|
+
const [t0, t1] = [event.touches[0], event.touches[1]];
|
|
266
|
+
const dist = Math.hypot(t1.clientX - t0.clientX, t1.clientY - t0.clientY);
|
|
267
|
+
const ratio = dist / pinch.initialDistance;
|
|
268
|
+
const clientX = (t0.clientX + t1.clientX) / 2;
|
|
269
|
+
const clientY = (t0.clientY + t1.clientY) / 2;
|
|
270
|
+
setSize((prevSize) => {
|
|
271
|
+
const canvasSz = snap.canvasSize;
|
|
272
|
+
const cdim = snap.contentDimensions;
|
|
273
|
+
const scale = remotion_1.Internals.calculateScale({
|
|
274
|
+
canvasSize: canvasSz,
|
|
275
|
+
compositionHeight: cdim.height,
|
|
276
|
+
compositionWidth: cdim.width,
|
|
277
|
+
previewSize: prevSize.size,
|
|
278
|
+
});
|
|
279
|
+
const oldNumeric = prevSize.size === 'auto' ? scale : prevSize.size;
|
|
280
|
+
return (0, get_effective_translation_1.applyZoomAroundFocalPoint)({
|
|
281
|
+
canvasSize: canvasSz,
|
|
282
|
+
contentDimensions: cdim,
|
|
283
|
+
previewSizeBefore: prevSize,
|
|
284
|
+
oldNumericSize: oldNumeric,
|
|
285
|
+
newNumericSize: pinch.initialZoom * ratio,
|
|
286
|
+
clientX,
|
|
287
|
+
clientY,
|
|
288
|
+
});
|
|
289
|
+
});
|
|
290
|
+
};
|
|
291
|
+
const onTouchEnd = (event) => {
|
|
292
|
+
if (event.touches.length < 2) {
|
|
293
|
+
touchPinchRef.current = null;
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
current.addEventListener('touchstart', onTouchStart, { passive: true });
|
|
297
|
+
current.addEventListener('touchmove', onTouchMove, { passive: false });
|
|
298
|
+
current.addEventListener('touchend', onTouchEnd);
|
|
299
|
+
current.addEventListener('touchcancel', onTouchEnd);
|
|
300
|
+
return () => {
|
|
301
|
+
current.removeEventListener('touchstart', onTouchStart);
|
|
302
|
+
current.removeEventListener('touchmove', onTouchMove);
|
|
303
|
+
current.removeEventListener('touchend', onTouchEnd);
|
|
304
|
+
current.removeEventListener('touchcancel', onTouchEnd);
|
|
305
|
+
};
|
|
306
|
+
}, [editorZoomGestures, setSize]);
|
|
152
307
|
const onReset = (0, react_1.useCallback)(() => {
|
|
153
308
|
setSize(() => {
|
|
154
309
|
return {
|
|
@@ -263,6 +418,6 @@ const Canvas = ({ canvasContent, size }) => {
|
|
|
263
418
|
fetchMetadata();
|
|
264
419
|
}, [fetchMetadata]);
|
|
265
420
|
return (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
|
|
266
|
-
jsx_runtime_1.jsxs("div", { ref: canvas_ref_1.canvasRef, style:
|
|
421
|
+
jsx_runtime_1.jsxs("div", { ref: canvas_ref_1.canvasRef, style: getContainerStyle(editorZoomGestures), children: [size ? (jsx_runtime_1.jsx(Preview_1.VideoPreview, { canvasContent: canvasContent, contentDimensions: contentDimensions, canvasSize: size, assetMetadata: assetResolution })) : null, isFit ? null : (jsx_runtime_1.jsx("div", { style: resetZoom, className: "css-reset", children: jsx_runtime_1.jsx(ResetZoomButton_1.ResetZoomButton, { onClick: onReset }) })), editorShowGuides && canvasContent.type === 'composition' && (jsx_runtime_1.jsx(EditorGuides_1.default, { canvasSize: size, contentDimensions: contentDimensions, assetMetadata: assetResolution }))] }), areRulersVisible && (jsx_runtime_1.jsx(EditorRuler_1.EditorRulers, { contentDimensions: contentDimensions, canvasSize: size, assetMetadata: assetResolution, containerRef: canvas_ref_1.canvasRef }))] }));
|
|
267
422
|
};
|
|
268
423
|
exports.Canvas = Canvas;
|
|
@@ -52,6 +52,7 @@ const timeline_refs_1 = require("./timeline-refs");
|
|
|
52
52
|
const TimelineDragHandler_1 = require("./TimelineDragHandler");
|
|
53
53
|
const TimelineInOutPointer_1 = require("./TimelineInOutPointer");
|
|
54
54
|
const TimelineList_1 = require("./TimelineList");
|
|
55
|
+
const TimelinePinchZoom_1 = require("./TimelinePinchZoom");
|
|
55
56
|
const TimelinePlayCursorSyncer_1 = require("./TimelinePlayCursorSyncer");
|
|
56
57
|
const TimelineScrollable_1 = require("./TimelineScrollable");
|
|
57
58
|
const TimelineSlider_1 = require("./TimelineSlider");
|
|
@@ -116,10 +117,12 @@ const TimelineInner = () => {
|
|
|
116
117
|
overflowX: 'hidden',
|
|
117
118
|
};
|
|
118
119
|
}, [hasBeenCut, shown, expandedTracks, visualModeEnabled]);
|
|
119
|
-
return (jsx_runtime_1.jsx("div", { ref: timeline_refs_1.timelineVerticalScroll, style: container, className: 'css-reset ' + is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: jsx_runtime_1.
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
120
|
+
return (jsx_runtime_1.jsx("div", { ref: timeline_refs_1.timelineVerticalScroll, style: container, className: 'css-reset ' + is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: jsx_runtime_1.jsxs(TimelineWidthProvider_1.TimelineWidthProvider, { children: [
|
|
121
|
+
jsx_runtime_1.jsx(TimelinePinchZoom_1.TimelinePinchZoom, {}), jsx_runtime_1.jsx("div", { style: inner, children: jsx_runtime_1.jsxs(SplitterContainer_1.SplitterContainer, { orientation: "vertical", defaultFlex: 0.2, id: "names-to-timeline", maxFlex: 0.5, minFlex: 0.15, children: [
|
|
122
|
+
jsx_runtime_1.jsx(SplitterElement_1.SplitterElement, { type: "flexer", sticky: jsx_runtime_1.jsx(TimelineTimeIndicators_1.TimelineTimePlaceholders, {}), children: jsx_runtime_1.jsx(TimelineList_1.TimelineList, { timeline: shown }) }), jsx_runtime_1.jsx(SplitterHandle_1.SplitterHandle, { onCollapse: noop, allowToCollapse: "none" }), jsx_runtime_1.jsx(SplitterElement_1.SplitterElement, { type: "anti-flexer", sticky: null, children: jsx_runtime_1.jsxs(TimelineScrollable_1.TimelineScrollable, { children: [
|
|
123
|
+
jsx_runtime_1.jsx(TimelineTracks_1.TimelineTracks, { timeline: shown, hasBeenCut: hasBeenCut }), jsx_runtime_1.jsx(TimelineInOutPointer_1.TimelineInOutPointer, {}), jsx_runtime_1.jsx(TimelinePlayCursorSyncer_1.TimelinePlayCursorSyncer, {}), jsx_runtime_1.jsx(TimelineDragHandler_1.TimelineDragHandler, {}), jsx_runtime_1.jsx(TimelineTimeIndicators_1.TimelineTimeIndicators, {}), jsx_runtime_1.jsx(TimelineSlider_1.TimelineSlider, {})
|
|
124
|
+
] }) })
|
|
125
|
+
] }) })
|
|
126
|
+
] }) }));
|
|
124
127
|
};
|
|
125
128
|
exports.Timeline = react_1.default.memo(TimelineInner);
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TimelinePinchZoom = void 0;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
const remotion_1 = require("remotion");
|
|
6
|
+
const is_current_selected_still_1 = require("../../helpers/is-current-selected-still");
|
|
7
|
+
const editor_zoom_gestures_1 = require("../../state/editor-zoom-gestures");
|
|
8
|
+
const timeline_zoom_1 = require("../../state/timeline-zoom");
|
|
9
|
+
const timeline_refs_1 = require("./timeline-refs");
|
|
10
|
+
const timeline_scroll_logic_1 = require("./timeline-scroll-logic");
|
|
11
|
+
/**
|
|
12
|
+
* Maps wheel deltaY to zoom delta. Must be large enough that typical ctrl+wheel
|
|
13
|
+
* pinch steps change `TimelineZoomCtx` zoom by at least one 0.1 step after
|
|
14
|
+
* `Math.round(z * 10) / 10` in `timeline-zoom.tsx` (0.005 was too small).
|
|
15
|
+
*/
|
|
16
|
+
const ZOOM_WHEEL_DELTA = 0.06;
|
|
17
|
+
const TimelinePinchZoom = () => {
|
|
18
|
+
const isVideoComposition = (0, is_current_selected_still_1.useIsVideoComposition)();
|
|
19
|
+
const videoConfig = remotion_1.Internals.useUnsafeVideoConfig();
|
|
20
|
+
const { canvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
|
|
21
|
+
const { zoom, setZoom } = (0, react_1.useContext)(timeline_zoom_1.TimelineZoomCtx);
|
|
22
|
+
const { editorZoomGestures } = (0, react_1.useContext)(editor_zoom_gestures_1.EditorZoomGesturesContext);
|
|
23
|
+
const zoomRef = (0, react_1.useRef)(zoom);
|
|
24
|
+
zoomRef.current = zoom;
|
|
25
|
+
const pinchBaseZoomRef = (0, react_1.useRef)(null);
|
|
26
|
+
const suppressWheelFromWebKitPinchRef = (0, react_1.useRef)(false);
|
|
27
|
+
const touchPinchRef = (0, react_1.useRef)(null);
|
|
28
|
+
const onWheel = (0, react_1.useCallback)((e) => {
|
|
29
|
+
if (!editorZoomGestures || !isVideoComposition) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const { ctrlKey, metaKey, clientX, deltaY, deltaMode } = e;
|
|
33
|
+
const wantsToZoom = ctrlKey || metaKey;
|
|
34
|
+
if (!wantsToZoom) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (suppressWheelFromWebKitPinchRef.current && wantsToZoom) {
|
|
38
|
+
e.preventDefault();
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (!videoConfig || videoConfig.durationInFrames < 2) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (!canvasContent || canvasContent.type !== 'composition') {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const scrollEl = timeline_refs_1.scrollableRef.current;
|
|
48
|
+
if (!scrollEl) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
e.preventDefault();
|
|
52
|
+
const anchorContentX = (0, timeline_scroll_logic_1.viewportClientXToScrollContentX)({
|
|
53
|
+
clientX,
|
|
54
|
+
scrollEl,
|
|
55
|
+
});
|
|
56
|
+
let scaledDeltaY = deltaY;
|
|
57
|
+
if (deltaMode === WheelEvent.DOM_DELTA_LINE) {
|
|
58
|
+
scaledDeltaY *= 16;
|
|
59
|
+
}
|
|
60
|
+
else if (deltaMode === WheelEvent.DOM_DELTA_PAGE) {
|
|
61
|
+
scaledDeltaY *= scrollEl.clientHeight;
|
|
62
|
+
}
|
|
63
|
+
setZoom(canvasContent.compositionId, (z) => z - scaledDeltaY * ZOOM_WHEEL_DELTA, { anchorFrame: null, anchorContentX });
|
|
64
|
+
}, [
|
|
65
|
+
editorZoomGestures,
|
|
66
|
+
isVideoComposition,
|
|
67
|
+
videoConfig,
|
|
68
|
+
canvasContent,
|
|
69
|
+
setZoom,
|
|
70
|
+
]);
|
|
71
|
+
const supportsWebKitPinch = typeof window !== 'undefined' && 'GestureEvent' in window;
|
|
72
|
+
(0, react_1.useEffect)(() => {
|
|
73
|
+
const el = timeline_refs_1.timelineVerticalScroll.current;
|
|
74
|
+
if (!el) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
el.addEventListener('wheel', onWheel, { passive: false });
|
|
78
|
+
return () => {
|
|
79
|
+
el.removeEventListener('wheel', onWheel);
|
|
80
|
+
};
|
|
81
|
+
}, [onWheel]);
|
|
82
|
+
(0, react_1.useEffect)(() => {
|
|
83
|
+
const el = timeline_refs_1.timelineVerticalScroll.current;
|
|
84
|
+
if (!el || !editorZoomGestures || !supportsWebKitPinch) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const endWebKitPinch = () => {
|
|
88
|
+
pinchBaseZoomRef.current = null;
|
|
89
|
+
suppressWheelFromWebKitPinchRef.current = false;
|
|
90
|
+
};
|
|
91
|
+
const onGestureStart = (event) => {
|
|
92
|
+
var _a;
|
|
93
|
+
const e = event;
|
|
94
|
+
if (!isVideoComposition) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (!videoConfig || videoConfig.durationInFrames < 2) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (!canvasContent || canvasContent.type !== 'composition') {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const scrollEl = timeline_refs_1.scrollableRef.current;
|
|
104
|
+
if (!scrollEl) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
e.preventDefault();
|
|
108
|
+
suppressWheelFromWebKitPinchRef.current = true;
|
|
109
|
+
pinchBaseZoomRef.current = (_a = zoomRef.current[canvasContent.compositionId]) !== null && _a !== void 0 ? _a : timeline_zoom_1.TIMELINE_MIN_ZOOM;
|
|
110
|
+
};
|
|
111
|
+
const onGestureChange = (event) => {
|
|
112
|
+
const e = event;
|
|
113
|
+
const base = pinchBaseZoomRef.current;
|
|
114
|
+
if (base === null ||
|
|
115
|
+
!isVideoComposition ||
|
|
116
|
+
!videoConfig ||
|
|
117
|
+
videoConfig.durationInFrames < 2) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (!canvasContent || canvasContent.type !== 'composition') {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
const scrollEl = timeline_refs_1.scrollableRef.current;
|
|
124
|
+
if (!scrollEl) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
e.preventDefault();
|
|
128
|
+
const anchorContentX = (0, timeline_scroll_logic_1.viewportClientXToScrollContentX)({
|
|
129
|
+
clientX: e.clientX,
|
|
130
|
+
scrollEl,
|
|
131
|
+
});
|
|
132
|
+
setZoom(canvasContent.compositionId, () => base * e.scale, {
|
|
133
|
+
anchorFrame: null,
|
|
134
|
+
anchorContentX,
|
|
135
|
+
});
|
|
136
|
+
};
|
|
137
|
+
const onGestureEnd = () => {
|
|
138
|
+
endWebKitPinch();
|
|
139
|
+
};
|
|
140
|
+
el.addEventListener('gesturestart', onGestureStart, { passive: false });
|
|
141
|
+
el.addEventListener('gesturechange', onGestureChange, { passive: false });
|
|
142
|
+
el.addEventListener('gestureend', onGestureEnd);
|
|
143
|
+
el.addEventListener('gesturecancel', onGestureEnd);
|
|
144
|
+
return () => {
|
|
145
|
+
el.removeEventListener('gesturestart', onGestureStart);
|
|
146
|
+
el.removeEventListener('gesturechange', onGestureChange);
|
|
147
|
+
el.removeEventListener('gestureend', onGestureEnd);
|
|
148
|
+
el.removeEventListener('gesturecancel', onGestureEnd);
|
|
149
|
+
};
|
|
150
|
+
}, [
|
|
151
|
+
editorZoomGestures,
|
|
152
|
+
supportsWebKitPinch,
|
|
153
|
+
isVideoComposition,
|
|
154
|
+
videoConfig,
|
|
155
|
+
canvasContent,
|
|
156
|
+
setZoom,
|
|
157
|
+
]);
|
|
158
|
+
(0, react_1.useEffect)(() => {
|
|
159
|
+
const el = timeline_refs_1.timelineVerticalScroll.current;
|
|
160
|
+
if (!el || !editorZoomGestures) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
const onTouchStart = (event) => {
|
|
164
|
+
var _a;
|
|
165
|
+
if (event.touches.length !== 2) {
|
|
166
|
+
touchPinchRef.current = null;
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
if (!isVideoComposition ||
|
|
170
|
+
!videoConfig ||
|
|
171
|
+
videoConfig.durationInFrames < 2) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
if (!canvasContent || canvasContent.type !== 'composition') {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
const [t0, t1] = [event.touches[0], event.touches[1]];
|
|
178
|
+
const initialDistance = Math.hypot(t1.clientX - t0.clientX, t1.clientY - t0.clientY);
|
|
179
|
+
if (initialDistance < 1e-6) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
touchPinchRef.current = {
|
|
183
|
+
initialDistance,
|
|
184
|
+
initialZoom: (_a = zoomRef.current[canvasContent.compositionId]) !== null && _a !== void 0 ? _a : timeline_zoom_1.TIMELINE_MIN_ZOOM,
|
|
185
|
+
};
|
|
186
|
+
};
|
|
187
|
+
const onTouchMove = (event) => {
|
|
188
|
+
const pinch = touchPinchRef.current;
|
|
189
|
+
if (pinch === null ||
|
|
190
|
+
event.touches.length !== 2 ||
|
|
191
|
+
!videoConfig ||
|
|
192
|
+
videoConfig.durationInFrames < 2) {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
if (!canvasContent || canvasContent.type !== 'composition') {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const scrollEl = timeline_refs_1.scrollableRef.current;
|
|
199
|
+
if (!scrollEl) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
event.preventDefault();
|
|
203
|
+
const [t0, t1] = [event.touches[0], event.touches[1]];
|
|
204
|
+
const dist = Math.hypot(t1.clientX - t0.clientX, t1.clientY - t0.clientY);
|
|
205
|
+
const ratio = dist / pinch.initialDistance;
|
|
206
|
+
const clientX = (t0.clientX + t1.clientX) / 2;
|
|
207
|
+
const anchorContentX = (0, timeline_scroll_logic_1.viewportClientXToScrollContentX)({
|
|
208
|
+
clientX,
|
|
209
|
+
scrollEl,
|
|
210
|
+
});
|
|
211
|
+
setZoom(canvasContent.compositionId, () => pinch.initialZoom * ratio, {
|
|
212
|
+
anchorFrame: null,
|
|
213
|
+
anchorContentX,
|
|
214
|
+
});
|
|
215
|
+
};
|
|
216
|
+
const onTouchEnd = (event) => {
|
|
217
|
+
if (event.touches.length < 2) {
|
|
218
|
+
touchPinchRef.current = null;
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
el.addEventListener('touchstart', onTouchStart, { passive: true });
|
|
222
|
+
el.addEventListener('touchmove', onTouchMove, { passive: false });
|
|
223
|
+
el.addEventListener('touchend', onTouchEnd);
|
|
224
|
+
el.addEventListener('touchcancel', onTouchEnd);
|
|
225
|
+
return () => {
|
|
226
|
+
el.removeEventListener('touchstart', onTouchStart);
|
|
227
|
+
el.removeEventListener('touchmove', onTouchMove);
|
|
228
|
+
el.removeEventListener('touchend', onTouchEnd);
|
|
229
|
+
el.removeEventListener('touchcancel', onTouchEnd);
|
|
230
|
+
};
|
|
231
|
+
}, [
|
|
232
|
+
editorZoomGestures,
|
|
233
|
+
isVideoComposition,
|
|
234
|
+
videoConfig,
|
|
235
|
+
canvasContent,
|
|
236
|
+
setZoom,
|
|
237
|
+
]);
|
|
238
|
+
return null;
|
|
239
|
+
};
|
|
240
|
+
exports.TimelinePinchZoom = TimelinePinchZoom;
|
|
@@ -5,6 +5,7 @@ const jsx_runtime_1 = require("react/jsx-runtime");
|
|
|
5
5
|
const react_1 = require("react");
|
|
6
6
|
const remotion_1 = require("remotion");
|
|
7
7
|
const get_left_of_timeline_slider_1 = require("../../helpers/get-left-of-timeline-slider");
|
|
8
|
+
const timeline_zoom_1 = require("../../state/timeline-zoom");
|
|
8
9
|
const imperative_state_1 = require("./imperative-state");
|
|
9
10
|
const timeline_refs_1 = require("./timeline-refs");
|
|
10
11
|
const TimelineSliderHandle_1 = require("./TimelineSliderHandle");
|
|
@@ -32,20 +33,33 @@ const TimelineSlider = () => {
|
|
|
32
33
|
};
|
|
33
34
|
exports.TimelineSlider = TimelineSlider;
|
|
34
35
|
const Inner = () => {
|
|
36
|
+
var _a;
|
|
35
37
|
const videoConfig = (0, remotion_1.useVideoConfig)();
|
|
36
38
|
const timelinePosition = remotion_1.Internals.Timeline.useTimelinePosition();
|
|
37
39
|
const ref = (0, react_1.useRef)(null);
|
|
38
40
|
const timelineWidth = (0, react_1.useContext)(TimelineWidthProvider_1.TimelineWidthContext);
|
|
41
|
+
const { zoom: zoomMap } = (0, react_1.useContext)(timeline_zoom_1.TimelineZoomCtx);
|
|
42
|
+
const { canvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
|
|
39
43
|
if (timelineWidth === null) {
|
|
40
44
|
throw new Error('Unexpectedly did not have timeline width');
|
|
41
45
|
}
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
const zoomLevel = (canvasContent === null || canvasContent === void 0 ? void 0 : canvasContent.type) === 'composition'
|
|
47
|
+
? ((_a = zoomMap[canvasContent.compositionId]) !== null && _a !== void 0 ? _a : timeline_zoom_1.TIMELINE_MIN_ZOOM)
|
|
48
|
+
: timeline_zoom_1.TIMELINE_MIN_ZOOM;
|
|
49
|
+
(0, react_1.useLayoutEffect)(() => {
|
|
50
|
+
var _a;
|
|
51
|
+
const el = ref.current;
|
|
52
|
+
const measuredWidth = (_a = timeline_refs_1.sliderAreaRef.current) === null || _a === void 0 ? void 0 : _a.clientWidth;
|
|
53
|
+
if (!el || measuredWidth === undefined || measuredWidth === 0) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
el.style.transform = `translateX(${(0, get_left_of_timeline_slider_1.getXPositionOfItemInTimelineImperatively)(timelinePosition, videoConfig.durationInFrames, measuredWidth)}px)`;
|
|
57
|
+
}, [
|
|
58
|
+
timelinePosition,
|
|
59
|
+
videoConfig.durationInFrames,
|
|
60
|
+
timelineWidth,
|
|
61
|
+
zoomLevel,
|
|
62
|
+
]);
|
|
49
63
|
(0, react_1.useImperativeHandle)(exports.redrawTimelineSliderFast, () => {
|
|
50
64
|
return {
|
|
51
65
|
draw: (frame, width) => {
|
|
@@ -76,7 +90,7 @@ const Inner = () => {
|
|
|
76
90
|
current.removeEventListener('scroll', onScroll);
|
|
77
91
|
};
|
|
78
92
|
}, []);
|
|
79
|
-
return (jsx_runtime_1.jsxs("div", { ref: ref, style:
|
|
93
|
+
return (jsx_runtime_1.jsxs("div", { ref: ref, style: container, children: [
|
|
80
94
|
jsx_runtime_1.jsx("div", { style: line }), jsx_runtime_1.jsx(TimelineSliderHandle_1.TimelineSliderHandle, {})
|
|
81
95
|
] }));
|
|
82
96
|
};
|
|
@@ -33,19 +33,22 @@ const TimelineZoomControls = () => {
|
|
|
33
33
|
if (canvasContent === null || canvasContent.type !== 'composition') {
|
|
34
34
|
return;
|
|
35
35
|
}
|
|
36
|
-
setZoom(canvasContent.compositionId, (z) => Math.max(timeline_zoom_1.TIMELINE_MIN_ZOOM, z - 0.2));
|
|
36
|
+
setZoom(canvasContent.compositionId, (z) => Math.max(timeline_zoom_1.TIMELINE_MIN_ZOOM, z - 0.2), { anchorFrame: null, anchorContentX: null });
|
|
37
37
|
}, [canvasContent, setZoom]);
|
|
38
38
|
const onPlusClicked = (0, react_1.useCallback)(() => {
|
|
39
39
|
if (canvasContent === null || canvasContent.type !== 'composition') {
|
|
40
40
|
return;
|
|
41
41
|
}
|
|
42
|
-
setZoom(canvasContent.compositionId, (z) => Math.min(timeline_zoom_1.TIMELINE_MAX_ZOOM, z + 0.2));
|
|
42
|
+
setZoom(canvasContent.compositionId, (z) => Math.min(timeline_zoom_1.TIMELINE_MAX_ZOOM, z + 0.2), { anchorFrame: null, anchorContentX: null });
|
|
43
43
|
}, [canvasContent, setZoom]);
|
|
44
44
|
const onChange = (0, react_1.useCallback)((e) => {
|
|
45
45
|
if (canvasContent === null || canvasContent.type !== 'composition') {
|
|
46
46
|
return;
|
|
47
47
|
}
|
|
48
|
-
setZoom(canvasContent.compositionId, () => Number(e.target.value)
|
|
48
|
+
setZoom(canvasContent.compositionId, () => Number(e.target.value), {
|
|
49
|
+
anchorFrame: null,
|
|
50
|
+
anchorContentX: null,
|
|
51
|
+
});
|
|
49
52
|
}, [canvasContent, setZoom]);
|
|
50
53
|
const isStill = (0, is_current_selected_still_1.useIsStill)();
|
|
51
54
|
if (isStill ||
|