lexgui 8.1.2 → 8.2.1
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/build/components/AlertDialog.d.ts +7 -7
- package/build/components/Avatar.d.ts +15 -0
- package/build/components/Counter.d.ts +9 -9
- package/build/components/Dialog.d.ts +20 -20
- package/build/components/Footer.d.ts +14 -14
- package/build/components/Menubar.d.ts +59 -59
- package/build/components/NodeTree.d.ts +26 -1
- package/build/components/Vector.d.ts +1 -0
- package/build/core/Area.d.ts +143 -143
- package/build/core/Event.d.ts +0 -20
- package/build/core/Namespace.js +1 -1
- package/build/core/Namespace.js.map +1 -1
- package/build/core/Panel.d.ts +538 -538
- package/build/extensions/AssetView.d.ts +137 -136
- package/build/extensions/AssetView.js +193 -155
- package/build/extensions/AssetView.js.map +1 -1
- package/build/extensions/Audio.js +163 -163
- package/build/extensions/Audio.js.map +1 -1
- package/build/extensions/CodeEditor.d.ts +358 -350
- package/build/extensions/CodeEditor.js +302 -270
- package/build/extensions/CodeEditor.js.map +1 -1
- package/build/extensions/DocMaker.d.ts +27 -27
- package/build/extensions/DocMaker.js +15 -11
- package/build/extensions/DocMaker.js.map +1 -1
- package/build/extensions/GraphEditor.js +2754 -2760
- package/build/extensions/GraphEditor.js.map +1 -1
- package/build/extensions/ImUi.js +227 -227
- package/build/extensions/Timeline.d.ts +668 -670
- package/build/extensions/Timeline.js +71 -79
- package/build/extensions/Timeline.js.map +1 -1
- package/build/extensions/VideoEditor.d.ts +38 -16
- package/build/extensions/VideoEditor.js +294 -180
- package/build/extensions/VideoEditor.js.map +1 -1
- package/build/extensions/index.d.ts +8 -8
- package/build/extensions/index.js +10 -10
- package/build/index.all.d.ts +2 -2
- package/build/index.css.d.ts +3 -4
- package/build/index.d.ts +57 -56
- package/build/lexgui.all.js +1877 -1520
- package/build/lexgui.all.js.map +1 -1
- package/build/lexgui.all.min.js +1 -1
- package/build/lexgui.all.module.js +1875 -1516
- package/build/lexgui.all.module.js.map +1 -1
- package/build/lexgui.all.module.min.js +1 -1
- package/build/lexgui.css +6123 -5556
- package/build/lexgui.js +997 -814
- package/build/lexgui.js.map +1 -1
- package/build/lexgui.min.css +2 -3
- package/build/lexgui.min.js +1 -1
- package/build/lexgui.module.js +995 -810
- package/build/lexgui.module.js.map +1 -1
- package/build/lexgui.module.min.js +1 -1
- package/changelog.md +65 -2
- package/demo.js +167 -65
- package/examples/all-components.html +40 -55
- package/examples/asset-view.html +27 -0
- package/examples/code-editor.html +12 -1
- package/examples/dialogs.html +13 -2
- package/examples/editor.html +9 -49
- package/examples/index.html +2 -2
- package/examples/side-bar.html +1 -1
- package/examples/timeline.html +2 -2
- package/examples/video-editor.html +1 -1
- package/examples/video-editor2.html +2 -2
- package/package.json +7 -4
|
@@ -15,24 +15,29 @@ LX.Panel;
|
|
|
15
15
|
class TimeBar {
|
|
16
16
|
static TIMEBAR_PLAY = 1;
|
|
17
17
|
static TIMEBAR_TRIM = 2;
|
|
18
|
-
static BACKGROUND_COLOR = LX.
|
|
19
|
-
static COLOR = LX.
|
|
20
|
-
static ACTIVE_COLOR = '
|
|
18
|
+
static BACKGROUND_COLOR = LX.getCSSVariable('secondary');
|
|
19
|
+
static COLOR = LX.getCSSVariable('accent');
|
|
20
|
+
static ACTIVE_COLOR = LX.getCSSVariable('color-blue-400');
|
|
21
21
|
type = TimeBar.TIMEBAR_PLAY;
|
|
22
22
|
duration = 1.0;
|
|
23
23
|
canvas;
|
|
24
24
|
ctx;
|
|
25
|
+
options;
|
|
25
26
|
markerWidth = 8;
|
|
26
27
|
markerHeight;
|
|
27
28
|
offset;
|
|
28
29
|
lineWidth;
|
|
29
30
|
lineHeight;
|
|
30
|
-
|
|
31
|
+
linePosition;
|
|
31
32
|
startX;
|
|
32
33
|
endX;
|
|
33
34
|
currentX;
|
|
34
35
|
hovering;
|
|
35
36
|
dragging;
|
|
37
|
+
_onMouseUpListener;
|
|
38
|
+
_onMouseMoveListener;
|
|
39
|
+
_mouseDownCanvasRect = null;
|
|
40
|
+
updateTheme;
|
|
36
41
|
onChangeCurrent;
|
|
37
42
|
onChangeStart;
|
|
38
43
|
onChangeEnd;
|
|
@@ -40,46 +45,65 @@ class TimeBar {
|
|
|
40
45
|
onMouse;
|
|
41
46
|
constructor(area, type, options = {}) {
|
|
42
47
|
this.type = type ?? TimeBar.TIMEBAR_PLAY;
|
|
48
|
+
this.options = options ?? {};
|
|
43
49
|
this.duration = options.duration ?? this.duration;
|
|
44
50
|
// Create canvas
|
|
45
51
|
this.canvas = document.createElement('canvas');
|
|
52
|
+
this.canvas.style.borderRadius = '6px';
|
|
46
53
|
this.canvas.width = area.size[0];
|
|
47
54
|
this.canvas.height = area.size[1];
|
|
48
55
|
area.attach(this.canvas);
|
|
49
56
|
this.ctx = this.canvas.getContext('2d');
|
|
50
57
|
this.markerWidth = options.markerWidth ?? this.markerWidth;
|
|
51
|
-
this.markerHeight = options.markerHeight ??
|
|
52
|
-
|
|
58
|
+
this.markerHeight = (options.markerHeight ?? 0.5) * this.canvas.height;
|
|
59
|
+
const defaultOffset = this.markerWidth * 0.5 + 5;
|
|
60
|
+
if (typeof (options.offset) == 'number') {
|
|
61
|
+
this.offset = new vec2(options.offset, options.offset);
|
|
62
|
+
}
|
|
63
|
+
else if (Array.isArray(options.offset)) {
|
|
64
|
+
this.offset = new vec2(options.offset[0] ?? defaultOffset, options.offset[1] ?? defaultOffset);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
this.offset = new vec2(defaultOffset, defaultOffset);
|
|
68
|
+
}
|
|
53
69
|
// dimensions of line (not canvas)
|
|
54
|
-
this.lineWidth = this.canvas.width - this.offset * 2;
|
|
70
|
+
this.lineWidth = this.canvas.width - this.offset.x * 2;
|
|
55
71
|
this.lineHeight = options.barHeight ?? 5;
|
|
56
|
-
this.
|
|
57
|
-
this.startX = this.
|
|
58
|
-
this.endX = this.
|
|
72
|
+
this.linePosition = new vec2(this.offset.x, this.canvas.height * 0.5 - this.lineHeight * 0.5);
|
|
73
|
+
this.startX = this.linePosition.x;
|
|
74
|
+
this.endX = this.linePosition.x + this.lineWidth;
|
|
59
75
|
this.currentX = this.startX;
|
|
60
76
|
this._draw();
|
|
77
|
+
function updateTheme() {
|
|
78
|
+
TimeBar.BACKGROUND_COLOR = LX.getCSSVariable('secondary');
|
|
79
|
+
TimeBar.COLOR = LX.getCSSVariable('accent');
|
|
80
|
+
TimeBar.ACTIVE_COLOR = LX.getCSSVariable('color-blue-400');
|
|
81
|
+
}
|
|
82
|
+
this.updateTheme = updateTheme.bind(this);
|
|
83
|
+
LX.addSignal('@on_new_color_scheme', this.updateTheme);
|
|
61
84
|
this.updateTheme();
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
});
|
|
85
|
+
// prepare event listeners' functions
|
|
86
|
+
this._onMouseUpListener = this.onMouseUp.bind(this);
|
|
87
|
+
this._onMouseMoveListener = this.onMouseMove.bind(this);
|
|
66
88
|
this.canvas.onmousedown = (e) => this.onMouseDown(e);
|
|
67
|
-
this.canvas.onmousemove = (e) =>
|
|
68
|
-
|
|
89
|
+
this.canvas.onmousemove = (e) => {
|
|
90
|
+
if (this.dragging)
|
|
91
|
+
return; // already handled by _onMouseMoveListener
|
|
92
|
+
this.onMouseMove(e);
|
|
93
|
+
};
|
|
69
94
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
TimeBar.ACTIVE_COLOR = '#668ee4';
|
|
95
|
+
unbind() {
|
|
96
|
+
removeEventListener('mousemove', this._onMouseMoveListener);
|
|
97
|
+
removeEventListener('mouseup', this._onMouseUpListener);
|
|
74
98
|
}
|
|
75
99
|
setDuration(duration) {
|
|
76
100
|
this.duration = duration;
|
|
77
101
|
}
|
|
78
102
|
xToTime(x) {
|
|
79
|
-
return ((x - this.offset) / (this.lineWidth)) * this.duration;
|
|
103
|
+
return ((x - this.offset.x) / (this.lineWidth)) * this.duration;
|
|
80
104
|
}
|
|
81
105
|
timeToX(time) {
|
|
82
|
-
return (time / this.duration) * (this.lineWidth) + this.offset;
|
|
106
|
+
return (time / this.duration) * (this.lineWidth) + this.offset.x;
|
|
83
107
|
}
|
|
84
108
|
setCurrentTime(time) {
|
|
85
109
|
this.currentX = this.timeToX(time);
|
|
@@ -124,16 +148,15 @@ class TimeBar {
|
|
|
124
148
|
ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
|
|
125
149
|
// Draw background timeline
|
|
126
150
|
ctx.fillStyle = TimeBar.COLOR;
|
|
127
|
-
ctx.fillRect(this.
|
|
151
|
+
ctx.fillRect(this.linePosition.x, this.linePosition.y, this.lineWidth, this.lineHeight);
|
|
128
152
|
// Draw background trimed timeline
|
|
129
153
|
ctx.fillStyle = TimeBar.ACTIVE_COLOR;
|
|
130
|
-
ctx.fillRect(this.startX, this.
|
|
154
|
+
ctx.fillRect(this.startX, this.linePosition.y, this.endX - this.startX, this.lineHeight);
|
|
131
155
|
ctx.restore();
|
|
132
156
|
// Min-Max time markers
|
|
133
157
|
this._drawTrimMarker('start', this.startX, { color: null, fillColor: TimeBar.ACTIVE_COLOR || '#5f88c9' });
|
|
134
158
|
this._drawTrimMarker('end', this.endX, { color: null, fillColor: TimeBar.ACTIVE_COLOR || '#5f88c9' });
|
|
135
|
-
this._drawTimeMarker('current', this.currentX, { color: '#e5e5e5',
|
|
136
|
-
fillColor: TimeBar.ACTIVE_COLOR || '#5f88c9', width: this.markerWidth });
|
|
159
|
+
this._drawTimeMarker('current', this.currentX, { color: '#e5e5e5', fillColor: TimeBar.ACTIVE_COLOR || '#5f88c9', width: this.markerWidth });
|
|
137
160
|
if (this.onDraw) {
|
|
138
161
|
this.onDraw();
|
|
139
162
|
}
|
|
@@ -165,9 +188,9 @@ class TimeBar {
|
|
|
165
188
|
ctx.shadowBlur = 0;
|
|
166
189
|
}
|
|
167
190
|
_drawTimeMarker(name, x, options = {}) {
|
|
168
|
-
let y = this.offset;
|
|
191
|
+
let y = this.offset.y;
|
|
169
192
|
const w = options.width ? options.width : (this.dragging == name ? 6 : 4);
|
|
170
|
-
|
|
193
|
+
this.canvas.height - this.offset.y * 2;
|
|
171
194
|
let ctx = this.ctx;
|
|
172
195
|
if (!ctx)
|
|
173
196
|
return;
|
|
@@ -182,15 +205,14 @@ class TimeBar {
|
|
|
182
205
|
ctx.fillStyle = ctx.strokeStyle = 'white';
|
|
183
206
|
ctx.beginPath();
|
|
184
207
|
ctx.moveTo(x, y);
|
|
185
|
-
ctx.lineTo(x, y +
|
|
208
|
+
ctx.lineTo(x, this.linePosition.y + this.lineHeight * 0.5);
|
|
186
209
|
ctx.stroke();
|
|
187
210
|
ctx.closePath();
|
|
188
211
|
ctx.fillStyle = ctx.strokeStyle = options.fillColor || '#111'; // "#FFF";
|
|
189
|
-
y -= this.offset + 8;
|
|
190
212
|
// Current time ball grab
|
|
191
213
|
ctx.fillStyle = options.fillColor || '#e5e5e5';
|
|
192
214
|
ctx.beginPath();
|
|
193
|
-
ctx.roundRect(x - w * 0.5, y
|
|
215
|
+
ctx.roundRect(x - w * 0.5, y - w * 0.5, w, w, 5);
|
|
194
216
|
ctx.fill();
|
|
195
217
|
ctx.shadowBlur = 0;
|
|
196
218
|
}
|
|
@@ -212,13 +234,11 @@ class TimeBar {
|
|
|
212
234
|
const y = e.offsetY;
|
|
213
235
|
// Check if some marker is clicked
|
|
214
236
|
const threshold = this.markerWidth;
|
|
237
|
+
const startDist = Math.abs(this.startX - x);
|
|
238
|
+
const endDist = Math.abs(this.endX - x);
|
|
215
239
|
// grab trim markers only from the bottom
|
|
216
|
-
if (
|
|
217
|
-
this.dragging = 'start';
|
|
218
|
-
canvas.style.cursor = 'grabbing';
|
|
219
|
-
}
|
|
220
|
-
else if (Math.abs(this.endX - x) < threshold && this.position.y < y) {
|
|
221
|
-
this.dragging = 'end';
|
|
240
|
+
if ((startDist < threshold || endDist < threshold) && this.linePosition.y < y) {
|
|
241
|
+
this.dragging = (startDist < endDist || x < this.startX) ? 'start' : 'end';
|
|
222
242
|
canvas.style.cursor = 'grabbing';
|
|
223
243
|
}
|
|
224
244
|
else {
|
|
@@ -235,9 +255,14 @@ class TimeBar {
|
|
|
235
255
|
}
|
|
236
256
|
this.onSetCurrentValue(this.currentX);
|
|
237
257
|
}
|
|
258
|
+
this._mouseDownCanvasRect = canvas.getBoundingClientRect(); // cache this to avoid stalls during mousemove
|
|
259
|
+
window.addEventListener('mousemove', this._onMouseMoveListener);
|
|
260
|
+
window.addEventListener('mouseup', this._onMouseUpListener);
|
|
238
261
|
this._draw();
|
|
239
262
|
}
|
|
240
263
|
onMouseUp(e) {
|
|
264
|
+
window.removeEventListener('mousemove', this._onMouseMoveListener);
|
|
265
|
+
window.removeEventListener('mouseup', this._onMouseUpListener);
|
|
241
266
|
if (this.onMouse) {
|
|
242
267
|
this.onMouse(e);
|
|
243
268
|
}
|
|
@@ -260,17 +285,17 @@ class TimeBar {
|
|
|
260
285
|
e.preventDefault();
|
|
261
286
|
const canvas = this.canvas;
|
|
262
287
|
// Process mouse
|
|
263
|
-
const x = e.target == canvas ? e.offsetX : e.clientX -
|
|
264
|
-
e.target == canvas ? e.offsetY : e.clientY -
|
|
288
|
+
const x = e.target == canvas ? e.offsetX : (e.clientX - this._mouseDownCanvasRect.left);
|
|
289
|
+
e.target == canvas ? e.offsetY : (e.clientY - this._mouseDownCanvasRect.top);
|
|
265
290
|
if (this.dragging) {
|
|
266
291
|
switch (this.dragging) {
|
|
267
292
|
case 'start':
|
|
268
|
-
this.startX = Math.max(this.
|
|
293
|
+
this.startX = Math.max(this.linePosition.x, Math.min(this.endX, x));
|
|
269
294
|
this.currentX = this.startX;
|
|
270
295
|
this.onSetStartValue(this.startX);
|
|
271
296
|
break;
|
|
272
297
|
case 'end':
|
|
273
|
-
this.endX = Math.max(this.startX, Math.min(this.
|
|
298
|
+
this.endX = Math.max(this.startX, Math.min(this.linePosition.x + this.lineWidth, x));
|
|
274
299
|
this.currentX = this.endX;
|
|
275
300
|
this.onSetEndValue(this.endX);
|
|
276
301
|
break;
|
|
@@ -304,15 +329,18 @@ class TimeBar {
|
|
|
304
329
|
resize(size) {
|
|
305
330
|
this.canvas.width = Math.max(0, size[0]);
|
|
306
331
|
this.canvas.height = Math.max(0, size[1]);
|
|
307
|
-
|
|
332
|
+
this.markerHeight = (this.options.markerHeight ?? 0.5) * this.canvas.height;
|
|
333
|
+
let newWidth = size[0] - this.offset.x * 2;
|
|
308
334
|
newWidth = newWidth < 0.00001 ? 0.00001 : newWidth; // actual width of the line = canvas.width - offsetleft - offsetRight
|
|
309
|
-
const startRatio = (this.startX - this.offset) / this.lineWidth;
|
|
310
|
-
const currentRatio = (this.currentX - this.offset) / this.lineWidth;
|
|
311
|
-
const endRatio = (this.endX - this.offset) / this.lineWidth;
|
|
335
|
+
const startRatio = (this.startX - this.offset.x) / this.lineWidth;
|
|
336
|
+
const currentRatio = (this.currentX - this.offset.x) / this.lineWidth;
|
|
337
|
+
const endRatio = (this.endX - this.offset.x) / this.lineWidth;
|
|
312
338
|
this.lineWidth = newWidth;
|
|
313
|
-
this.
|
|
314
|
-
this.
|
|
315
|
-
this.
|
|
339
|
+
this.linePosition.x = this.offset.x;
|
|
340
|
+
this.linePosition.y = this.canvas.height * 0.5 - this.lineHeight * 0.5;
|
|
341
|
+
this.startX = Math.min(Math.max(newWidth * startRatio, 0), newWidth) + this.offset.x;
|
|
342
|
+
this.currentX = Math.min(Math.max(newWidth * currentRatio, 0), newWidth) + this.offset.x;
|
|
343
|
+
this.endX = Math.min(Math.max(newWidth * endRatio, 0), newWidth) + this.offset.x;
|
|
316
344
|
this._draw();
|
|
317
345
|
}
|
|
318
346
|
}
|
|
@@ -333,10 +361,7 @@ class VideoEditor {
|
|
|
333
361
|
playing = false;
|
|
334
362
|
videoReady = false;
|
|
335
363
|
controls = true;
|
|
336
|
-
startTimeString = '0:0';
|
|
337
|
-
endTimeString = '0:0';
|
|
338
364
|
speed = 1.0;
|
|
339
|
-
currentTime = 0.0;
|
|
340
365
|
startTime = 0.0;
|
|
341
366
|
endTime = 0.0;
|
|
342
367
|
requestId;
|
|
@@ -347,27 +372,29 @@ class VideoEditor {
|
|
|
347
372
|
crop = false;
|
|
348
373
|
dragOffsetX = 0.0;
|
|
349
374
|
dragOffsetY = 0.0;
|
|
350
|
-
|
|
351
|
-
timebar;
|
|
375
|
+
timebar = null;
|
|
352
376
|
mainArea;
|
|
353
377
|
cropArea; // HTMLElement with normCoord attribute;
|
|
378
|
+
videoArea;
|
|
354
379
|
controlsArea;
|
|
355
|
-
|
|
356
|
-
controlsPanelRight;
|
|
357
|
-
controlsCurrentPanel;
|
|
380
|
+
controlsComponents;
|
|
358
381
|
onChangeCurrent;
|
|
359
382
|
onChangeStart;
|
|
360
383
|
onChangeEnd;
|
|
361
384
|
onKeyUp;
|
|
362
385
|
onSetTime;
|
|
363
386
|
onVideoLoaded;
|
|
364
|
-
onCropArea;
|
|
365
387
|
onResize;
|
|
388
|
+
onCropArea;
|
|
366
389
|
onChangeSpeed;
|
|
390
|
+
onChangeState;
|
|
391
|
+
onChangeLoop;
|
|
367
392
|
_updateTime = true;
|
|
368
393
|
_onCropMouseUp;
|
|
369
394
|
_onCropMouseMove;
|
|
370
|
-
resize;
|
|
395
|
+
resize = null;
|
|
396
|
+
resizeControls = null;
|
|
397
|
+
resizeVideo = null;
|
|
371
398
|
constructor(area, options = {}) {
|
|
372
399
|
this.options = options ?? {};
|
|
373
400
|
this.speed = options.speed ?? this.speed;
|
|
@@ -379,8 +406,7 @@ class VideoEditor {
|
|
|
379
406
|
controlsArea = options.controlsArea;
|
|
380
407
|
}
|
|
381
408
|
else {
|
|
382
|
-
[videoArea, controlsArea] = area.split({ type: 'vertical', sizes: ['85%', null], minimizable: false,
|
|
383
|
-
resize: false });
|
|
409
|
+
[videoArea, controlsArea] = area.split({ type: 'vertical', sizes: ['85%', null], minimizable: false, resize: false });
|
|
384
410
|
}
|
|
385
411
|
controlsArea.root.classList.add('lexconstrolsarea');
|
|
386
412
|
this.cropArea = document.createElement('div');
|
|
@@ -401,7 +427,7 @@ class VideoEditor {
|
|
|
401
427
|
}
|
|
402
428
|
if (options.videoArea) {
|
|
403
429
|
options.videoArea.root.classList.add('lexvideoeditor');
|
|
404
|
-
options.videoArea.root.style.position =
|
|
430
|
+
options.videoArea.root.style.position = 'relative';
|
|
405
431
|
options.videoArea.attach(this.cropArea);
|
|
406
432
|
videoArea.attach(options.videoArea);
|
|
407
433
|
}
|
|
@@ -410,126 +436,43 @@ class VideoEditor {
|
|
|
410
436
|
videoArea.attach(this.cropArea);
|
|
411
437
|
videoArea.root.classList.add('lexvideoeditor');
|
|
412
438
|
}
|
|
413
|
-
videoArea.root.style.position =
|
|
439
|
+
videoArea.root.style.position = 'relative';
|
|
440
|
+
this.videoArea = videoArea;
|
|
414
441
|
this.controlsArea = controlsArea;
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
bottomArea.root.classList.add('lexbar');
|
|
425
|
-
this.controlsCurrentPanel = new LX.Panel({ className: 'lexcontrolspanel lextime' });
|
|
426
|
-
this.controlsCurrentPanel.refresh = () => {
|
|
427
|
-
this.controlsCurrentPanel.clear();
|
|
428
|
-
this.controlsCurrentPanel.addLabel(this.currentTimeString, { float: 'center' });
|
|
429
|
-
};
|
|
430
|
-
topArea.root.classList.add('lexflexarea');
|
|
431
|
-
topArea.attach(this.controlsCurrentPanel);
|
|
432
|
-
this.controlsCurrentPanel.refresh();
|
|
433
|
-
const style = getComputedStyle(bottomArea.root);
|
|
434
|
-
let padding = Number(style.getPropertyValue('padding').replace('px', ''));
|
|
435
|
-
this.timebar = new TimeBar(timeBarArea, TimeBar.TIMEBAR_TRIM, { offset: padding });
|
|
436
|
-
// Create controls panel (play/pause button and start time)
|
|
437
|
-
this.controlsPanelLeft = new LX.Panel({ className: 'lexcontrolspanel' });
|
|
438
|
-
this.controlsPanelLeft.refresh = () => {
|
|
439
|
-
this.controlsPanelLeft.clear();
|
|
440
|
-
this.controlsPanelLeft.sameLine();
|
|
441
|
-
let playbtn = this.controlsPanelLeft.addButton('Play', '', (v) => {
|
|
442
|
-
this.playing = v;
|
|
443
|
-
if (this.playing) {
|
|
444
|
-
if (this.video.currentTime + 0.000001 >= this.endTime) {
|
|
445
|
-
this.video.currentTime = this.startTime;
|
|
446
|
-
}
|
|
447
|
-
this.video.play();
|
|
448
|
-
}
|
|
449
|
-
else {
|
|
450
|
-
this.video.pause();
|
|
451
|
-
}
|
|
452
|
-
}, { width: '40px', icon: 'Play@solid', swap: 'Pause@solid', hideName: true,
|
|
453
|
-
className: 'justify-center' });
|
|
454
|
-
playbtn.setState(this.playing, true);
|
|
455
|
-
this.controlsPanelLeft.addButton('', '', (v, e) => {
|
|
456
|
-
const panel = new LX.Panel();
|
|
457
|
-
panel.addRange('Speed', this.speed, (v) => {
|
|
458
|
-
this.speed = v;
|
|
459
|
-
this.video.playbackRate = v;
|
|
460
|
-
if (this.onChangeSpeed) {
|
|
461
|
-
this.onChangeSpeed(v);
|
|
462
|
-
}
|
|
463
|
-
}, { min: 0, max: 2.5, step: 0.01, hideName: true });
|
|
464
|
-
new LX.Popover(e.target, [panel], { align: 'start', side: 'top', sideOffset: 12 });
|
|
465
|
-
}, { width: '40px', title: 'speed', icon: 'Timer@solid', className: 'justify-center' });
|
|
466
|
-
this.controlsPanelLeft.addButton('', 'Loop', (v) => {
|
|
467
|
-
this.loop = v;
|
|
468
|
-
}, { width: '40px', title: 'loop', icon: ('Repeat@solid'), className: `justify-center`, selectable: true,
|
|
469
|
-
selected: this.loop });
|
|
470
|
-
this.controlsPanelLeft.addLabel(this.startTimeString, { width: '100px' });
|
|
471
|
-
this.controlsPanelLeft.endLine();
|
|
472
|
-
let availableWidth = leftArea.root.clientWidth - controlsLeft.root.clientWidth;
|
|
473
|
-
this.timebar.resize([availableWidth, timeBarArea.root.clientHeight]);
|
|
442
|
+
this.controlsComponents = {
|
|
443
|
+
timebar: null,
|
|
444
|
+
playBtn: null,
|
|
445
|
+
speedBtn: null,
|
|
446
|
+
loopBtn: null,
|
|
447
|
+
trimStartText: null,
|
|
448
|
+
trimEndText: null,
|
|
449
|
+
curTimeText: null,
|
|
450
|
+
resetCropBtn: null
|
|
474
451
|
};
|
|
475
|
-
this.
|
|
476
|
-
|
|
477
|
-
// controlsLeft.root.classList.add();
|
|
478
|
-
controlsLeft.attach(this.controlsPanelLeft);
|
|
479
|
-
// Create right controls panel (ens time)
|
|
480
|
-
this.controlsPanelRight = new LX.Panel({ className: 'lexcontrolspanel' });
|
|
481
|
-
this.controlsPanelRight.refresh = () => {
|
|
482
|
-
this.controlsPanelRight.clear();
|
|
483
|
-
this.controlsPanelRight.addLabel(this.endTimeString, { width: 100 });
|
|
484
|
-
};
|
|
485
|
-
this.controlsPanelRight.refresh();
|
|
486
|
-
controlsRight.root.style.minWidth = 'fit-content';
|
|
487
|
-
controlsRight.attach(this.controlsPanelRight);
|
|
488
|
-
this.timebar.onChangeCurrent = this._setCurrentTime.bind(this);
|
|
489
|
-
this.timebar.onChangeStart = this._setStartTime.bind(this);
|
|
490
|
-
this.timebar.onChangeEnd = this._setEndTime.bind(this);
|
|
491
|
-
this.resize = () => {
|
|
492
|
-
bottomArea.setSize([this.controlsArea.root.clientWidth, 40]);
|
|
493
|
-
let availableWidth = this.controlsArea.root.clientWidth - controlsLeft.root.clientWidth
|
|
494
|
-
- controlsRight.root.clientWidth;
|
|
495
|
-
this.timebar.resize([availableWidth, timeBarArea.root.clientHeight]);
|
|
452
|
+
this.createControls();
|
|
453
|
+
this.resizeVideo = () => {
|
|
496
454
|
this.moveCropArea(this.cropArea.normCoords.x, this.cropArea.normCoords.y, true);
|
|
497
455
|
this.resizeCropArea(this.cropArea.normCoords.w, this.cropArea.normCoords.h, true);
|
|
498
456
|
if (this.onResize) {
|
|
499
457
|
this.onResize([videoArea.root.clientWidth, videoArea.root.clientHeight]);
|
|
500
458
|
}
|
|
501
459
|
};
|
|
460
|
+
this.resize = () => {
|
|
461
|
+
this.resizeVideo();
|
|
462
|
+
this.resizeControls();
|
|
463
|
+
};
|
|
502
464
|
area.onresize = this.resize.bind(this);
|
|
503
465
|
window.addEventListener('resize', area.onresize);
|
|
504
466
|
this.onKeyUp = (e) => {
|
|
505
467
|
if (this.controls && e.key == ' ') {
|
|
506
468
|
e.preventDefault();
|
|
507
469
|
e.stopPropagation();
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
if (this.video.currentTime + 0.000001 >= this.endTime) {
|
|
511
|
-
this.video.currentTime = this.startTime;
|
|
512
|
-
}
|
|
513
|
-
this.video.play();
|
|
514
|
-
}
|
|
515
|
-
else {
|
|
516
|
-
this.video.pause();
|
|
517
|
-
}
|
|
518
|
-
this.controlsPanelLeft.refresh();
|
|
470
|
+
// do not skip callback
|
|
471
|
+
this.controlsComponents.playBtn?.setState(!this.playing, false);
|
|
519
472
|
}
|
|
520
473
|
};
|
|
521
474
|
window.addEventListener('keyup', this.onKeyUp);
|
|
522
|
-
const parent = controlsArea.parentElement ? controlsArea.parentElement : controlsArea.root.parentElement;
|
|
523
|
-
// Add canvas event listeneres
|
|
524
|
-
parent.addEventListener('mousedown', (e) => {
|
|
525
|
-
// if( this.controls) {
|
|
526
|
-
// this.timebar.onMouseDown(e);
|
|
527
|
-
// }
|
|
528
|
-
});
|
|
529
475
|
this._onCropMouseUp = (event) => {
|
|
530
|
-
// if(this.controls) {
|
|
531
|
-
// this.timebar.onMouseUp(event);
|
|
532
|
-
// }
|
|
533
476
|
event.preventDefault();
|
|
534
477
|
event.stopPropagation();
|
|
535
478
|
if ((this.isDragging || this.isResizing) && this.onCropArea) {
|
|
@@ -541,9 +484,6 @@ class VideoEditor {
|
|
|
541
484
|
document.removeEventListener('mousemove', this._onCropMouseMove); // self destroy. Added during mouseDown on cropArea and handles
|
|
542
485
|
};
|
|
543
486
|
this._onCropMouseMove = (event) => {
|
|
544
|
-
// if(this.controls) {
|
|
545
|
-
// this.timebar.onMouseMove(event);
|
|
546
|
-
// }
|
|
547
487
|
window.getSelection()?.removeAllRanges();
|
|
548
488
|
event.preventDefault();
|
|
549
489
|
event.stopPropagation();
|
|
@@ -604,6 +544,182 @@ class VideoEditor {
|
|
|
604
544
|
this.onChangeStart = null;
|
|
605
545
|
this.onChangeEnd = null;
|
|
606
546
|
}
|
|
547
|
+
createControls(options = null) {
|
|
548
|
+
const controlsArea = this.controlsArea;
|
|
549
|
+
options = options ?? this.options;
|
|
550
|
+
// clear area. Signals are not cleared !!! (not a problem if there are no signals)
|
|
551
|
+
while (controlsArea.root.children.length) {
|
|
552
|
+
controlsArea.root.children[0].remove();
|
|
553
|
+
}
|
|
554
|
+
controlsArea.sections.length = 0;
|
|
555
|
+
// start trimming text
|
|
556
|
+
this.controlsComponents.trimStartText = new LX.TextInput(null, this.timeToString(this.startTime), null, { width: '100px',
|
|
557
|
+
title: 'Trimmed Start Time', disabled: true, inputClass: 'bg-none' });
|
|
558
|
+
this.controlsComponents.trimEndText = new LX.TextInput(null, this.timeToString(this.endTime), null, { width: '100px',
|
|
559
|
+
title: 'Trimmed End Time', disabled: true, inputClass: 'bg-none' });
|
|
560
|
+
this.controlsComponents.curTimeText = new LX.TextInput(null, this.video.currentTime, null, { title: 'Current Time', float: 'center',
|
|
561
|
+
disabled: true, inputClass: 'bg-none' });
|
|
562
|
+
// reset crop area
|
|
563
|
+
this.controlsComponents.resetCropBtn = new LX.Button('ResetCrop', null, (v) => {
|
|
564
|
+
this.moveCropArea(0, 0, true);
|
|
565
|
+
this.resizeCropArea(1, 1, true);
|
|
566
|
+
if (this.onCropArea) {
|
|
567
|
+
this.onCropArea(this.getCroppedArea());
|
|
568
|
+
}
|
|
569
|
+
}, { width: '40px', title: 'Reset Crop Area', icon: 'Crop@solid', hideName: true,
|
|
570
|
+
className: 'justify-center' + (this.crop ? '' : ' hidden') });
|
|
571
|
+
// play button
|
|
572
|
+
this.controlsComponents.playBtn = new LX.Button('Play', '', (v) => {
|
|
573
|
+
this.playing = v;
|
|
574
|
+
if (this.playing) {
|
|
575
|
+
if (this.video.currentTime + 0.000001 >= this.endTime) {
|
|
576
|
+
this.video.currentTime = this.startTime;
|
|
577
|
+
}
|
|
578
|
+
this.video.play();
|
|
579
|
+
}
|
|
580
|
+
else {
|
|
581
|
+
this.video.pause();
|
|
582
|
+
}
|
|
583
|
+
if (this.onChangeState) {
|
|
584
|
+
this.onChangeState(v);
|
|
585
|
+
}
|
|
586
|
+
}, { width: '40px', title: 'Play/Pause', icon: 'Play@solid', swap: 'Pause@solid', hideName: true, className: 'justify-center' });
|
|
587
|
+
this.controlsComponents.playBtn.setState(this.playing, true);
|
|
588
|
+
// speed button
|
|
589
|
+
this.controlsComponents.speedBtn = new LX.Button('Speed', '', (v, e) => {
|
|
590
|
+
const panel = new LX.Panel();
|
|
591
|
+
panel.addRange('Speed', this.speed, (v) => {
|
|
592
|
+
this.speed = v;
|
|
593
|
+
this.video.playbackRate = v;
|
|
594
|
+
if (this.onChangeSpeed) {
|
|
595
|
+
this.onChangeSpeed(v);
|
|
596
|
+
}
|
|
597
|
+
}, { min: 0, max: 2.5, step: 0.01, hideName: true });
|
|
598
|
+
new LX.Popover(e.target, [panel], { align: 'start', side: 'top', sideOffset: 12 });
|
|
599
|
+
}, { width: '40px', title: 'Speed', hideName: true, icon: 'Timer@solid', className: 'justify-center' });
|
|
600
|
+
// loop button
|
|
601
|
+
this.controlsComponents.loopBtn = new LX.Button('', 'Loop', (v) => {
|
|
602
|
+
this.loop = v;
|
|
603
|
+
if (this.onChangeLoop) {
|
|
604
|
+
this.onChangeLoop(v);
|
|
605
|
+
}
|
|
606
|
+
}, { width: '40px', hideName: true, title: 'Loop', icon: 'Repeat@solid', className: `justify-center`, selectable: true,
|
|
607
|
+
selected: this.loop });
|
|
608
|
+
let timeBarArea = null;
|
|
609
|
+
if (typeof (options.controlsLayout) == 'function') {
|
|
610
|
+
timeBarArea = options.controlsLayout;
|
|
611
|
+
}
|
|
612
|
+
else if (options.controlsLayout == 1) {
|
|
613
|
+
timeBarArea = this._createControlsLayout_1();
|
|
614
|
+
}
|
|
615
|
+
else {
|
|
616
|
+
timeBarArea = this._createControlsLayout_0();
|
|
617
|
+
}
|
|
618
|
+
if (this.timebar) {
|
|
619
|
+
this.timebar.unbind();
|
|
620
|
+
}
|
|
621
|
+
this.timebar = this.controlsComponents.timebar = new TimeBar(timeBarArea, TimeBar.TIMEBAR_TRIM, { offset: [12, null] });
|
|
622
|
+
this.timebar.onChangeCurrent = this._setCurrentTime.bind(this);
|
|
623
|
+
this.timebar.onChangeStart = this._setStartTime.bind(this);
|
|
624
|
+
this.timebar.onChangeEnd = this._setEndTime.bind(this);
|
|
625
|
+
let duration = 1;
|
|
626
|
+
if (this.video.duration !== Infinity && !isNaN(this.video.duration)) {
|
|
627
|
+
duration = this.video.duration;
|
|
628
|
+
}
|
|
629
|
+
this.timebar.setDuration(duration);
|
|
630
|
+
this.timebar.setEndTime(this.endTime);
|
|
631
|
+
this.timebar.setStartTime(this.startTime);
|
|
632
|
+
this.timebar.setCurrentTime(this.startTime);
|
|
633
|
+
this.resizeControls();
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* Creates the areas where components will be.
|
|
637
|
+
* Attaches all (desired) components of controlsComponents except the timebar
|
|
638
|
+
* @returns {Area} for the timebar
|
|
639
|
+
* Layout:
|
|
640
|
+
* |--------------------------timebar--------------------------|
|
|
641
|
+
* play speed loop resetCrop curTime trimStart / trimEnd
|
|
642
|
+
*/
|
|
643
|
+
_createControlsLayout_1() {
|
|
644
|
+
const controlsArea = this.controlsArea;
|
|
645
|
+
// Create playing timeline area and attach panels
|
|
646
|
+
let [timeBarArea, bottomArea] = controlsArea.split({ type: 'vertical', sizes: ['50%', null], minimizable: false, resize: false });
|
|
647
|
+
bottomArea.root.classList.add('relative');
|
|
648
|
+
let separator = document.createElement('p');
|
|
649
|
+
separator.style.alignContent = 'center';
|
|
650
|
+
separator.innerText = '/';
|
|
651
|
+
let trimDiv = LX.makeContainer(['fit-content', '100%'], 'relative flex flex-row pb-2', null, bottomArea, { float: 'right' });
|
|
652
|
+
trimDiv.appendChild(this.controlsComponents.trimStartText.root);
|
|
653
|
+
trimDiv.appendChild(separator);
|
|
654
|
+
trimDiv.appendChild(this.controlsComponents.trimEndText.root);
|
|
655
|
+
this.controlsComponents.trimStartText.root.querySelector('input').classList.add('text-end');
|
|
656
|
+
this.controlsComponents.trimStartText.root.classList.add('top-0', 'bottom-0');
|
|
657
|
+
this.controlsComponents.trimEndText.root.classList.add('top-0', 'bottom-0');
|
|
658
|
+
// current time
|
|
659
|
+
let curTimeDiv = LX.makeContainer(['100%', '100%'], 'absolute top-0 left-0 flex flex-row justify-center items-center pb-2', null, bottomArea, {});
|
|
660
|
+
curTimeDiv.appendChild(this.controlsComponents.curTimeText.root);
|
|
661
|
+
// Buttons
|
|
662
|
+
const buttonsPanel = bottomArea.addPanel({ className: 'absolute top-0 left-0 flex flex-row pl-4 pr-4 pt-1 pb-2' });
|
|
663
|
+
buttonsPanel.root.classList.remove('pad-md');
|
|
664
|
+
buttonsPanel._attachComponent(this.controlsComponents.playBtn);
|
|
665
|
+
buttonsPanel._attachComponent(this.controlsComponents.speedBtn);
|
|
666
|
+
buttonsPanel._attachComponent(this.controlsComponents.loopBtn);
|
|
667
|
+
buttonsPanel._attachComponent(this.controlsComponents.resetCropBtn);
|
|
668
|
+
this.controlsComponents.playBtn.root.classList.add('pl-0');
|
|
669
|
+
this.controlsComponents.resetCropBtn.root.classList.add('pr-0');
|
|
670
|
+
// timebar
|
|
671
|
+
timeBarArea.root.classList.add('p-4', 'pb-0');
|
|
672
|
+
this.resizeControls = () => {
|
|
673
|
+
const style = getComputedStyle(timeBarArea.root);
|
|
674
|
+
let pleft = parseFloat(style.paddingLeft);
|
|
675
|
+
let pright = parseFloat(style.paddingRight);
|
|
676
|
+
let ptop = parseFloat(style.paddingTop);
|
|
677
|
+
let pbot = parseFloat(style.paddingBottom);
|
|
678
|
+
// assuming timeBarArea will not overflow
|
|
679
|
+
this.timebar.resize([timeBarArea.root.clientWidth - pleft - pright, timeBarArea.root.clientHeight - ptop - pbot]);
|
|
680
|
+
};
|
|
681
|
+
return timeBarArea;
|
|
682
|
+
}
|
|
683
|
+
/**
|
|
684
|
+
* Creates the areas where components will be.
|
|
685
|
+
* Attaches all (desired) components of controlsComponents except the timebar
|
|
686
|
+
* @returns {Area} for the timebar
|
|
687
|
+
* Layout:
|
|
688
|
+
* curTime
|
|
689
|
+
* play speed loop trimStart |---timebar---| trimend
|
|
690
|
+
*/
|
|
691
|
+
_createControlsLayout_0() {
|
|
692
|
+
const controlsArea = this.controlsArea;
|
|
693
|
+
// Create playing timeline area and attach panels
|
|
694
|
+
let [topArea, bottomArea] = controlsArea.split({ type: 'vertical', sizes: ['50%', null], minimizable: false, resize: false });
|
|
695
|
+
bottomArea.setSize([bottomArea.size[0], 40]);
|
|
696
|
+
let [leftArea, controlsRight] = bottomArea.split({ type: 'horizontal', sizes: ['92%', null], minimizable: false, resize: false });
|
|
697
|
+
let [controlsLeft, timeBarArea] = leftArea.split({ type: 'horizontal', sizes: ['10%', null], minimizable: false, resize: false });
|
|
698
|
+
const controlsCurrentPanel = topArea.addPanel({ className: 'flex' });
|
|
699
|
+
controlsCurrentPanel._attachComponent(this.controlsComponents.curTimeText);
|
|
700
|
+
// Create controls panel (play/pause button and start time)
|
|
701
|
+
controlsLeft.root.classList.add('min-w-fit');
|
|
702
|
+
const controlsPanelLeft = controlsLeft.addPanel({ className: 'lexcontrolspanel p-0 pl-2' });
|
|
703
|
+
controlsPanelLeft.root.classList.remove('pad-md');
|
|
704
|
+
controlsPanelLeft.sameLine();
|
|
705
|
+
controlsPanelLeft._attachComponent(this.controlsComponents.playBtn);
|
|
706
|
+
controlsPanelLeft._attachComponent(this.controlsComponents.speedBtn);
|
|
707
|
+
controlsPanelLeft._attachComponent(this.controlsComponents.loopBtn);
|
|
708
|
+
controlsPanelLeft._attachComponent(this.controlsComponents.trimStartText);
|
|
709
|
+
controlsPanelLeft.endLine();
|
|
710
|
+
// Create right controls panel (end time)
|
|
711
|
+
controlsRight.root.classList.add('min-w-fit');
|
|
712
|
+
const controlsPanelRight = controlsRight.addPanel({ className: 'lexcontrolspanel p-0' });
|
|
713
|
+
controlsPanelRight.root.classList.remove('pad-md');
|
|
714
|
+
controlsPanelRight._attachComponent(this.controlsComponents.trimEndText);
|
|
715
|
+
this.resizeControls = () => {
|
|
716
|
+
bottomArea.setSize([this.controlsArea.root.clientWidth, 40]);
|
|
717
|
+
let availableWidth = this.controlsArea.root.clientWidth - controlsLeft.root.clientWidth
|
|
718
|
+
- controlsRight.root.clientWidth;
|
|
719
|
+
this.timebar.resize([availableWidth, timeBarArea.root.clientHeight]);
|
|
720
|
+
};
|
|
721
|
+
return timeBarArea;
|
|
722
|
+
}
|
|
607
723
|
setCropAreaHandles(flags) {
|
|
608
724
|
// remove existing resizer handles
|
|
609
725
|
const resizers = this.cropArea.getElementsByClassName('resize-handle');
|
|
@@ -732,18 +848,12 @@ class VideoEditor {
|
|
|
732
848
|
this.video.currentTime = this.startTime;
|
|
733
849
|
this.timebar.setCurrentTime(this.video.currentTime);
|
|
734
850
|
};
|
|
735
|
-
this.timebar.startX = this.timebar.position.x;
|
|
736
|
-
this.timebar.endX = this.timebar.position.x + this.timebar.lineWidth;
|
|
737
851
|
this.startTime = 0;
|
|
738
852
|
this.endTime = this.video.duration;
|
|
739
853
|
this.timebar.setDuration(this.endTime);
|
|
740
854
|
this.timebar.setEndTime(this.video.duration);
|
|
741
855
|
this.timebar.setStartTime(this.startTime);
|
|
742
856
|
this.timebar.setCurrentTime(this.startTime);
|
|
743
|
-
// this.timebar.setStartValue( this.timebar.startX);
|
|
744
|
-
// this.timebar.currentX = this._timeToX( this.video.currentTime);
|
|
745
|
-
// this.timebar.setCurrentValue( this.timebar.currentX);
|
|
746
|
-
// this.timebar.update( this.timebar.currentX );
|
|
747
857
|
// only have one update on flight
|
|
748
858
|
if (!this.requestId) {
|
|
749
859
|
this._update();
|
|
@@ -776,7 +886,7 @@ class VideoEditor {
|
|
|
776
886
|
this.video.pause();
|
|
777
887
|
if (!this.loop) {
|
|
778
888
|
this.playing = false;
|
|
779
|
-
this.
|
|
889
|
+
this.controlsComponents.playBtn?.setState(false, true); // skip callback
|
|
780
890
|
}
|
|
781
891
|
else {
|
|
782
892
|
this.video.currentTime = this.startTime;
|
|
@@ -802,8 +912,7 @@ class VideoEditor {
|
|
|
802
912
|
if (this.video.currentTime != t && this._updateTime) {
|
|
803
913
|
this.video.currentTime = t;
|
|
804
914
|
}
|
|
805
|
-
this.
|
|
806
|
-
this.controlsCurrentPanel.refresh();
|
|
915
|
+
this.controlsComponents.curTimeText?.set(this.timeToString(t));
|
|
807
916
|
if (this.onSetTime) {
|
|
808
917
|
this.onSetTime(t);
|
|
809
918
|
}
|
|
@@ -813,8 +922,7 @@ class VideoEditor {
|
|
|
813
922
|
}
|
|
814
923
|
_setStartTime(t) {
|
|
815
924
|
this.startTime = this.video.currentTime = t;
|
|
816
|
-
this.
|
|
817
|
-
this.controlsPanelLeft.refresh();
|
|
925
|
+
this.controlsComponents.trimStartText?.set(this.timeToString(t));
|
|
818
926
|
if (this.onSetTime) {
|
|
819
927
|
this.onSetTime(t);
|
|
820
928
|
}
|
|
@@ -824,8 +932,7 @@ class VideoEditor {
|
|
|
824
932
|
}
|
|
825
933
|
_setEndTime(t) {
|
|
826
934
|
this.endTime = this.video.currentTime = t;
|
|
827
|
-
this.
|
|
828
|
-
this.controlsPanelRight.refresh();
|
|
935
|
+
this.controlsComponents.trimEndText?.set(this.timeToString(t));
|
|
829
936
|
if (this.onSetTime) {
|
|
830
937
|
this.onSetTime(t);
|
|
831
938
|
}
|
|
@@ -846,7 +953,9 @@ class VideoEditor {
|
|
|
846
953
|
return this.cropArea.getBoundingClientRect();
|
|
847
954
|
}
|
|
848
955
|
showCropArea() {
|
|
956
|
+
this.crop = true;
|
|
849
957
|
this.cropArea.classList.remove('hidden');
|
|
958
|
+
this.controlsComponents.resetCropBtn?.root.classList.remove('hidden');
|
|
850
959
|
const nodes = this.cropArea.parentElement?.childNodes ?? [];
|
|
851
960
|
const rect = this.cropArea.getBoundingClientRect();
|
|
852
961
|
for (let i = 0; i < nodes.length; i++) {
|
|
@@ -859,7 +968,9 @@ class VideoEditor {
|
|
|
859
968
|
}
|
|
860
969
|
}
|
|
861
970
|
hideCropArea() {
|
|
971
|
+
this.crop = false;
|
|
862
972
|
this.cropArea.classList.add('hidden');
|
|
973
|
+
this.controlsComponents.resetCropBtn?.root.classList.add('hidden');
|
|
863
974
|
const nodes = this.cropArea.parentElement?.childNodes ?? [];
|
|
864
975
|
for (let i = 0; i < nodes.length; i++) {
|
|
865
976
|
const node = nodes[i];
|
|
@@ -887,8 +998,11 @@ class VideoEditor {
|
|
|
887
998
|
this.stopUpdates();
|
|
888
999
|
this.video.pause();
|
|
889
1000
|
this.playing = false;
|
|
890
|
-
this.
|
|
1001
|
+
this.controlsComponents.playBtn?.setState(false, true); // skip callback
|
|
891
1002
|
this.video.src = '';
|
|
1003
|
+
if (this.timebar) {
|
|
1004
|
+
this.timebar.unbind();
|
|
1005
|
+
}
|
|
892
1006
|
window.removeEventListener('keyup', this.onKeyUp);
|
|
893
1007
|
document.removeEventListener('mouseup', this._onCropMouseUp);
|
|
894
1008
|
document.removeEventListener('mousemove', this._onCropMouseMove);
|