lexgui 0.5.7 → 0.5.9
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/audio.js +2 -2
- package/build/components/timeline.js +475 -420
- package/build/components/videoeditor.js +97 -148
- package/build/lexgui.css +571 -99
- package/build/lexgui.js +812 -343
- package/build/lexgui.min.css +2 -6
- package/build/lexgui.min.js +1 -1
- package/build/lexgui.module.js +812 -343
- package/build/lexgui.module.min.js +1 -1
- package/changelog.md +34 -1
- package/demo.js +3 -3
- package/examples/all_widgets.html +12 -2
- package/package.json +1 -1
- package/build/utilities.css +0 -410
|
@@ -17,7 +17,7 @@ class TimeBar {
|
|
|
17
17
|
|
|
18
18
|
static BACKGROUND_COLOR = LX.getThemeColor("global-branch-darker");
|
|
19
19
|
static COLOR = LX.getThemeColor("global-button-color");
|
|
20
|
-
static ACTIVE_COLOR =
|
|
20
|
+
static ACTIVE_COLOR = "#668ee4";
|
|
21
21
|
|
|
22
22
|
constructor( area, type, options = {} ) {
|
|
23
23
|
|
|
@@ -30,60 +30,66 @@ class TimeBar {
|
|
|
30
30
|
area.attach( this.canvas );
|
|
31
31
|
|
|
32
32
|
this.ctx = this.canvas.getContext("2d");
|
|
33
|
-
|
|
34
|
-
const barHeight = options.barHeight ?? 5;
|
|
33
|
+
|
|
35
34
|
this.markerWidth = options.markerWidth ?? 8;
|
|
36
|
-
this.
|
|
35
|
+
this.markerHeight = options.markerHeight ?? (this.canvas.height * 0.5);
|
|
36
|
+
this.offset = options.offset || (this.markerWidth*0.5 + 8);
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
this.
|
|
38
|
+
// dimensions of line (not canvas)
|
|
39
|
+
this.lineWidth = this.canvas.width - this.offset * 2;
|
|
40
|
+
this.lineHeight = options.barHeight ?? 5;
|
|
40
41
|
|
|
41
|
-
this.position = new LX.vec2( this.offset, this.canvas.height * 0.5 - this.
|
|
42
|
+
this.position = new LX.vec2( this.offset, this.canvas.height * 0.5 - this.lineHeight * 0.5);
|
|
42
43
|
this.startX = this.position.x;
|
|
43
|
-
this.endX = this.
|
|
44
|
+
this.endX = this.position.x + this.lineWidth;
|
|
44
45
|
this.currentX = this.startX;
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
const w = this.markerWidth;
|
|
48
|
-
const h = this.canvas.height - y * 2;
|
|
49
|
-
this.trimRec = [this.startX, y, w, h];
|
|
47
|
+
this._draw();
|
|
50
48
|
|
|
51
|
-
this.
|
|
49
|
+
this.updateTheme();
|
|
50
|
+
LX.addSignal( "@on_new_color_scheme", (el, value) => {
|
|
51
|
+
// Retrieve again the color using LX.getThemeColor, which checks the applied theme
|
|
52
|
+
this.updateTheme();
|
|
53
|
+
} )
|
|
54
|
+
}
|
|
52
55
|
|
|
53
|
-
|
|
56
|
+
updateTheme(){
|
|
57
|
+
TimeBar.BACKGROUND_COLOR = LX.getThemeColor("global-color-secondary");
|
|
58
|
+
TimeBar.COLOR = LX.getThemeColor("global-color-quaternary");
|
|
59
|
+
TimeBar.ACTIVE_COLOR = "#668ee4";
|
|
54
60
|
}
|
|
55
61
|
|
|
56
62
|
_draw() {
|
|
57
63
|
const ctx = this.ctx;
|
|
58
|
-
|
|
64
|
+
|
|
59
65
|
ctx.save();
|
|
60
66
|
ctx.fillStyle = TimeBar.BACKGROUND_COLOR;
|
|
61
67
|
ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
|
62
68
|
ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
|
|
63
69
|
|
|
64
|
-
//
|
|
70
|
+
// Draw background timeline
|
|
65
71
|
ctx.fillStyle = TimeBar.COLOR;
|
|
66
|
-
ctx.fillRect(this.position.x, this.position.y, this.
|
|
72
|
+
ctx.fillRect(this.position.x, this.position.y, this.lineWidth, this.lineHeight);
|
|
67
73
|
|
|
68
74
|
// Draw background trimed timeline
|
|
69
75
|
ctx.fillStyle = TimeBar.ACTIVE_COLOR;
|
|
70
|
-
ctx.fillRect(this.startX, this.position.y, this.endX - this.
|
|
76
|
+
ctx.fillRect(this.startX, this.position.y, this.endX - this.startX, this.lineHeight);
|
|
71
77
|
|
|
72
78
|
ctx.restore();
|
|
73
79
|
|
|
74
80
|
// Min-Max time markers
|
|
75
|
-
this.
|
|
76
|
-
this.
|
|
77
|
-
this.
|
|
81
|
+
this._drawTrimMarker('start', this.startX, { color: null, fillColor: TimeBar.ACTIVE_COLOR || '#5f88c9'});
|
|
82
|
+
this._drawTrimMarker('end', this.endX, { color: null, fillColor: TimeBar.ACTIVE_COLOR || '#5f88c9'});
|
|
83
|
+
this._drawTimeMarker('current', this.currentX, { color: '#e5e5e5', fillColor: TimeBar.ACTIVE_COLOR || '#5f88c9', width: this.markerWidth });
|
|
78
84
|
}
|
|
79
85
|
|
|
80
|
-
|
|
86
|
+
_drawTrimMarker(name, x, options) {
|
|
81
87
|
|
|
82
88
|
options = options || {};
|
|
83
89
|
|
|
84
|
-
const
|
|
85
|
-
const
|
|
86
|
-
const
|
|
90
|
+
const w = this.markerWidth;
|
|
91
|
+
const h = this.markerHeight;
|
|
92
|
+
const y = this.canvas.height * 0.5 - h * 0.5;
|
|
87
93
|
|
|
88
94
|
const ctx = this.ctx;
|
|
89
95
|
if(this.hovering == name) {
|
|
@@ -109,7 +115,7 @@ class TimeBar {
|
|
|
109
115
|
|
|
110
116
|
}
|
|
111
117
|
|
|
112
|
-
|
|
118
|
+
_drawTimeMarker(name, x, options) {
|
|
113
119
|
|
|
114
120
|
options = options || {};
|
|
115
121
|
|
|
@@ -150,6 +156,15 @@ class TimeBar {
|
|
|
150
156
|
ctx.shadowBlur = 0;
|
|
151
157
|
}
|
|
152
158
|
|
|
159
|
+
update (x) {
|
|
160
|
+
this.currentX = Math.min(Math.max(this.startX, x), this.endX);
|
|
161
|
+
this._draw();
|
|
162
|
+
|
|
163
|
+
if(this.onDraw) {
|
|
164
|
+
this.onDraw();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
153
168
|
onMouseDown (e) {
|
|
154
169
|
|
|
155
170
|
e.preventDefault();
|
|
@@ -166,19 +181,19 @@ class TimeBar {
|
|
|
166
181
|
// Check if some marker is clicked
|
|
167
182
|
const threshold = this.markerWidth;
|
|
168
183
|
|
|
169
|
-
|
|
184
|
+
// grab trim markers only from the bottom
|
|
185
|
+
if(Math.abs(this.startX - x) < threshold && this.position.y < y) {
|
|
170
186
|
this.dragging = 'start';
|
|
171
187
|
canvas.style.cursor = "grabbing";
|
|
172
188
|
}
|
|
173
|
-
else if(Math.abs(this.endX - x) < threshold && this.
|
|
189
|
+
else if(Math.abs(this.endX - x) < threshold && this.position.y < y) {
|
|
174
190
|
this.dragging = 'end';
|
|
175
191
|
canvas.style.cursor = "grabbing";
|
|
176
192
|
}
|
|
177
|
-
else
|
|
193
|
+
else {
|
|
178
194
|
this.dragging = 'current';
|
|
179
195
|
canvas.style.cursor = "grabbing";
|
|
180
|
-
|
|
181
|
-
else {
|
|
196
|
+
|
|
182
197
|
if(x < this.startX) {
|
|
183
198
|
this.currentX = this.startX;
|
|
184
199
|
}
|
|
@@ -188,18 +203,13 @@ class TimeBar {
|
|
|
188
203
|
else {
|
|
189
204
|
this.currentX = x;
|
|
190
205
|
}
|
|
191
|
-
}
|
|
192
206
|
|
|
193
|
-
|
|
194
|
-
|
|
207
|
+
if(this.onChangeCurrent) {
|
|
208
|
+
this.onChangeCurrent(this.currentX);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
195
211
|
|
|
196
|
-
update (x) {
|
|
197
|
-
this.currentX = Math.min(Math.max(this.startX, x), this.endX);
|
|
198
212
|
this._draw();
|
|
199
|
-
|
|
200
|
-
if(this.onDraw) {
|
|
201
|
-
this.onDraw();
|
|
202
|
-
}
|
|
203
213
|
}
|
|
204
214
|
|
|
205
215
|
onMouseUp (e) {
|
|
@@ -214,100 +224,49 @@ class TimeBar {
|
|
|
214
224
|
|
|
215
225
|
const canvas = this.canvas;
|
|
216
226
|
canvas.style.cursor = "default";
|
|
217
|
-
|
|
218
|
-
// Process mouse
|
|
219
|
-
const x = e.target == this.canvas ? e.offsetX : e.offsetX - this.canvas.offsetLeft ;
|
|
220
|
-
const y = e.target == this.canvas ? e.offsetY : e.offsetY - this.canvas.offsetTop ;
|
|
221
|
-
const threshold = 5;
|
|
222
|
-
|
|
223
|
-
if(this.trimRec[1] < y && y < this.trimRec[3] + this.trimRec[1]) {
|
|
224
|
-
if(x < this.startX) {
|
|
225
|
-
this.currentX = this.startX;
|
|
226
|
-
}
|
|
227
|
-
else if(x > this.endX) {
|
|
228
|
-
this.currentX = this.endX;
|
|
229
|
-
}
|
|
230
|
-
else {
|
|
231
|
-
this.currentX = x;
|
|
232
|
-
}
|
|
233
|
-
if(this.onChangeCurrent) {
|
|
234
|
-
this.onChangeCurrent(this.currentX);
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
227
|
}
|
|
238
228
|
|
|
239
229
|
onMouseMove (e) {
|
|
230
|
+
if(!this.canvas) {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
240
233
|
|
|
241
234
|
e.preventDefault();
|
|
235
|
+
const canvas = this.canvas;
|
|
242
236
|
|
|
243
237
|
// Process mouse
|
|
244
|
-
const x = e.target ==
|
|
245
|
-
const y = e.target ==
|
|
246
|
-
const threshold = 5;
|
|
238
|
+
const x = e.target == canvas ? e.offsetX : e.clientX - canvas.offsetLeft;
|
|
239
|
+
const y = e.target == canvas ? e.offsetY : e.clientY - canvas.offsetTop;
|
|
247
240
|
|
|
248
241
|
if(this.dragging) {
|
|
249
242
|
switch(this.dragging) {
|
|
250
243
|
case 'start':
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
}
|
|
257
|
-
else {
|
|
258
|
-
this.currentX = this.startX = x;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
if(this.onChangeStart) {
|
|
262
|
-
this.onChangeStart(this.startX);
|
|
263
|
-
}
|
|
264
|
-
if(this.onChangeCurrent) {
|
|
265
|
-
this.onChangeCurrent(this.currentX);
|
|
266
|
-
}
|
|
244
|
+
this.startX = Math.max(this.position.x, Math.min(this.endX, x));
|
|
245
|
+
this.currentX = this.startX;
|
|
246
|
+
if(this.onChangeStart) {
|
|
247
|
+
this.onChangeStart(this.startX);
|
|
248
|
+
}
|
|
267
249
|
break;
|
|
268
250
|
case 'end':
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
this.currentX = this.endX = this.startX;
|
|
274
|
-
}
|
|
275
|
-
else {
|
|
276
|
-
this.currentX = this.endX = x;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
if(this.onChangeEnd) {
|
|
280
|
-
this.onChangeEnd(this.endX);
|
|
281
|
-
}
|
|
282
|
-
if(this.onChangeCurrent) {
|
|
283
|
-
this.onChangeCurrent(this.currentX);
|
|
284
|
-
}
|
|
285
|
-
break;
|
|
286
|
-
case 'current':
|
|
287
|
-
|
|
288
|
-
if(x < this.startX) {
|
|
289
|
-
this.currentX = this.startX;
|
|
290
|
-
}
|
|
291
|
-
else if(x > this.endX) {
|
|
292
|
-
this.currentX = this.endX;
|
|
293
|
-
}
|
|
294
|
-
else {
|
|
295
|
-
this.currentX = x;
|
|
296
|
-
}
|
|
297
|
-
if(this.onChangeCurrent) {
|
|
298
|
-
this.onChangeCurrent(this.currentX);
|
|
251
|
+
this.endX = Math.max(this.startX, Math.min(this.position.x + this.lineWidth, x));
|
|
252
|
+
this.currentX = this.endX;
|
|
253
|
+
if(this.onChangeEnd) {
|
|
254
|
+
this.onChangeEnd(this.endX);
|
|
299
255
|
}
|
|
300
256
|
break;
|
|
257
|
+
default:
|
|
258
|
+
this.currentX = Math.max(this.startX, Math.min(this.endX, x));
|
|
259
|
+
break;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if(this.onChangeCurrent) {
|
|
263
|
+
this.onChangeCurrent(this.currentX);
|
|
301
264
|
}
|
|
302
265
|
}
|
|
303
266
|
else {
|
|
304
|
-
|
|
305
|
-
return;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
const canvas = this.canvas;
|
|
267
|
+
const threshold = this.markerWidth * 0.5;
|
|
309
268
|
|
|
310
|
-
if(Math.abs(this.startX - x) < threshold
|
|
269
|
+
if(Math.abs(this.startX - x) < threshold ) {
|
|
311
270
|
this.hovering = 'start';
|
|
312
271
|
canvas.style.cursor = "grab";
|
|
313
272
|
}
|
|
@@ -331,14 +290,16 @@ class TimeBar {
|
|
|
331
290
|
this.canvas.width = size[0];
|
|
332
291
|
this.canvas.height = size[1];
|
|
333
292
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
const
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
this.
|
|
341
|
-
this.
|
|
293
|
+
let newWidth = size[0] - this.offset * 2;
|
|
294
|
+
newWidth = newWidth < 0.00001 ? 0.00001 : newWidth; // actual with of the line = canvas.width - offsetleft - offsetRight
|
|
295
|
+
const startRatio = (this.startX - this.offset) / this.lineWidth;
|
|
296
|
+
const currentRatio = (this.currentX - this.offset) / this.lineWidth;
|
|
297
|
+
const endRatio = (this.endX - this.offset) / this.lineWidth;
|
|
298
|
+
|
|
299
|
+
this.lineWidth = newWidth;
|
|
300
|
+
this.startX = Math.min( Math.max(newWidth * startRatio, 0), newWidth ) + this.offset;
|
|
301
|
+
this.currentX = Math.min(Math.max(newWidth * currentRatio, 0), newWidth) + this.offset;
|
|
302
|
+
this.endX = Math.min( Math.max(newWidth * endRatio, 0 ), newWidth) + this.offset;
|
|
342
303
|
|
|
343
304
|
this._draw();
|
|
344
305
|
}
|
|
@@ -420,24 +381,16 @@ class VideoEditor {
|
|
|
420
381
|
this.controlsPanelLeft.refresh = () => {
|
|
421
382
|
this.controlsPanelLeft.clear();
|
|
422
383
|
this.controlsPanelLeft.sameLine();
|
|
423
|
-
this.controlsPanelLeft.addButton('',
|
|
384
|
+
this.controlsPanelLeft.addButton('', "", (v) => {
|
|
424
385
|
this.playing = !this.playing;
|
|
425
386
|
if(this.playing) {
|
|
426
|
-
|
|
427
387
|
this.video.play();
|
|
428
|
-
// if(!this.requestId) {
|
|
429
|
-
// this.requestId = requestAnimationFrame(this._update.bind(this))
|
|
430
|
-
// }
|
|
431
388
|
}
|
|
432
389
|
else {
|
|
433
|
-
// if(this.requestId) {
|
|
434
|
-
// cancelAnimationFrame(this.requestId);
|
|
435
|
-
// this.requestId = null;
|
|
436
|
-
// }
|
|
437
390
|
this.video.pause();
|
|
438
391
|
}
|
|
439
392
|
this.controlsPanelLeft.refresh();
|
|
440
|
-
}, { width: '40px'});
|
|
393
|
+
}, { width: '40px', icon: "fa-solid " + (this.playing ? 'fa-pause' : 'fa-play') });
|
|
441
394
|
|
|
442
395
|
this.controlsPanelLeft.addLabel(this.startTimeString, {width: 50});
|
|
443
396
|
this.controlsPanelLeft.endLine();
|
|
@@ -534,7 +487,6 @@ class VideoEditor {
|
|
|
534
487
|
}
|
|
535
488
|
|
|
536
489
|
if(this.isDragging) {
|
|
537
|
-
|
|
538
490
|
this.dragCropArea(event);
|
|
539
491
|
}
|
|
540
492
|
});
|
|
@@ -615,24 +567,21 @@ class VideoEditor {
|
|
|
615
567
|
y = rectVideo.top;
|
|
616
568
|
}
|
|
617
569
|
|
|
618
|
-
if( y + this.cropArea.clientHeight > rectVideo.
|
|
619
|
-
y = rectVideo.
|
|
570
|
+
if( y + this.cropArea.clientHeight > rectVideo.bottom ) {
|
|
571
|
+
y = rectVideo.bottom - this.cropArea.clientHeight;
|
|
620
572
|
}
|
|
621
573
|
|
|
622
|
-
this.cropArea.
|
|
623
|
-
this.cropArea.style.top = y + "px";
|
|
574
|
+
const parentRect = this.cropArea.parentElement.getBoundingClientRect();
|
|
624
575
|
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
const videoEndY = rectVideo.height;
|
|
628
|
-
const cropEndY = y + this.cropArea.clientHeight;
|
|
576
|
+
this.cropArea.style.left = x - parentRect.left + "px";
|
|
577
|
+
this.cropArea.style.top = y - parentRect.top + "px";
|
|
629
578
|
|
|
630
579
|
const nodes = this.cropArea.parentElement.childNodes;
|
|
631
580
|
|
|
632
581
|
for( let i = 0; i < nodes.length; i++ ) {
|
|
633
582
|
if( nodes[i] != this.cropArea ) {
|
|
634
583
|
const rectEl = nodes[i].getBoundingClientRect();
|
|
635
|
-
nodes[i].style.webkitMask = `linear-gradient(#000 0 0) ${x - rectEl.left}px ${y }px / ${this.cropArea.clientWidth}px ${this.cropArea.clientHeight}px, linear-gradient(rgba(0, 0, 0, 0.3) 0 0)`;
|
|
584
|
+
nodes[i].style.webkitMask = `linear-gradient(#000 0 0) ${x - rectEl.left}px ${y - rectEl.top}px / ${this.cropArea.clientWidth}px ${this.cropArea.clientHeight}px, linear-gradient(rgba(0, 0, 0, 0.3) 0 0)`;
|
|
636
585
|
nodes[i].style.webkitMaskRepeat = 'no-repeat';
|
|
637
586
|
}
|
|
638
587
|
}
|
|
@@ -645,7 +594,7 @@ class VideoEditor {
|
|
|
645
594
|
}
|
|
646
595
|
|
|
647
596
|
this.timebar.startX = this.timebar.position.x;
|
|
648
|
-
this.timebar.endX = this.timebar.
|
|
597
|
+
this.timebar.endX = this.timebar.position.x + this.timebar.lineWidth;
|
|
649
598
|
|
|
650
599
|
this.video.currentTime = 0.01; // BUG: some videos will not play unless this line is present
|
|
651
600
|
this.endTime = this.video.duration;
|
|
@@ -665,9 +614,9 @@ class VideoEditor {
|
|
|
665
614
|
this.hideControls();
|
|
666
615
|
}
|
|
667
616
|
|
|
668
|
-
const ratio = this.video.clientHeight / this.video.videoHeight;
|
|
669
617
|
this.cropArea.style.height = this.video.clientHeight + "px";
|
|
670
|
-
this.cropArea.style.width =
|
|
618
|
+
this.cropArea.style.width = this.video.clientWidth + "px";
|
|
619
|
+
this.dragCropArea( { clientX: -1, clientY: -1 } );
|
|
671
620
|
|
|
672
621
|
if( this.crop ) {
|
|
673
622
|
this.showCropArea();
|
|
@@ -698,11 +647,11 @@ class VideoEditor {
|
|
|
698
647
|
}
|
|
699
648
|
|
|
700
649
|
_xToTime (x) {
|
|
701
|
-
return ((x - this.timebar.offset) / (this.timebar.
|
|
650
|
+
return ((x - this.timebar.offset) / (this.timebar.lineWidth)) * this.video.duration;
|
|
702
651
|
}
|
|
703
652
|
|
|
704
653
|
_timeToX (time) {
|
|
705
|
-
return (time / this.video.duration) * (this.timebar.
|
|
654
|
+
return (time / this.video.duration) * (this.timebar.lineWidth) + this.timebar.offset;
|
|
706
655
|
}
|
|
707
656
|
|
|
708
657
|
_setCurrentValue ( x, updateTime = true ) {
|