lexgui 0.1.30 → 0.1.32
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/nodegraph.js +187 -88
- package/build/components/timeline.js +768 -442
- package/build/components/videoeditor.js +539 -0
- package/build/lexgui.css +95 -11
- package/build/lexgui.js +287 -248
- package/build/lexgui.module.js +262 -223
- package/changelog.md +20 -0
- package/examples/index.html +2 -1
- package/examples/node_graph.html +0 -1
- package/examples/timeline.html +279 -0
- package/examples/video_editor.html +35 -0
- package/package.json +1 -1
|
@@ -44,12 +44,11 @@ class Timeline {
|
|
|
44
44
|
this.framerate = 30;
|
|
45
45
|
this.opacity = options.opacity || 1;
|
|
46
46
|
this.sidebarWidth = 0// 200;
|
|
47
|
-
this.topMargin =
|
|
47
|
+
this.topMargin = 40;
|
|
48
48
|
this.renderOutFrames = false;
|
|
49
49
|
this.lastMouse = [];
|
|
50
50
|
this.lastKeyFramesSelected = [];
|
|
51
51
|
this.tracksDrawn = [];
|
|
52
|
-
this.buttonsDrawn = [];
|
|
53
52
|
this.trackState = [];
|
|
54
53
|
this.clipboard = null;
|
|
55
54
|
this.grabTime = 0;
|
|
@@ -58,12 +57,20 @@ class Timeline {
|
|
|
58
57
|
this.tracksDictionary = {};
|
|
59
58
|
this._times = [];
|
|
60
59
|
|
|
60
|
+
this.onBeforeCreateTopBar = options.onBeforeCreateTopBar;
|
|
61
|
+
this.onAfterCreateTopBar = options.onAfterCreateTopBar;
|
|
62
|
+
this.onChangePlayMode = options.onChangePlayMode;
|
|
63
|
+
|
|
64
|
+
this.playing = false;
|
|
65
|
+
this.loop = options.loop ?? true;
|
|
66
|
+
|
|
61
67
|
this.session = new Session();
|
|
62
68
|
|
|
63
69
|
this.canvas = options.canvas ?? document.createElement('canvas');
|
|
64
70
|
|
|
65
71
|
this.duration = 1;
|
|
66
|
-
this.
|
|
72
|
+
this.speed = 1;
|
|
73
|
+
this.position = [0, 0];
|
|
67
74
|
this.size = [ options.width ?? 400, options.height ?? 100];
|
|
68
75
|
|
|
69
76
|
this.currentScroll = 0; //in percentage
|
|
@@ -79,6 +86,7 @@ class Timeline {
|
|
|
79
86
|
this.active = true;
|
|
80
87
|
this.skipVisibility = options.skipVisibility ?? false;
|
|
81
88
|
this.skipLock = options.skipLock ?? false;
|
|
89
|
+
this.disableNewTracks = options.disableNewTracks ?? false;
|
|
82
90
|
|
|
83
91
|
this.optimizeThreshold = 0.025;
|
|
84
92
|
|
|
@@ -117,14 +125,14 @@ class Timeline {
|
|
|
117
125
|
|
|
118
126
|
this.canvas.tabIndex = 1;
|
|
119
127
|
// Process keys events
|
|
120
|
-
this.
|
|
128
|
+
this.canvasArea.root.addEventListener("keydown", this.processKeys.bind(this));
|
|
121
129
|
|
|
122
130
|
right.onresize = bounding => {
|
|
123
131
|
if(!(bounding.width && bounding.height))
|
|
124
132
|
return;
|
|
125
133
|
this.resizeCanvas( [ bounding.width, bounding.height + this.header_offset ] );
|
|
126
134
|
}
|
|
127
|
-
|
|
135
|
+
this.resize(this.size);
|
|
128
136
|
}
|
|
129
137
|
|
|
130
138
|
/**
|
|
@@ -144,8 +152,26 @@ class Timeline {
|
|
|
144
152
|
let header = this.header;
|
|
145
153
|
LX.DEFAULT_NAME_WIDTH = "50%";
|
|
146
154
|
header.sameLine();
|
|
147
|
-
|
|
148
|
-
|
|
155
|
+
|
|
156
|
+
if(this.name) {
|
|
157
|
+
header.addTitle(this.name);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
header.addButton('', '<i class="fa-solid fa-'+ (this.playing ? 'pause' : 'play') +'"></i>', (value, event) => {
|
|
161
|
+
this.changeState();
|
|
162
|
+
}, {width: "40px", buttonClass: "accept"});
|
|
163
|
+
|
|
164
|
+
header.addButton('', '<i class="fa-solid fa-rotate"></i>', (value, event) => {
|
|
165
|
+
this.loop = !this.loop;
|
|
166
|
+
if(this.onChangePlayMode) {
|
|
167
|
+
this.onChangePlayMode(this.loop);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
}, {width: "40px", selectable: true, selected: this.loop});
|
|
171
|
+
|
|
172
|
+
if(this.onBeforeCreateTopBar)
|
|
173
|
+
this.onBeforeCreateTopBar(header);
|
|
174
|
+
|
|
149
175
|
header.addNumber("Current Time", this.currentTime, (value, event) => {
|
|
150
176
|
if(value > this.duration) {
|
|
151
177
|
value = this.duration;
|
|
@@ -163,10 +189,11 @@ class Timeline {
|
|
|
163
189
|
this.setDuration(value, false)}, {step: 0.01, min: 0, signal: "@on_set_duration"
|
|
164
190
|
});
|
|
165
191
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
192
|
+
header.addNumber("Speed", +this.speed.toFixed(3), (value, event) => {
|
|
193
|
+
this.setSpeed(value)}, {step: 0.01});
|
|
194
|
+
|
|
195
|
+
if(this.onAfterCreateTopBar)
|
|
196
|
+
this.onAfterCreateTopBar(header);
|
|
170
197
|
|
|
171
198
|
if(this.onShowOptimizeMenu)
|
|
172
199
|
header.addButton("", '<i class="fa-solid fa-filter"></i>', (value, event) => {this.onShowOptimizeMenu(event)}, {width: "40px"});
|
|
@@ -193,6 +220,7 @@ class Timeline {
|
|
|
193
220
|
}
|
|
194
221
|
})
|
|
195
222
|
}, {width: "40px"})
|
|
223
|
+
|
|
196
224
|
header.endLine();
|
|
197
225
|
LX.DEFAULT_NAME_WIDTH = "30%";
|
|
198
226
|
}
|
|
@@ -207,15 +235,25 @@ class Timeline {
|
|
|
207
235
|
if(this.leftPanel)
|
|
208
236
|
this.leftPanel.clear();
|
|
209
237
|
else {
|
|
210
|
-
this.leftPanel = area.addPanel({className: 'lextimelinepanel', width: "100%"});
|
|
238
|
+
this.leftPanel = area.addPanel({className: 'lextimelinepanel', width: "100%", height: "100%"});
|
|
211
239
|
}
|
|
212
240
|
|
|
213
241
|
let panel = this.leftPanel;
|
|
242
|
+
panel.sameLine(2);
|
|
214
243
|
let title = panel.addTitle("Tracks");
|
|
244
|
+
|
|
245
|
+
if(!this.disableNewTracks)
|
|
246
|
+
{
|
|
247
|
+
panel.addButton('', '<i class = "fa-solid fa-plus"></i>', (value, event) => {
|
|
248
|
+
this.addNewTrack();
|
|
249
|
+
}, {width: "40px", height: "40px"});
|
|
250
|
+
}
|
|
251
|
+
panel.endLine();
|
|
252
|
+
|
|
215
253
|
const styles = window.getComputedStyle(title);
|
|
216
254
|
const titleHeight = title.clientHeight + parseFloat(styles['marginTop']) + parseFloat(styles['marginBottom']);
|
|
255
|
+
|
|
217
256
|
let p = new LX.Panel({height: "calc(100% - " + titleHeight + "px)"});
|
|
218
|
-
|
|
219
257
|
if(this.animationClip && this.selectedItems) {
|
|
220
258
|
let items = {'id': '', 'children': []};
|
|
221
259
|
|
|
@@ -230,10 +268,10 @@ class Timeline {
|
|
|
230
268
|
let track = this.tracksPerItem[selected][j];
|
|
231
269
|
let id = track.type ? track.type : track.name;
|
|
232
270
|
|
|
233
|
-
t.children.push({'id': id, 'skipVisibility': this.skipVisibility, visible: track.active, 'children':[], actions : this.skipLock ? null : [{
|
|
271
|
+
t.children.push({'id': id, 'skipVisibility': this.skipVisibility, visible: track.active, selected: track.isSelected, 'children':[], actions : this.skipLock ? null : [{
|
|
234
272
|
'name':'Lock edition',
|
|
235
|
-
'icon': 'fa-solid '+ (track.locked ? 'fa-lock' : 'fa-lock-open'),
|
|
236
|
-
'callback': (
|
|
273
|
+
'icon': 'fa-solid '+ (track.locked ? 'fa-lock' : 'fa-lock-open'),
|
|
274
|
+
'callback': (node, el) => {
|
|
237
275
|
// TO DO (apply functionality)
|
|
238
276
|
let value = el.classList.contains('fa-lock');
|
|
239
277
|
|
|
@@ -269,6 +307,7 @@ class Timeline {
|
|
|
269
307
|
switch(e.type) {
|
|
270
308
|
case LX.TreeEvent.NODE_SELECTED:
|
|
271
309
|
this.selectTrack(e.node);
|
|
310
|
+
this.updateLeftPanel();
|
|
272
311
|
break;
|
|
273
312
|
case LX.TreeEvent.NODE_VISIBILITY:
|
|
274
313
|
this.changeTrackVisibility(e.node, e.value);
|
|
@@ -296,16 +335,6 @@ class Timeline {
|
|
|
296
335
|
this.resizeCanvas([ this.root.root.clientWidth - this.leftPanel.root.clientWidth - 8, this.size[1]]);
|
|
297
336
|
}
|
|
298
337
|
|
|
299
|
-
/**
|
|
300
|
-
* @method addButtons
|
|
301
|
-
* @param buttons: array
|
|
302
|
-
*/
|
|
303
|
-
|
|
304
|
-
addButtons(buttons) {
|
|
305
|
-
this.buttonsDrawn = buttons || this.buttonsDrawn;
|
|
306
|
-
this.updateHeader();
|
|
307
|
-
}
|
|
308
|
-
|
|
309
338
|
/**
|
|
310
339
|
* @method addNewTrack
|
|
311
340
|
*/
|
|
@@ -322,6 +351,7 @@ class Timeline {
|
|
|
322
351
|
};
|
|
323
352
|
|
|
324
353
|
this.animationClip.tracks.push(trackInfo);
|
|
354
|
+
this.updateLeftPanel();
|
|
325
355
|
return trackInfo.idx;
|
|
326
356
|
}
|
|
327
357
|
|
|
@@ -359,30 +389,37 @@ class Timeline {
|
|
|
359
389
|
/**
|
|
360
390
|
* @method setAnimationClip
|
|
361
391
|
* @param {*} animation
|
|
392
|
+
* @param {boolean} needsToProcess
|
|
362
393
|
* TODO
|
|
363
394
|
*/
|
|
364
395
|
|
|
365
|
-
setAnimationClip( animation ) {
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
396
|
+
setAnimationClip( animation, needsToProcess = true ) {
|
|
397
|
+
if(!animation || !animation.tracks || needsToProcess) {
|
|
398
|
+
this.processTracks(animation); // generate default animationclip or process the user's one
|
|
399
|
+
}
|
|
400
|
+
else{
|
|
401
|
+
this.animationClip = animation;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
this.duration = this.animationClip.duration;
|
|
405
|
+
this.speed = this.animationClip.speed ?? this.speed;
|
|
369
406
|
var w = Math.max(300, this.canvas.width);
|
|
370
407
|
this.secondsToPixels = ( w - this.session.left_margin ) / this.duration;
|
|
371
|
-
// if(this.secondsToPixels < 1)
|
|
372
|
-
// this.secondsToPixels = 100;
|
|
373
|
-
// this.session.start_time = -50 / this.secondsToPixels;
|
|
374
|
-
|
|
375
|
-
if(this.animationClip && this.animationClip.tracks.length)
|
|
376
|
-
this.processTracks(animation);
|
|
377
408
|
|
|
378
|
-
this.updateHeader();
|
|
409
|
+
//this.updateHeader();
|
|
379
410
|
this.updateLeftPanel();
|
|
411
|
+
|
|
412
|
+
return this.animationClip;
|
|
380
413
|
}
|
|
381
414
|
|
|
382
415
|
drawTimeInfo (w, h = this.topMargin) {
|
|
383
416
|
|
|
384
417
|
let ctx = this.canvas.getContext("2d");
|
|
418
|
+
ctx.font = "11px " + Timeline.FONT;//"11px Calibri";
|
|
419
|
+
ctx.textAlign = "center";
|
|
420
|
+
|
|
385
421
|
let canvas = this.canvas;
|
|
422
|
+
|
|
386
423
|
// Draw time markers
|
|
387
424
|
let startx = Math.round( this.timeToX( this.startTime ) ) + 0.5;
|
|
388
425
|
let endx = Math.round( this.timeToX( this.endTime ) ) + 0.5;
|
|
@@ -393,11 +430,11 @@ class Timeline {
|
|
|
393
430
|
ctx.save();
|
|
394
431
|
|
|
395
432
|
ctx.fillStyle = Timeline.BACKGROUND_COLOR;
|
|
396
|
-
ctx.fillRect( this.session.left_margin,0, canvas.width, h );
|
|
433
|
+
ctx.fillRect( this.session.left_margin, 0, canvas.width, h );
|
|
434
|
+
ctx.strokeStyle = LX.Timeline.FONT_COLOR;
|
|
397
435
|
|
|
398
436
|
if(this.secondsToPixels > 200 )
|
|
399
437
|
{
|
|
400
|
-
ctx.strokeStyle = LX.getThemeColor("global-selected-light");
|
|
401
438
|
ctx.globalAlpha = 0.5 * (1.0 - LX.UTILS.clamp( 200 / this.secondsToPixels, 0, 1));
|
|
402
439
|
ctx.beginPath();
|
|
403
440
|
for( let time = this.startTime; time <= this.endTime; time += 1 / this.framerate )
|
|
@@ -405,18 +442,18 @@ class Timeline {
|
|
|
405
442
|
let x = this.timeToX( time );
|
|
406
443
|
if(x < this.session.left_margin)
|
|
407
444
|
continue;
|
|
408
|
-
ctx.moveTo(Math.round(x) + 0.5, h * 0.
|
|
409
|
-
ctx.lineTo(Math.round(x) + 0.5, h *0.95);
|
|
445
|
+
ctx.moveTo(Math.round(x) + 0.5, h * 0.9);
|
|
446
|
+
ctx.lineTo(Math.round(x) + 0.5, h * 0.95);
|
|
410
447
|
}
|
|
411
448
|
ctx.stroke();
|
|
412
449
|
ctx.globalAlpha = this.opacity;
|
|
413
450
|
}
|
|
414
451
|
|
|
415
452
|
ctx.globalAlpha = 0.5;
|
|
416
|
-
ctx.strokeStyle = LX.getThemeColor("global-selected-light");
|
|
417
453
|
ctx.beginPath();
|
|
418
454
|
let times = this._times;
|
|
419
455
|
this._times.length = 0;
|
|
456
|
+
|
|
420
457
|
for( let time = this.startTime; time <= this.endTime; time += tick_time)
|
|
421
458
|
{
|
|
422
459
|
let x = this.timeToX( time );
|
|
@@ -425,31 +462,28 @@ class Timeline {
|
|
|
425
462
|
continue;
|
|
426
463
|
|
|
427
464
|
let is_tick = time % 5 == 0;
|
|
428
|
-
if(is_tick ||
|
|
429
|
-
|
|
465
|
+
if(is_tick || this.secondsToPixels > 70 ) {
|
|
430
466
|
times.push([x,time]);
|
|
431
|
-
ctx.moveTo(Math.round(x) + 0.5, h * 0.4 + (is_tick ? 0 : h * 0.
|
|
432
|
-
ctx.lineTo(Math.round(x) + 0.5, h *0.95 );
|
|
467
|
+
ctx.moveTo(Math.round(x) + 0.5, h * 0.4 + (is_tick ? h * 0.3 : h * 0.4) );
|
|
468
|
+
ctx.lineTo(Math.round(x) + 0.5, h * 0.95 );
|
|
469
|
+
ctx.stroke();
|
|
433
470
|
}
|
|
434
|
-
|
|
435
471
|
}
|
|
436
472
|
|
|
437
473
|
let x = startx;
|
|
438
|
-
if(x < this.session.left_margin)
|
|
439
|
-
x = this.session.left_margin;
|
|
440
|
-
|
|
474
|
+
if(x < this.session.left_margin) {
|
|
475
|
+
x = this.session.left_margin;
|
|
476
|
+
}
|
|
477
|
+
//ctx.moveTo(x, h - 0.5);
|
|
441
478
|
// ctx.lineTo( endx, h - 0.5);
|
|
442
|
-
ctx.stroke();
|
|
443
479
|
ctx.globalAlpha = this.opacity;
|
|
444
480
|
|
|
445
|
-
//
|
|
446
|
-
ctx.font = "11px " + Timeline.FONT;//"11px Calibri";
|
|
447
|
-
ctx.textAlign = "center";
|
|
481
|
+
// Time seconds in text
|
|
448
482
|
ctx.fillStyle = Timeline.FONT_COLOR//"#888";
|
|
449
483
|
for(var i = 0; i < times.length; ++i)
|
|
450
484
|
{
|
|
451
485
|
let time = times[i][1];
|
|
452
|
-
ctx.fillText( time == (time|0) ? time : time.toFixed(1), times[i][0]
|
|
486
|
+
ctx.fillText( time == (time|0) ? time : time.toFixed(1), times[i][0], h * 0.6);
|
|
453
487
|
}
|
|
454
488
|
|
|
455
489
|
ctx.restore();
|
|
@@ -510,6 +544,8 @@ class Timeline {
|
|
|
510
544
|
draw( currentTime = this.currentTime, rect ) {
|
|
511
545
|
|
|
512
546
|
let ctx = this.canvas.getContext("2d");
|
|
547
|
+
ctx.textBaseline = "bottom";
|
|
548
|
+
ctx.font = "11px " + Timeline.FONT;//"11px Calibri";
|
|
513
549
|
if(!rect)
|
|
514
550
|
rect = [0, ctx.canvas.height - ctx.canvas.height , ctx.canvas.width, ctx.canvas.height ];
|
|
515
551
|
|
|
@@ -568,28 +604,38 @@ class Timeline {
|
|
|
568
604
|
this.drawTimeInfo(w);
|
|
569
605
|
|
|
570
606
|
// Current time marker vertical line
|
|
571
|
-
let
|
|
572
|
-
let
|
|
573
|
-
let pos = Math.round( this.timeToX(
|
|
607
|
+
let truePos = Math.round( this.timeToX( this.currentTime ) ) + 0.5;
|
|
608
|
+
let quantCurrentTime = Math.round( this.currentTime * this.framerate ) / this.framerate;
|
|
609
|
+
let pos = Math.round( this.timeToX( quantCurrentTime ) ) + 0.5; //current_time is quantized
|
|
610
|
+
|
|
611
|
+
let posy = this.topMargin * 0.4;
|
|
574
612
|
if(pos >= this.session.left_margin)
|
|
575
613
|
{
|
|
576
|
-
|
|
577
|
-
// ctx.beginPath();
|
|
578
|
-
// ctx.globalAlpha = 0.3;
|
|
579
|
-
// ctx.moveTo(pos, 0); ctx.lineTo( pos, h );
|
|
580
|
-
// ctx.stroke();
|
|
581
|
-
|
|
582
|
-
ctx.strokeStyle = ctx.fillStyle = LX.getThemeColor("global-selected-light");
|
|
614
|
+
ctx.strokeStyle = ctx.fillStyle = LX.getThemeColor("global-selected");
|
|
583
615
|
ctx.globalAlpha = this.opacity;
|
|
584
616
|
ctx.beginPath();
|
|
585
|
-
ctx.moveTo(
|
|
617
|
+
ctx.moveTo(truePos, posy * 0.6); ctx.lineTo(truePos, this.canvas.height);//line
|
|
586
618
|
ctx.stroke();
|
|
587
|
-
ctx.beginPath();
|
|
588
|
-
ctx.moveTo(true_pos - 4, 0); ctx.lineTo(true_pos + 4, 0); ctx.lineTo(true_pos + 4, 10); ctx.lineTo(true_pos + 2, 12);ctx.lineTo(true_pos - 2, 12); ctx.lineTo(true_pos - 4, 10); //triangle
|
|
589
619
|
ctx.closePath();
|
|
620
|
+
ctx.shadowBlur = 8;
|
|
621
|
+
ctx.shadowColor = LX.getThemeColor("global-selected");
|
|
622
|
+
ctx.shadowOffsetX = 1;
|
|
623
|
+
ctx.shadowOffsetY = 1;
|
|
624
|
+
|
|
625
|
+
ctx.roundRect( truePos - 10, posy * 0.6, 20, posy, 5, true );
|
|
590
626
|
ctx.fill();
|
|
627
|
+
ctx.shadowBlur = 0;
|
|
628
|
+
ctx.shadowOffsetX = 0;
|
|
629
|
+
ctx.shadowOffsetY = 0;
|
|
591
630
|
}
|
|
592
|
-
|
|
631
|
+
|
|
632
|
+
// Current time seconds in text
|
|
633
|
+
ctx.font = "11px " + Timeline.FONT;//"11px Calibri";
|
|
634
|
+
ctx.textAlign = "center";
|
|
635
|
+
//ctx.textBaseline = "middle";
|
|
636
|
+
ctx.fillStyle = Timeline.COLOR_UNACTIVE//"#888";
|
|
637
|
+
ctx.fillText( this.currentTime.toFixed(1), truePos, this.topMargin * 0.6 );
|
|
638
|
+
|
|
593
639
|
// Selections
|
|
594
640
|
ctx.strokeStyle = ctx.fillStyle = Timeline.FONT_COLOR;
|
|
595
641
|
ctx.translate( this.position[0], this.position[1] + this.topMargin )
|
|
@@ -681,6 +727,21 @@ class Timeline {
|
|
|
681
727
|
return t;
|
|
682
728
|
}
|
|
683
729
|
|
|
730
|
+
|
|
731
|
+
/**
|
|
732
|
+
* @method setSpeed
|
|
733
|
+
* @param {Number} speed
|
|
734
|
+
*/
|
|
735
|
+
|
|
736
|
+
setSpeed(speed) {
|
|
737
|
+
this.speed = speed;
|
|
738
|
+
LX.emit( "@on_set_speed", +speed.toFixed(3));
|
|
739
|
+
|
|
740
|
+
|
|
741
|
+
if( this.onSetSpeed )
|
|
742
|
+
this.onSetSpeed( speed );
|
|
743
|
+
}
|
|
744
|
+
|
|
684
745
|
// Converts distance in pixels to time
|
|
685
746
|
xToTime( x ) {
|
|
686
747
|
return (x - this.session.left_margin) / this.secondsToPixels + this.session.start_time;
|
|
@@ -734,12 +795,12 @@ class Timeline {
|
|
|
734
795
|
|
|
735
796
|
if(!this.canvas)
|
|
736
797
|
return;
|
|
737
|
-
|
|
738
|
-
// e.stopPropagation();
|
|
798
|
+
|
|
739
799
|
e.multipleSelection = false;
|
|
740
800
|
|
|
741
801
|
let h = this.canvas.height;
|
|
742
802
|
let w = this.canvas.width;
|
|
803
|
+
|
|
743
804
|
// Process mouse
|
|
744
805
|
let x = e.offsetX;
|
|
745
806
|
let y = e.offsetY;
|
|
@@ -748,21 +809,22 @@ class Timeline {
|
|
|
748
809
|
let localX = e.offsetX - this.position[0];
|
|
749
810
|
let localY = e.offsetY - this.position[1];
|
|
750
811
|
|
|
751
|
-
// if(!this.grabbing_timeline && !this.movingKeys)
|
|
752
|
-
// this.canvas.style.cursor = "default";
|
|
753
|
-
|
|
754
|
-
|
|
755
812
|
let timeX = this.timeToX( this.currentTime );
|
|
756
813
|
let current_grabbing_timeline = localY < this.topMargin && localX > this.session.left_margin &&
|
|
757
814
|
localX > (timeX - 6) && localX < (timeX + 6);
|
|
758
815
|
|
|
759
|
-
if( current_grabbing_timeline )
|
|
816
|
+
if( current_grabbing_timeline ) {
|
|
760
817
|
this.canvas.style.cursor = "col-resize";
|
|
818
|
+
}
|
|
761
819
|
else if(this.movingKeys) {
|
|
762
820
|
this.canvas.style.cursor = "grabbing";
|
|
763
821
|
}
|
|
764
|
-
|
|
822
|
+
else if(e.shiftKey) {
|
|
823
|
+
this.canvas.style.cursor = "crosshair";
|
|
824
|
+
}
|
|
825
|
+
else {
|
|
765
826
|
this.canvas.style.cursor = "default";
|
|
827
|
+
}
|
|
766
828
|
|
|
767
829
|
if( e.type == "wheel" ) {
|
|
768
830
|
if(e.shiftKey)
|
|
@@ -770,15 +832,14 @@ class Timeline {
|
|
|
770
832
|
this.setScale( e.wheelDelta < 0 ? 0.95 : 1.05 );
|
|
771
833
|
}
|
|
772
834
|
else if( h < this.scrollableHeight)
|
|
773
|
-
{
|
|
774
|
-
this.
|
|
775
|
-
this.leftPanel.root.children[1].scrollTop = this.currentScroll* (this.scrollableHeight - h);
|
|
835
|
+
{
|
|
836
|
+
this.leftPanel.root.children[1].scrollTop += e.deltaY * 0.1 ;
|
|
776
837
|
}
|
|
777
838
|
|
|
778
839
|
return;
|
|
779
840
|
}
|
|
780
841
|
|
|
781
|
-
|
|
842
|
+
var time = this.xToTime(x, true);
|
|
782
843
|
|
|
783
844
|
var is_inside = x >= this.position[0] && x <= (this.position[0] + this.size[0]) &&
|
|
784
845
|
y >= this.position[1] && y <= (this.position[1] + this.size[1]);
|
|
@@ -798,8 +859,6 @@ class Timeline {
|
|
|
798
859
|
e.localX = localX;
|
|
799
860
|
e.localY = localY;
|
|
800
861
|
|
|
801
|
-
|
|
802
|
-
|
|
803
862
|
const innerSetTime = (t) => {
|
|
804
863
|
LX.emit( "@on_current_time_" + this.constructor.name, t);
|
|
805
864
|
if( this.onSetTime )
|
|
@@ -833,15 +892,13 @@ class Timeline {
|
|
|
833
892
|
return;
|
|
834
893
|
}
|
|
835
894
|
|
|
836
|
-
if( e.button == 0 && this.onMouseUp )
|
|
895
|
+
if( e.button == 0 && this.onMouseUp ) {
|
|
837
896
|
this.onMouseUp(e, time);
|
|
897
|
+
}
|
|
898
|
+
this.unSelectAllTracks();
|
|
899
|
+
this.updateLeftPanel();
|
|
838
900
|
}
|
|
839
|
-
|
|
840
|
-
if( !is_inside && !this.grabbing && !(e.metaKey || e.altKey ) )
|
|
841
|
-
return true;
|
|
842
|
-
|
|
843
|
-
if( this.onMouse && this.onMouse( e, time, this ) )
|
|
844
|
-
return;
|
|
901
|
+
|
|
845
902
|
|
|
846
903
|
if( e.type == "mousedown") {
|
|
847
904
|
|
|
@@ -863,7 +920,6 @@ class Timeline {
|
|
|
863
920
|
this.grabTime = time - this.currentTime;
|
|
864
921
|
if(!track || track && this.getCurrentContent(track, time, 0.001) == undefined) {
|
|
865
922
|
this.grabbing_timeline = current_grabbing_timeline;
|
|
866
|
-
|
|
867
923
|
}
|
|
868
924
|
|
|
869
925
|
if(this.onMouseDown && this.active )
|
|
@@ -890,7 +946,7 @@ class Timeline {
|
|
|
890
946
|
}
|
|
891
947
|
else if(this.grabbingScroll )
|
|
892
948
|
{
|
|
893
|
-
this.
|
|
949
|
+
this.leftPanel.root.children[1].scrollTop += e.movementY ;
|
|
894
950
|
}
|
|
895
951
|
else
|
|
896
952
|
{
|
|
@@ -900,18 +956,28 @@ class Timeline {
|
|
|
900
956
|
this.session.start_time += (old - now);
|
|
901
957
|
}
|
|
902
958
|
}
|
|
903
|
-
|
|
959
|
+
|
|
960
|
+
if(this.onMouseMove) {
|
|
904
961
|
this.onMouseMove(e, time);
|
|
962
|
+
}
|
|
905
963
|
}
|
|
906
964
|
else if (e.type == "dblclick" && this.onDblClick) {
|
|
907
965
|
this.onDblClick(e);
|
|
908
966
|
}
|
|
909
|
-
else if (e.type == "contextmenu" && this.showContextMenu && this.active)
|
|
967
|
+
else if (e.type == "contextmenu" && this.showContextMenu && this.active) {
|
|
910
968
|
this.showContextMenu(e);
|
|
969
|
+
}
|
|
911
970
|
|
|
912
971
|
this.lastMouse[0] = x;
|
|
913
972
|
this.lastMouse[1] = y;
|
|
914
973
|
|
|
974
|
+
if( !is_inside && !this.grabbing && !(e.metaKey || e.altKey ) ) {
|
|
975
|
+
return true;
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
if( this.onMouse && this.onMouse( e, time, this ) )
|
|
979
|
+
return;
|
|
980
|
+
|
|
915
981
|
return true;
|
|
916
982
|
}
|
|
917
983
|
|
|
@@ -934,9 +1000,32 @@ class Timeline {
|
|
|
934
1000
|
if(e.ctrlKey)
|
|
935
1001
|
this.pasteContent();
|
|
936
1002
|
break;
|
|
1003
|
+
case ' ':
|
|
1004
|
+
e.preventDefault();
|
|
1005
|
+
e.stopImmediatePropagation();
|
|
1006
|
+
this.changeState();
|
|
1007
|
+
break;
|
|
1008
|
+
|
|
1009
|
+
case "Shift":
|
|
1010
|
+
this.canvas.style.cursor = "crosshair";
|
|
1011
|
+
break;
|
|
937
1012
|
}
|
|
938
1013
|
}
|
|
939
1014
|
}
|
|
1015
|
+
|
|
1016
|
+
/**
|
|
1017
|
+
* @method changeState
|
|
1018
|
+
* @description change play/pause state
|
|
1019
|
+
* ...
|
|
1020
|
+
**/
|
|
1021
|
+
changeState() {
|
|
1022
|
+
this.playing = !this.playing;
|
|
1023
|
+
this.updateHeader();
|
|
1024
|
+
|
|
1025
|
+
if(this.onChangeState) {
|
|
1026
|
+
this.onChangeState(this.playing);
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
940
1029
|
|
|
941
1030
|
/**
|
|
942
1031
|
* @method drawTrackWithKeyframes
|
|
@@ -948,72 +1037,81 @@ class Timeline {
|
|
|
948
1037
|
|
|
949
1038
|
drawTrackWithKeyframes( ctx, y, trackHeight, title, track, trackInfo ) {
|
|
950
1039
|
|
|
951
|
-
if(trackInfo.enabled === false)
|
|
1040
|
+
if(trackInfo.enabled === false) {
|
|
952
1041
|
ctx.globalAlpha = 0.4;
|
|
1042
|
+
}
|
|
953
1043
|
|
|
954
|
-
ctx.font = Math.floor( trackHeight * 0.8) + "px
|
|
1044
|
+
ctx.font = Math.floor( trackHeight * 0.8) + "px" + Timeline.FONT;
|
|
955
1045
|
ctx.textAlign = "left";
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
// if(title != null)
|
|
959
|
-
// {
|
|
960
|
-
// // var info = ctx.measureText( title );
|
|
961
|
-
// ctx.fillStyle = this.active ? "rgba(255,255,255,0.9)" : "rgba(250,250,250,0.7)";
|
|
962
|
-
// ctx.fillText( title, 25, y + trackHeight * 0.75 );
|
|
963
|
-
// }
|
|
1046
|
+
|
|
964
1047
|
ctx.globalAlpha = 0.2;
|
|
965
|
-
|
|
966
|
-
if(trackInfo.isSelected)
|
|
1048
|
+
|
|
1049
|
+
if(trackInfo.isSelected) {
|
|
1050
|
+
ctx.fillStyle = Timeline.TRACK_SELECTED;//"#2c303570";
|
|
967
1051
|
ctx.fillRect(0, y, ctx.canvas.width, trackHeight );
|
|
1052
|
+
}
|
|
1053
|
+
ctx.fillStyle = Timeline.COLOR;//"#2c303570";
|
|
968
1054
|
ctx.globalAlpha = 1;
|
|
969
|
-
|
|
970
|
-
|
|
1055
|
+
|
|
1056
|
+
let keyframes = track.times;
|
|
971
1057
|
|
|
972
|
-
if(keyframes) {
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
1058
|
+
if(!keyframes) {
|
|
1059
|
+
return;
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
this.tracksDrawn.push([track,y+this.topMargin,trackHeight]);
|
|
1063
|
+
|
|
1064
|
+
for(let j = 0; j < keyframes.length; ++j)
|
|
1065
|
+
{
|
|
1066
|
+
let time = keyframes[j];
|
|
1067
|
+
let selected = trackInfo.selected[j];
|
|
1068
|
+
if( time < this.startTime || time > this.endTime ) {
|
|
1069
|
+
continue;
|
|
1070
|
+
}
|
|
1071
|
+
let keyframePosX = this.timeToX( time );
|
|
1072
|
+
if( keyframePosX > this.sidebarWidth ){
|
|
1073
|
+
ctx.save();
|
|
984
1074
|
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
}
|
|
999
|
-
if(trackInfo.locked)
|
|
1000
|
-
ctx.fillStyle = Timeline.COLOR_LOCK;
|
|
1075
|
+
let margin = -1;
|
|
1076
|
+
let size = trackHeight * 0.3;
|
|
1077
|
+
|
|
1078
|
+
if(trackInfo.edited[j]) {
|
|
1079
|
+
ctx.fillStyle = Timeline.COLOR_EDITED;
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
if(selected) {
|
|
1083
|
+
ctx.fillStyle = Timeline.COLOR_SELECTED;
|
|
1084
|
+
ctx.shadowBlur = 8;
|
|
1085
|
+
size = trackHeight * 0.35;
|
|
1086
|
+
margin = 0;
|
|
1087
|
+
}
|
|
1001
1088
|
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
ctx.
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
ctx.
|
|
1089
|
+
if(trackInfo.hovered[j]) {
|
|
1090
|
+
size = trackHeight * 0.35;
|
|
1091
|
+
ctx.fillStyle = Timeline.COLOR_HOVERED;
|
|
1092
|
+
ctx.shadowBlur = 8;
|
|
1093
|
+
margin = 0;
|
|
1094
|
+
}
|
|
1095
|
+
if(trackInfo.locked) {
|
|
1096
|
+
ctx.fillStyle = Timeline.COLOR_LOCK;
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
if(!this.active || trackInfo.active == false) {
|
|
1100
|
+
ctx.fillStyle = Timeline.COLOR_UNACTIVE;
|
|
1014
1101
|
}
|
|
1102
|
+
|
|
1103
|
+
ctx.translate(keyframePosX, y + this.trackHeight * 0.75 + margin);
|
|
1104
|
+
ctx.rotate(45 * Math.PI / 180);
|
|
1105
|
+
ctx.fillRect( -size, -size, size, size);
|
|
1106
|
+
if(selected) {
|
|
1107
|
+
ctx.globalAlpha = 0.3;
|
|
1108
|
+
ctx.fillRect( -size*1.1, -size*1.1, size*1.2, size*1.2);
|
|
1109
|
+
}
|
|
1110
|
+
ctx.shadowBlur = 0;
|
|
1111
|
+
ctx.restore();
|
|
1015
1112
|
}
|
|
1016
1113
|
}
|
|
1114
|
+
|
|
1017
1115
|
|
|
1018
1116
|
ctx.globalAlpha = this.opacity;
|
|
1019
1117
|
}
|
|
@@ -1027,99 +1125,129 @@ class Timeline {
|
|
|
1027
1125
|
|
|
1028
1126
|
drawTrackWithBoxes( ctx, y, trackHeight, title, track ) {
|
|
1029
1127
|
|
|
1030
|
-
|
|
1031
|
-
this.tracksDrawn.push([track,y+this.topMargin,trackHeight]);
|
|
1128
|
+
const offset = (trackHeight - trackHeight * 0.6) * 0.5;
|
|
1129
|
+
this.tracksDrawn.push([track, y + this.topMargin, trackHeight]);
|
|
1130
|
+
|
|
1032
1131
|
trackHeight *= 0.6;
|
|
1132
|
+
this.canvas = this.canvas || ctx.canvas;
|
|
1133
|
+
|
|
1033
1134
|
let selectedClipArea = null;
|
|
1034
1135
|
|
|
1035
|
-
if(track.enabled === false)
|
|
1136
|
+
if(track.enabled === false) {
|
|
1036
1137
|
ctx.globalAlpha = 0.4;
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1138
|
+
}
|
|
1139
|
+
else {
|
|
1140
|
+
ctx.globalAlpha = 0.2;
|
|
1141
|
+
}
|
|
1041
1142
|
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
//
|
|
1143
|
+
ctx.font = Math.floor( trackHeight * 0.8) + "px" + Timeline.FONT;
|
|
1144
|
+
ctx.textAlign = "left";
|
|
1145
|
+
ctx.textBaseline = "middle";
|
|
1146
|
+
ctx.fillStyle = Timeline.TRACK_SELECTED_LIGHT//"#2c303570";
|
|
1147
|
+
|
|
1148
|
+
// Fill track background if it's selected
|
|
1149
|
+
if(track.isSelected) {
|
|
1150
|
+
ctx.fillRect(0, y + offset - 2, ctx.canvas.width, trackHeight + 4 );
|
|
1151
|
+
}
|
|
1048
1152
|
|
|
1049
|
-
ctx.fillStyle = "rgba(10,200,200,1)";
|
|
1050
1153
|
var clips = track.clips;
|
|
1051
1154
|
let trackAlpha = 1;
|
|
1052
1155
|
|
|
1053
|
-
if(clips) {
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
{
|
|
1057
|
-
selectedClipArea = null;
|
|
1058
|
-
let clip = clips[j];
|
|
1059
|
-
//let selected = track.selected[j];
|
|
1060
|
-
var x = Math.floor( this.timeToX(clip.start) ) + 0.5;
|
|
1061
|
-
var x2 = Math.floor( this.timeToX( clip.start + clip.duration ) ) + 0.5;
|
|
1062
|
-
var w = x2-x;
|
|
1063
|
-
|
|
1064
|
-
if( x2 < 0 || x > this.canvas.width )
|
|
1065
|
-
continue;
|
|
1156
|
+
if(!clips) {
|
|
1157
|
+
return;
|
|
1158
|
+
}
|
|
1066
1159
|
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1160
|
+
for(var j = 0; j < clips.length; ++j)
|
|
1161
|
+
{
|
|
1162
|
+
selectedClipArea = null;
|
|
1163
|
+
let clip = clips[j];
|
|
1164
|
+
//let selected = track.selected[j];
|
|
1165
|
+
var x = Math.floor( this.timeToX(clip.start) ) + 0.5;
|
|
1166
|
+
var x2 = Math.floor( this.timeToX( clip.start + clip.duration ) ) + 0.5;
|
|
1167
|
+
var w = x2-x;
|
|
1168
|
+
|
|
1169
|
+
if( x2 < 0 || x > this.canvas.width )
|
|
1170
|
+
continue;
|
|
1171
|
+
|
|
1172
|
+
// Overwrite clip color state depending on its state
|
|
1173
|
+
ctx.globalAlpha = trackAlpha;
|
|
1174
|
+
ctx.fillStyle = clip.clipColor || (track.hovered[j] ? Timeline.COLOR_HOVERED : (Timeline.COLOR));
|
|
1175
|
+
if(track.selected[j] && !clip.clipColor) {
|
|
1176
|
+
ctx.fillStyle = Timeline.TRACK_SELECTED;
|
|
1177
|
+
}
|
|
1178
|
+
if(!this.active || track.active == false) {
|
|
1179
|
+
ctx.fillStyle = Timeline.COLOR_UNACTIVE;
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
// Draw clip background
|
|
1183
|
+
ctx.roundRect( x, y + offset, w, trackHeight , 5, true);
|
|
1184
|
+
|
|
1185
|
+
// Compute timeline position of fade-in and fade-out clip times
|
|
1186
|
+
let fadeinX = this.secondsToPixels * ((clip.fadein || 0) - clip.start);
|
|
1187
|
+
let fadeoutX = this.secondsToPixels * (clip.start + clip.duration - (clip.fadeout || (clip.start + clip.duration)));
|
|
1188
|
+
|
|
1189
|
+
if(this.active && track.active) {
|
|
1190
|
+
// Transform fade-in and fade-out fill color to RGBA
|
|
1191
|
+
if(ctx.fillStyle[0] == "#") {
|
|
1192
|
+
let color = LX.UTILS.HexToRgb(ctx.fillStyle);
|
|
1193
|
+
color = color.map(x => x*=0.8);
|
|
1194
|
+
ctx.fillStyle = 'rgba(' + color.join(',') + ', 0.8)';
|
|
1195
|
+
}
|
|
1196
|
+
else {
|
|
1197
|
+
ctx.globalAlpha = 0.8;
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
// Draw fade-in and fade-out
|
|
1201
|
+
if(fadeinX >= 0) {
|
|
1081
1202
|
ctx.roundRect(x, y + offset, fadeinX, trackHeight, {tl: 5, bl: 5, tr:0, br:0}, true);
|
|
1082
|
-
|
|
1203
|
+
}
|
|
1204
|
+
if(fadeoutX) {
|
|
1083
1205
|
ctx.roundRect( x + w - fadeoutX, y + offset, fadeoutX, trackHeight, {tl: 0, bl: 0, tr:5, br:5}, true);
|
|
1084
|
-
|
|
1085
|
-
//draw clip outline
|
|
1086
|
-
if(clip.hidden)
|
|
1087
|
-
ctx.globalAlpha = trackAlpha * 0.5;
|
|
1088
|
-
|
|
1089
|
-
ctx.globalAlpha = trackAlpha;
|
|
1090
|
-
if(this.selectedClip == clip || track.selected[j])
|
|
1091
|
-
selectedClipArea = [x, y + offset, x2-x, trackHeight];
|
|
1092
|
-
|
|
1093
|
-
ctx.fillStyle = "black"; //Timeline.FONT_COLOR; // clip.color || Timeline.FONT_COLOR;
|
|
1094
|
-
ctx.font = "12px" + Timeline.FONT;
|
|
1095
|
-
//render clip selection area
|
|
1096
|
-
if(selectedClipArea)
|
|
1097
|
-
{
|
|
1098
|
-
ctx.strokeStyle = track.clips[j].clipColor;
|
|
1099
|
-
ctx.fillStyle = "white"; //(Timeline.FONT_COLOR || track.clips[j].clipColor);
|
|
1100
|
-
ctx.globalAlpha = 0.6;
|
|
1101
|
-
ctx.lineWidth = 2.5;
|
|
1102
|
-
ctx.roundRect(selectedClipArea[0]-1,selectedClipArea[1]-1,selectedClipArea[2]+2,selectedClipArea[3]+2, 5, false, true);
|
|
1103
|
-
ctx.strokeStyle = "#888";
|
|
1104
|
-
ctx.lineWidth = 0.5;
|
|
1105
|
-
ctx.globalAlpha = this.opacity;
|
|
1106
|
-
ctx.font = "bold 13px " + Timeline.FONT;
|
|
1107
1206
|
}
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
ctx.fillStyle = clip.color || Timeline.FONT_COLOR; // clip.color || Timeline.FONT_COLOR;
|
|
1210
|
+
//ctx.font = "12px" + Timeline.FONT;
|
|
1108
1211
|
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
if( this.secondsToPixels < 200)
|
|
1112
|
-
ctx.font = this.secondsToPixels*0.06 +"px" + Timeline.FONT;
|
|
1212
|
+
// Overwrite style and draw clip selection area if it's selected
|
|
1213
|
+
ctx.globalAlpha = clip.hidden ? trackAlpha * 0.5 : trackAlpha;
|
|
1113
1214
|
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1215
|
+
if(this.selectedClip == clip || track.selected[j] || track.hovered[j]) {
|
|
1216
|
+
ctx.strokeStyle = ctx.shadowColor = track.clips[j].clipColor || Timeline.TRACK_SELECTED;
|
|
1217
|
+
ctx.shadowBlur = 10;
|
|
1218
|
+
ctx.shadowOffsetX = 1.5;
|
|
1219
|
+
ctx.shadowOffsetY = 1.5;
|
|
1220
|
+
|
|
1221
|
+
selectedClipArea = [x - 1, y + offset -1, x2 - x + 2, trackHeight + 2];
|
|
1222
|
+
ctx.roundRect(selectedClipArea[0], selectedClipArea[1], selectedClipArea[2], selectedClipArea[3], 5, false, true);
|
|
1223
|
+
|
|
1224
|
+
ctx.shadowBlur = 0;
|
|
1225
|
+
ctx.shadowOffsetX = 0;
|
|
1226
|
+
ctx.shadowOffsetY = 0;
|
|
1117
1227
|
|
|
1118
|
-
ctx.font = "
|
|
1228
|
+
ctx.font = "bold" + Math.floor( trackHeight) + "px " + Timeline.FONT;
|
|
1229
|
+
ctx.fillStyle = "white";
|
|
1119
1230
|
}
|
|
1231
|
+
|
|
1232
|
+
// Overwrite style with small font size if it's zoomed out
|
|
1233
|
+
if( this.secondsToPixels < 200) {
|
|
1234
|
+
ctx.font = this.secondsToPixels*0.06 +"px" + Timeline.FONT;
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
const text = clip.id.replaceAll("_", " ").replaceAll("-", " ");
|
|
1238
|
+
const textInfo = ctx.measureText( text );
|
|
1239
|
+
|
|
1240
|
+
// Draw clip name if it's readable
|
|
1241
|
+
if(this.secondsToPixels > 100) {
|
|
1242
|
+
ctx.fillText( text, x + (w - textInfo.width)*0.5, y + offset + trackHeight * 0.5);
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
ctx.fillStyle = track.hovered[j] ? "white" : Timeline.FONT_COLOR;
|
|
1246
|
+
// Draw resize bounding
|
|
1247
|
+
ctx.roundRect(x + w - 8 , y + offset , 8, trackHeight, {tl: 4, bl: 4, tr:4, br:4}, true);
|
|
1120
1248
|
}
|
|
1121
1249
|
|
|
1122
|
-
|
|
1250
|
+
ctx.font = "12px" + Timeline.FONT;
|
|
1123
1251
|
}
|
|
1124
1252
|
|
|
1125
1253
|
/**
|
|
@@ -1228,18 +1356,15 @@ class Timeline {
|
|
|
1228
1356
|
*/
|
|
1229
1357
|
resize( size = [this.root.parent.root.clientWidth, this.root.parent.root.clientHeight]) {
|
|
1230
1358
|
|
|
1231
|
-
this.root.root.style.width = size[0] + "px";
|
|
1232
|
-
this.root.root.style.height = size[1] + "px";
|
|
1359
|
+
// this.root.root.style.width = size[0] + "px";
|
|
1360
|
+
// this.root.root.style.height = size[1] + "px";
|
|
1233
1361
|
|
|
1234
1362
|
this.size = size;
|
|
1235
|
-
this.content_area.setSize([size[0], size[1] - this.header_offset]);
|
|
1236
|
-
|
|
1237
|
-
let w = size[0] - this.leftPanel.root.clientWidth - 8;
|
|
1238
|
-
this.resizeCanvas([w , size[1]]);
|
|
1239
|
-
|
|
1240
|
-
// this.session.start_time = 0;
|
|
1241
|
-
|
|
1363
|
+
//this.content_area.setSize([size[0], size[1] - this.header_offset]);
|
|
1364
|
+
this.content_area.root.style.height = "calc(100% - "+ this.header_offset + "px)";
|
|
1242
1365
|
|
|
1366
|
+
let w = size[0] - this.leftPanel.root.clientWidth - 8;
|
|
1367
|
+
this.resizeCanvas([w , size[1]]);
|
|
1243
1368
|
}
|
|
1244
1369
|
|
|
1245
1370
|
resizeCanvas( size ) {
|
|
@@ -1252,15 +1377,11 @@ class Timeline {
|
|
|
1252
1377
|
this.pixelsToSeconds = 1 / this.secondsToPixels;
|
|
1253
1378
|
}
|
|
1254
1379
|
size[1] -= this.header_offset;
|
|
1255
|
-
this.canvasArea.setSize(size);
|
|
1256
|
-
this.
|
|
1257
|
-
this.canvas.
|
|
1258
|
-
|
|
1259
|
-
// var centerx = this.canvas.width * 0.5;
|
|
1260
|
-
// var x = this.xToTime( centerx );
|
|
1261
|
-
// this.session.start_time += x - this.xToTime( centerx );
|
|
1380
|
+
//this.canvasArea.setSize(size);
|
|
1381
|
+
//this.canvasArea.root.style.height = "calc(100% - "+ this.header_offset + "px)";
|
|
1382
|
+
this.canvas.width = this.canvasArea.root.clientWidth;
|
|
1383
|
+
this.canvas.height = this.canvasArea.root.clientHeight;
|
|
1262
1384
|
this.draw(this.currentTime);
|
|
1263
|
-
|
|
1264
1385
|
}
|
|
1265
1386
|
|
|
1266
1387
|
/**
|
|
@@ -1278,19 +1399,20 @@ class Timeline {
|
|
|
1278
1399
|
show() {
|
|
1279
1400
|
|
|
1280
1401
|
this.root.show();
|
|
1281
|
-
this.
|
|
1282
|
-
|
|
1402
|
+
this.updateLeftPanel();
|
|
1403
|
+
this.resize();
|
|
1283
1404
|
}
|
|
1284
1405
|
};
|
|
1285
1406
|
|
|
1286
1407
|
Timeline.BACKGROUND_COLOR = LX.getThemeColor("global-color-primary");
|
|
1287
|
-
Timeline.TRACK_COLOR_PRIMARY = LX.getThemeColor("global-
|
|
1408
|
+
Timeline.TRACK_COLOR_PRIMARY = LX.getThemeColor("global-blur-background");
|
|
1288
1409
|
Timeline.TRACK_COLOR_SECONDARY = LX.getThemeColor("global-color-terciary");
|
|
1289
1410
|
Timeline.TRACK_SELECTED = LX.getThemeColor("global-selected");
|
|
1411
|
+
Timeline.TRACK_SELECTED_LIGHT = LX.getThemeColor("global-selected-light");
|
|
1290
1412
|
Timeline.FONT = LX.getThemeColor("global-font");
|
|
1291
1413
|
Timeline.FONT_COLOR = LX.getThemeColor("global-text");
|
|
1292
|
-
Timeline.COLOR = "#5e9fdd";
|
|
1293
|
-
Timeline.COLOR_HOVERED = "
|
|
1414
|
+
Timeline.COLOR = LX.getThemeColor("global-selected-dark");//"#5e9fdd";
|
|
1415
|
+
Timeline.COLOR_HOVERED = LX.getThemeColor("global-selected");
|
|
1294
1416
|
Timeline.COLOR_SELECTED = "rgba(250,250,20,1)"///"rgba(250,250,20,1)";
|
|
1295
1417
|
Timeline.COLOR_UNACTIVE = "rgba(250,250,250,0.7)";
|
|
1296
1418
|
Timeline.COLOR_LOCK = "rgba(255,125,125,0.7)";
|
|
@@ -1319,14 +1441,8 @@ class KeyFramesTimeline extends Timeline {
|
|
|
1319
1441
|
this.autoKeyEnabled = false;
|
|
1320
1442
|
|
|
1321
1443
|
|
|
1322
|
-
if(this.animationClip && this.animationClip.tracks.length)
|
|
1444
|
+
if(this.animationClip && this.animationClip.tracks.length) {
|
|
1323
1445
|
this.processTracks(this.animationClip);
|
|
1324
|
-
|
|
1325
|
-
// Add button data
|
|
1326
|
-
let offset = 25;
|
|
1327
|
-
if(this.active)
|
|
1328
|
-
{
|
|
1329
|
-
|
|
1330
1446
|
}
|
|
1331
1447
|
}
|
|
1332
1448
|
|
|
@@ -1363,28 +1479,17 @@ class KeyFramesTimeline extends Timeline {
|
|
|
1363
1479
|
}
|
|
1364
1480
|
|
|
1365
1481
|
}else {
|
|
1366
|
-
let boundingBox = this.canvas.getBoundingClientRect()
|
|
1367
|
-
if(e.y < boundingBox.top || e.y > boundingBox.bottom)
|
|
1482
|
+
let boundingBox = this.canvas.getBoundingClientRect();
|
|
1483
|
+
if(e.y < boundingBox.top || e.y > boundingBox.bottom) {
|
|
1368
1484
|
return;
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1369
1487
|
// Check exact track keyframe
|
|
1370
1488
|
if(!discard && track) {
|
|
1371
|
-
this.processCurrentKeyFrame( e, null, track, localX );
|
|
1372
|
-
|
|
1489
|
+
this.processCurrentKeyFrame( e, null, track, localX );
|
|
1373
1490
|
}
|
|
1374
1491
|
else {
|
|
1375
|
-
this.unSelectAllKeyFrames();
|
|
1376
|
-
let x = e.offsetX;
|
|
1377
|
-
let y = e.offsetY - this.topMargin;
|
|
1378
|
-
for( const b of this.buttonsDrawn ) {
|
|
1379
|
-
b.pressed = false;
|
|
1380
|
-
const bActive = x >= b[2] && x <= (b[2] + b[4]) && y >= b[3] && y <= (b[3] + b[5]);
|
|
1381
|
-
if(bActive) {
|
|
1382
|
-
const callback = b[6];
|
|
1383
|
-
if(callback) callback(e);
|
|
1384
|
-
else this[ b[1] ] = !this[ b[1] ];
|
|
1385
|
-
break;
|
|
1386
|
-
}
|
|
1387
|
-
}
|
|
1492
|
+
this.unSelectAllKeyFrames();
|
|
1388
1493
|
}
|
|
1389
1494
|
}
|
|
1390
1495
|
|
|
@@ -1423,15 +1528,6 @@ class KeyFramesTimeline extends Timeline {
|
|
|
1423
1528
|
}
|
|
1424
1529
|
|
|
1425
1530
|
this.timeBeforeMove = track.times[ keyFrameIndex ];
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
}
|
|
1429
|
-
} else if(!track) {
|
|
1430
|
-
let x = e.offsetX;
|
|
1431
|
-
let y = e.offsetY - this.topMargin;
|
|
1432
|
-
for( const b of this.buttonsDrawn ) {
|
|
1433
|
-
const bActive = x >= b[2] && x <= (b[2] + b[4]) && y >= b[3] && y <= (b[3] + b[5]);
|
|
1434
|
-
b.pressed = bActive;
|
|
1435
1531
|
}
|
|
1436
1532
|
}
|
|
1437
1533
|
}
|
|
@@ -1638,7 +1734,7 @@ class KeyFramesTimeline extends Timeline {
|
|
|
1638
1734
|
track.selected[newIdx] = true;
|
|
1639
1735
|
|
|
1640
1736
|
}
|
|
1641
|
-
LX.emit( "@on_current_time_" + this.constructor.name, this.currentTime );
|
|
1737
|
+
//LX.emit( "@on_current_time_" + this.constructor.name, this.currentTime );
|
|
1642
1738
|
// Update time
|
|
1643
1739
|
if(this.onSetTime)
|
|
1644
1740
|
this.onSetTime(this.currentTime);
|
|
@@ -1652,48 +1748,84 @@ class KeyFramesTimeline extends Timeline {
|
|
|
1652
1748
|
this.tracksPerItem = {};
|
|
1653
1749
|
this.tracksDictionary = {};
|
|
1654
1750
|
this.animationClip = {
|
|
1655
|
-
name: animation.name,
|
|
1656
|
-
duration: animation.duration,
|
|
1657
|
-
speed: animation.speed
|
|
1751
|
+
name: (animation && animation.name) ? animation.name : "animationClip",
|
|
1752
|
+
duration: animation ? animation.duration : 0,
|
|
1753
|
+
speed: (animation && animation.speed ) ? animation.speed : this.speed,
|
|
1658
1754
|
tracks: []
|
|
1659
1755
|
};
|
|
1756
|
+
if (animation && animation.tracks) {
|
|
1757
|
+
for( let i = 0; i < animation.tracks.length; ++i ) {
|
|
1758
|
+
|
|
1759
|
+
let track = animation.tracks[i];
|
|
1760
|
+
|
|
1761
|
+
const [name, type] = this.getTrackName(track.name);
|
|
1762
|
+
|
|
1763
|
+
let trackInfo = {
|
|
1764
|
+
fullname: track.name,
|
|
1765
|
+
name: name, type: type,
|
|
1766
|
+
dim: track.values.length/track.times.length,
|
|
1767
|
+
selected: [], edited: [], hovered: [], active: true,
|
|
1768
|
+
times: track.times,
|
|
1769
|
+
values: track.values
|
|
1770
|
+
};
|
|
1771
|
+
|
|
1772
|
+
if(!this.tracksPerItem[name]) {
|
|
1773
|
+
this.tracksPerItem[name] = [trackInfo];
|
|
1774
|
+
}else {
|
|
1775
|
+
this.tracksPerItem[name].push( trackInfo );
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
|
|
1779
|
+
const trackIndex = this.tracksPerItem[name].length - 1;
|
|
1780
|
+
this.tracksPerItem[name][trackIndex].idx = trackIndex;
|
|
1781
|
+
this.tracksPerItem[name][trackIndex].clipIdx = i;
|
|
1782
|
+
|
|
1783
|
+
// Save index also in original track
|
|
1784
|
+
track.idx = trackIndex;
|
|
1785
|
+
this.tracksDictionary[track.name] = name;
|
|
1786
|
+
|
|
1787
|
+
this.animationClip.tracks.push(trackInfo);
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
this.resize();
|
|
1791
|
+
}
|
|
1660
1792
|
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1793
|
+
updateTrack(trackIdx, track) {
|
|
1794
|
+
if(!this.animationClip)
|
|
1795
|
+
return;
|
|
1796
|
+
this.animationClip.tracks[trackIdx].values = track.values;
|
|
1797
|
+
this.animationClip.tracks[trackIdx].times = track.times;
|
|
1798
|
+
this.processTrack(trackIdx);
|
|
1664
1799
|
|
|
1665
|
-
|
|
1800
|
+
}
|
|
1666
1801
|
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
dim: track.values.length/track.times.length,
|
|
1671
|
-
selected: [], edited: [], hovered: [], active: true,
|
|
1672
|
-
times: track.times,
|
|
1673
|
-
values: track.values
|
|
1674
|
-
};
|
|
1675
|
-
|
|
1676
|
-
if(!this.tracksPerItem[name]) {
|
|
1677
|
-
this.tracksPerItem[name] = [trackInfo];
|
|
1678
|
-
}else {
|
|
1679
|
-
this.tracksPerItem[name].push( trackInfo );
|
|
1680
|
-
}
|
|
1681
|
-
|
|
1802
|
+
processTrack(trackIdx) {
|
|
1803
|
+
if(!this.animationClip)
|
|
1804
|
+
return;
|
|
1682
1805
|
|
|
1683
|
-
|
|
1684
|
-
this.tracksPerItem[name][trackIndex].idx = trackIndex;
|
|
1685
|
-
this.tracksPerItem[name][trackIndex].clipIdx = i;
|
|
1806
|
+
let track = this.animationClip.tracks[trackIdx];
|
|
1686
1807
|
|
|
1687
|
-
|
|
1688
|
-
track.idx = trackIndex;
|
|
1689
|
-
this.tracksDictionary[track.name] = name;
|
|
1808
|
+
const [name, type] = this.getTrackName(track.fullname || track.name);
|
|
1690
1809
|
|
|
1691
|
-
|
|
1810
|
+
let trackInfo = {
|
|
1811
|
+
fullname: track.name,
|
|
1812
|
+
name: name, type: type,
|
|
1813
|
+
dim: track.values.length/track.times.length,
|
|
1814
|
+
selected: [], edited: [], hovered: [], active: true,
|
|
1815
|
+
times: track.times,
|
|
1816
|
+
values: track.values
|
|
1817
|
+
};
|
|
1818
|
+
|
|
1819
|
+
for(let i = 0; i < this.tracksPerItem[name].length; i++) {
|
|
1820
|
+
if(this.tracksPerItem[name][i].fullname == trackInfo.fullname) {
|
|
1821
|
+
trackInfo.idx = this.tracksPerItem[name][i].idx;
|
|
1822
|
+
trackInfo.clipIdx = this.tracksPerItem[name][i].clipIdx;
|
|
1823
|
+
this.tracksPerItem[name][i] = trackInfo;
|
|
1824
|
+
return;
|
|
1825
|
+
}
|
|
1692
1826
|
}
|
|
1693
|
-
this.resize();
|
|
1694
1827
|
}
|
|
1695
1828
|
|
|
1696
|
-
|
|
1697
1829
|
optimizeTrack(trackIdx) {
|
|
1698
1830
|
const track = this.animationClip.tracks[trackIdx];
|
|
1699
1831
|
if(track.optimize) {
|
|
@@ -2396,35 +2528,148 @@ class ClipsTimeline extends Timeline {
|
|
|
2396
2528
|
this.lastClipsSelected = [];
|
|
2397
2529
|
}
|
|
2398
2530
|
|
|
2399
|
-
resizeCanvas( size ) {
|
|
2400
|
-
|
|
2401
|
-
|
|
2531
|
+
// resizeCanvas( size ) {
|
|
2532
|
+
// if( size[0] <= 0 && size[1] <=0 )
|
|
2533
|
+
// return;
|
|
2402
2534
|
|
|
2403
|
-
|
|
2535
|
+
// size[1] -= this.header_offset;
|
|
2404
2536
|
|
|
2405
|
-
|
|
2537
|
+
// if(Math.abs(this.canvas.width - size[0]) > 1) {
|
|
2406
2538
|
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2539
|
+
// var w = Math.max(300, size[0] );
|
|
2540
|
+
// this.secondsToPixels = ( w- this.session.left_margin ) / this.duration;
|
|
2541
|
+
// this.pixelsToSeconds = 1 / this.secondsToPixels;
|
|
2542
|
+
// }
|
|
2543
|
+
|
|
2544
|
+
// this.canvasArea.setSize(size);
|
|
2545
|
+
// this.canvas.width = size[0];
|
|
2546
|
+
// this.canvas.height = size[1];
|
|
2547
|
+
// var w = Math.max(300, this.canvas.width);
|
|
2548
|
+
|
|
2549
|
+
// this.draw(this.currentTime);
|
|
2550
|
+
// }
|
|
2551
|
+
|
|
2552
|
+
updateLeftPanel(area) {
|
|
2553
|
+
|
|
2554
|
+
if(this.leftPanel)
|
|
2555
|
+
this.leftPanel.clear();
|
|
2556
|
+
else {
|
|
2557
|
+
this.leftPanel = area.addPanel({className: 'lextimelinepanel', width: "100%", height: "100%"});
|
|
2410
2558
|
}
|
|
2411
2559
|
|
|
2412
|
-
this.
|
|
2413
|
-
this.canvas.width = size[0];
|
|
2414
|
-
this.canvas.height = size[1];
|
|
2415
|
-
var w = Math.max(300, this.canvas.width);
|
|
2416
|
-
// this.secondsToPixels = ( w - this.session.left_margin ) / this.duration;
|
|
2417
|
-
// this.pixelsToSeconds = 1 / this.secondsToPixels;
|
|
2560
|
+
let panel = this.leftPanel;
|
|
2418
2561
|
|
|
2419
|
-
|
|
2420
|
-
let
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2562
|
+
panel.sameLine(2);
|
|
2563
|
+
let title = panel.addTitle("Tracks");
|
|
2564
|
+
if(!this.disableNewTracks)
|
|
2565
|
+
{
|
|
2566
|
+
panel.addButton('', '<i class = "fa-solid fa-plus"></i>', (value, event) => {
|
|
2567
|
+
this.addNewTrack();
|
|
2568
|
+
}, {width: "40px", height: "40px"});
|
|
2569
|
+
}
|
|
2570
|
+
panel.endLine();
|
|
2571
|
+
const styles = window.getComputedStyle(title);
|
|
2572
|
+
const titleHeight = title.clientHeight + parseFloat(styles['marginTop']) + parseFloat(styles['marginBottom']);
|
|
2573
|
+
let p = new LX.Panel({height: "calc(100% - " + titleHeight + "px)"});
|
|
2574
|
+
|
|
2575
|
+
if(this.animationClip) {
|
|
2576
|
+
|
|
2577
|
+
for(let i = 0; i < this.animationClip.tracks.length; i++ ) {
|
|
2578
|
+
let track = this.animationClip.tracks[i];
|
|
2579
|
+
let t = {
|
|
2580
|
+
'id': track.name ?? "Track_" + track.idx.toString(),
|
|
2581
|
+
'name': track.name,
|
|
2582
|
+
'skipVisibility': this.skipVisibility,
|
|
2583
|
+
'visible': track.active,
|
|
2584
|
+
'selected' : track.isSelected
|
|
2585
|
+
}
|
|
2586
|
+
|
|
2587
|
+
let tree = p.addTree(null, t, {filter: false, rename: false, draggable: false, onevent: (e) => {
|
|
2588
|
+
switch(e.type) {
|
|
2589
|
+
case LX.TreeEvent.NODE_SELECTED:
|
|
2590
|
+
this.selectTrack(e.node);
|
|
2591
|
+
break;
|
|
2592
|
+
case LX.TreeEvent.NODE_VISIBILITY:
|
|
2593
|
+
this.changeTrackVisibility(e.node, e.value);
|
|
2594
|
+
break;
|
|
2595
|
+
case LX.TreeEvent.NODE_CARETCHANGED:
|
|
2596
|
+
this.changeTrackDisplay(e.node, e.node.closed);
|
|
2597
|
+
break;
|
|
2598
|
+
}
|
|
2599
|
+
}});
|
|
2600
|
+
}
|
|
2601
|
+
}
|
|
2602
|
+
panel.attach(p.root)
|
|
2603
|
+
p.root.style.overflowY = "scroll";
|
|
2604
|
+
p.root.addEventListener("scroll", (e) => {
|
|
2605
|
+
this.currentScroll = e.currentTarget.scrollTop / (e.currentTarget.scrollHeight - e.currentTarget.clientHeight);
|
|
2606
|
+
})
|
|
2607
|
+
// for(let i = 0; i < this.animationClip.tracks.length; i++) {
|
|
2608
|
+
// let track = this.animationClip.tracks[i];
|
|
2609
|
+
// panel.addTitle(track.name + (track.type? '(' + track.type + ')' : ''));
|
|
2610
|
+
// }
|
|
2611
|
+
if(this.leftPanel.parent.root.classList.contains("hidden") || !this.root.root.parent)
|
|
2612
|
+
return;
|
|
2613
|
+
this.resizeCanvas([ this.root.root.clientWidth - this.leftPanel.root.clientWidth - 8, this.size[1]]);
|
|
2614
|
+
}
|
|
2615
|
+
|
|
2616
|
+
|
|
2617
|
+
/**
|
|
2618
|
+
* @method changeTrackVisibility
|
|
2619
|
+
* @param {id, parent, children, visible} trackInfo
|
|
2620
|
+
*/
|
|
2621
|
+
|
|
2622
|
+
changeTrackVisibility(trackInfo, visible) {
|
|
2623
|
+
let [name, type] = trackInfo.id.split(" (");
|
|
2624
|
+
if(type)
|
|
2625
|
+
type = type.replaceAll(")", "").replaceAll(" ", "");
|
|
2626
|
+
else {
|
|
2627
|
+
type = name;
|
|
2628
|
+
name = trackInfo.parent ? trackInfo.parent.id : trackInfo.id;
|
|
2424
2629
|
}
|
|
2630
|
+
let id = name.split("Track_")[1];
|
|
2631
|
+
trackInfo = {name, type};
|
|
2632
|
+
let track = this.animationClip.tracks[id];
|
|
2633
|
+
|
|
2634
|
+
track.active = visible;
|
|
2635
|
+
trackInfo = track;
|
|
2425
2636
|
|
|
2426
|
-
this.draw(
|
|
2427
|
-
|
|
2637
|
+
this.draw();
|
|
2638
|
+
if(this.onChangeTrackVisibility)
|
|
2639
|
+
this.onChangeTrackVisibility(trackInfo, visible);
|
|
2640
|
+
}
|
|
2641
|
+
|
|
2642
|
+
/**
|
|
2643
|
+
* @method selectTrack
|
|
2644
|
+
* @param {id, parent, children, visible} trackInfo
|
|
2645
|
+
*/
|
|
2646
|
+
|
|
2647
|
+
selectTrack( trackInfo) {
|
|
2648
|
+
this.unSelectAllTracks();
|
|
2649
|
+
|
|
2650
|
+
let [name, type] = trackInfo.id.split(" (");
|
|
2651
|
+
|
|
2652
|
+
if(type)
|
|
2653
|
+
type = type.replaceAll(")", "").replaceAll(" ", "");
|
|
2654
|
+
else {
|
|
2655
|
+
type = name;
|
|
2656
|
+
name = trackInfo.parent ? trackInfo.parent.id : trackInfo.id;
|
|
2657
|
+
}
|
|
2658
|
+
let id = name.split("Track_")[1];
|
|
2659
|
+
let track = this.animationClip.tracks[id];
|
|
2660
|
+
track.isSelected = true;
|
|
2661
|
+
|
|
2662
|
+
trackInfo = track;
|
|
2663
|
+
this.updateLeftPanel();
|
|
2664
|
+
if(this.onSelectTrack)
|
|
2665
|
+
this.onSelectTrack(trackInfo);
|
|
2666
|
+
}
|
|
2667
|
+
|
|
2668
|
+
unSelectAllTracks() {
|
|
2669
|
+
|
|
2670
|
+
for(let t = 0; t < this.animationClip.tracks.length; t++) {
|
|
2671
|
+
this.animationClip.tracks[t].isSelected = false;
|
|
2672
|
+
}
|
|
2428
2673
|
}
|
|
2429
2674
|
|
|
2430
2675
|
onMouseUp( e ) {
|
|
@@ -2478,7 +2723,7 @@ class ClipsTimeline extends Timeline {
|
|
|
2478
2723
|
this.boxSelectionStart = null;
|
|
2479
2724
|
this.boxSelectionEnd = null;
|
|
2480
2725
|
|
|
2481
|
-
|
|
2726
|
+
}
|
|
2482
2727
|
|
|
2483
2728
|
onMouseDown( e, time ) {
|
|
2484
2729
|
|
|
@@ -2496,26 +2741,26 @@ class ClipsTimeline extends Timeline {
|
|
|
2496
2741
|
|
|
2497
2742
|
let x = e.offsetX;
|
|
2498
2743
|
let selectedClips = [];
|
|
2499
|
-
if(this.lastClipsSelected.length){
|
|
2744
|
+
if(this.lastClipsSelected.length > 1) {
|
|
2500
2745
|
selectedClips = this.lastClipsSelected;
|
|
2501
2746
|
}
|
|
2502
|
-
else{
|
|
2747
|
+
else {
|
|
2503
2748
|
let clipIndex = this.getCurrentClip( track, this.xToTime( localX ), this.pixelsToSeconds * 5 );
|
|
2504
2749
|
if(clipIndex != undefined)
|
|
2505
2750
|
{
|
|
2506
2751
|
this.lastClipsSelected = selectedClips = [[track.idx, clipIndex]];
|
|
2507
|
-
}
|
|
2508
|
-
|
|
2752
|
+
}
|
|
2509
2753
|
}
|
|
2754
|
+
|
|
2510
2755
|
this.canvas.style.cursor = "grab";
|
|
2511
|
-
|
|
2756
|
+
this.timelineClickedClips = [];
|
|
2757
|
+
for(let i = 0; i < selectedClips.length; i++)
|
|
2512
2758
|
{
|
|
2513
2759
|
this.movingKeys = false
|
|
2514
2760
|
let [trackIndex, clipIndex] = selectedClips[i];
|
|
2515
2761
|
var clip = this.animationClip.tracks[trackIndex].clips[clipIndex];
|
|
2516
2762
|
|
|
2517
|
-
if(!this.timelineClickedClips)
|
|
2518
|
-
this.timelineClickedClips = [];
|
|
2763
|
+
//if(!this.timelineClickedClips)
|
|
2519
2764
|
if(this.timelineClickedClips.indexOf(clip) < 0) {
|
|
2520
2765
|
this.timelineClickedClips.push(clip);
|
|
2521
2766
|
|
|
@@ -2524,7 +2769,7 @@ class ClipsTimeline extends Timeline {
|
|
|
2524
2769
|
this.timelineClickedClipsTime.push(this.xToTime( localX ));
|
|
2525
2770
|
}
|
|
2526
2771
|
|
|
2527
|
-
|
|
2772
|
+
|
|
2528
2773
|
var endingX = this.timeToX( clip.start + clip.duration );
|
|
2529
2774
|
var distToStart = Math.abs( this.timeToX( clip.start ) - x );
|
|
2530
2775
|
var distToEnd = Math.abs( this.timeToX( clip.start + clip.duration ) - e.offsetX );
|
|
@@ -2535,7 +2780,7 @@ class ClipsTimeline extends Timeline {
|
|
|
2535
2780
|
//this.addUndoStep( "clip_modified", clip );
|
|
2536
2781
|
if( (e.ctrlKey && distToStart < 5) || (clip.fadein && Math.abs( this.timeToX( clip.start + clip.fadein ) - e.offsetX ) < 5) )
|
|
2537
2782
|
this.dragClipMode = "fadein";
|
|
2538
|
-
else if(
|
|
2783
|
+
else if(Math.abs( endingX - x ) < 5 ) {
|
|
2539
2784
|
this.dragClipMode = "duration";
|
|
2540
2785
|
this.canvas.style.cursor = "column-resize";
|
|
2541
2786
|
}
|
|
@@ -2564,6 +2809,14 @@ class ClipsTimeline extends Timeline {
|
|
|
2564
2809
|
if(this.onSelectClip)
|
|
2565
2810
|
this.onSelectClip(null);
|
|
2566
2811
|
}
|
|
2812
|
+
else if (track && (this.dragClipMode == "duration" || this.dragClipMode == "fadein" || this.dragClipMode == "fadeout" )) {
|
|
2813
|
+
let clips = this.getClipsInRange(track, time, time, 0.1);
|
|
2814
|
+
if(!clips) {
|
|
2815
|
+
return;
|
|
2816
|
+
}
|
|
2817
|
+
this.lastClipsSelected = [[track.idx, clips[0]]];
|
|
2818
|
+
this.timelineClickedClips = [track.clips[clips[0]]];
|
|
2819
|
+
}
|
|
2567
2820
|
}
|
|
2568
2821
|
|
|
2569
2822
|
onMouseMove( e, time ) {
|
|
@@ -2574,6 +2827,11 @@ class ClipsTimeline extends Timeline {
|
|
|
2574
2827
|
this.onSetTime( t );
|
|
2575
2828
|
}
|
|
2576
2829
|
|
|
2830
|
+
const removeHover = () => {
|
|
2831
|
+
if(this.lastHovered)
|
|
2832
|
+
this.animationClip.tracks[ this.lastHovered[0] ].hovered[ this.lastHovered[1] ] = undefined;
|
|
2833
|
+
};
|
|
2834
|
+
|
|
2577
2835
|
if(e.shiftKey) {
|
|
2578
2836
|
if(this.boxSelection) {
|
|
2579
2837
|
this.boxSelectionEnd = [localX,localY - this.topMargin];
|
|
@@ -2594,8 +2852,9 @@ class ClipsTimeline extends Timeline {
|
|
|
2594
2852
|
|
|
2595
2853
|
let trackIdx = this.lastClipsSelected[i][0];
|
|
2596
2854
|
let clipIdx = this.lastClipsSelected[i][1];
|
|
2597
|
-
|
|
2598
|
-
|
|
2855
|
+
let clip = this.timelineClickedClips[i];
|
|
2856
|
+
let diff = clip.start + delta < 0 ? - clip.start : delta;//this.currentTime - this.timelineClickedClipsTime[i];//delta;
|
|
2857
|
+
|
|
2599
2858
|
if( this.dragClipMode == "move" ) {
|
|
2600
2859
|
let clipsInRange = this.getClipsInRange(this.animationClip.tracks[trackIdx], clip.start+diff, clip.start + clip.duration + diff, 0.01)
|
|
2601
2860
|
if(clipsInRange && clipsInRange[0] != clipIdx)
|
|
@@ -2605,6 +2864,7 @@ class ClipsTimeline extends Timeline {
|
|
|
2605
2864
|
clip.fadein += diff;
|
|
2606
2865
|
if(clip.fadeout != undefined)
|
|
2607
2866
|
clip.fadeout += diff;
|
|
2867
|
+
|
|
2608
2868
|
this.canvas.style.cursor = "grabbing";
|
|
2609
2869
|
|
|
2610
2870
|
if( this.timelineClickedClips.length == 1 && e.track && e.movementY != 0) {
|
|
@@ -2623,41 +2883,94 @@ class ClipsTimeline extends Timeline {
|
|
|
2623
2883
|
}
|
|
2624
2884
|
// }
|
|
2625
2885
|
}
|
|
2626
|
-
if(this.onContentMoved) {
|
|
2627
|
-
|
|
2628
|
-
}
|
|
2886
|
+
// if(this.onContentMoved) {
|
|
2887
|
+
// this.onContentMoved(clip, diff);
|
|
2888
|
+
// }
|
|
2629
2889
|
}
|
|
2630
|
-
else if( this.dragClipMode == "fadein" )
|
|
2890
|
+
else if( this.dragClipMode == "fadein" ) {
|
|
2631
2891
|
clip.fadein = Math.min(Math.max((clip.fadein || 0) + delta, clip.start), clip.start+clip.duration);
|
|
2632
|
-
|
|
2892
|
+
diff = 0;
|
|
2893
|
+
}
|
|
2894
|
+
else if( this.dragClipMode == "fadeout" ) {
|
|
2633
2895
|
clip.fadeout = Math.max(Math.min((clip.fadeout || clip.start+clip.duration) + delta, clip.start+clip.duration), clip.start);
|
|
2896
|
+
diff = 0;
|
|
2897
|
+
}
|
|
2634
2898
|
else if( this.dragClipMode == "duration" ) {
|
|
2635
2899
|
clip.duration += delta;
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2900
|
+
// if(delta < 0) {
|
|
2901
|
+
// clip.fadein = Math.min(Math.max((clip.fadein || 0) + delta, clip.start), clip.start+clip.duration);
|
|
2902
|
+
// }
|
|
2903
|
+
clip.fadeout = Math.max(Math.min((clip.fadeout || clip.start+clip.duration) + delta, clip.start+clip.duration), clip.start);
|
|
2904
|
+
diff = 0;
|
|
2905
|
+
// if(this.onContentMoved) {
|
|
2906
|
+
// this.onContentMoved(clip, 0);
|
|
2907
|
+
// }
|
|
2640
2908
|
}
|
|
2641
2909
|
|
|
2642
2910
|
if(this.duration < clip.start + clip.duration )
|
|
2643
2911
|
{
|
|
2644
2912
|
this.setDuration(clip.start + clip.duration);
|
|
2645
2913
|
}
|
|
2914
|
+
if(this.onContentMoved) {
|
|
2915
|
+
this.onContentMoved(clip, diff);
|
|
2916
|
+
}
|
|
2646
2917
|
}
|
|
2918
|
+
|
|
2647
2919
|
return true;
|
|
2648
2920
|
}
|
|
2649
2921
|
else{
|
|
2650
2922
|
innerSetTime( this.currentTime );
|
|
2651
2923
|
}
|
|
2652
2924
|
}
|
|
2653
|
-
else if(e.track && e.ctrlKey) {
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2925
|
+
// else if(e.track && e.ctrlKey) {
|
|
2926
|
+
// for(let i = 0; i < e.track.clips.length; i++) {
|
|
2927
|
+
// let clip = e.track.clips[i];
|
|
2928
|
+
// const x = this.timeToX(clip.start+clip.duration);
|
|
2929
|
+
// if(Math.abs(e.localX - x) < 5)
|
|
2930
|
+
// this.canvas.style.cursor = "col-resize";
|
|
2931
|
+
// }
|
|
2932
|
+
// }
|
|
2933
|
+
else if(e.track) {
|
|
2934
|
+
|
|
2935
|
+
let clips = this.getClipsInRange(e.track, time, time, 0.1)
|
|
2936
|
+
if(!e.track.locked && clips != undefined) {
|
|
2937
|
+
|
|
2938
|
+
removeHover();
|
|
2939
|
+
this.lastHovered = [e.track.idx, clips[0]];
|
|
2940
|
+
e.track.hovered[clips[0]] = true;
|
|
2941
|
+
|
|
2942
|
+
let clip = e.track.clips[clips[0]];
|
|
2943
|
+
if(!clip) {
|
|
2944
|
+
return;
|
|
2945
|
+
}
|
|
2946
|
+
|
|
2947
|
+
const durationX = this.timeToX(clip.start + clip.duration);
|
|
2948
|
+
const fadeinX = this.timeToX(clip.fadein);
|
|
2949
|
+
const fadeoutX = this.timeToX(clip.fadeout);
|
|
2950
|
+
if(Math.abs(e.localX - durationX) < 8) {
|
|
2658
2951
|
this.canvas.style.cursor = "col-resize";
|
|
2952
|
+
this.dragClipMode = "duration";
|
|
2953
|
+
}
|
|
2954
|
+
else if(Math.abs(e.localX - fadeinX) < 8) {
|
|
2955
|
+
this.canvas.style.cursor = "e-resize";
|
|
2956
|
+
this.dragClipMode = "fadein";
|
|
2957
|
+
}
|
|
2958
|
+
else if(Math.abs(e.localX - fadeoutX) < 8) {
|
|
2959
|
+
this.canvas.style.cursor = "e-resize";
|
|
2960
|
+
this.dragClipMode = "fadeout";
|
|
2961
|
+
}
|
|
2962
|
+
else {
|
|
2963
|
+
this.dragClipMode = "";
|
|
2964
|
+
}
|
|
2965
|
+
}
|
|
2966
|
+
else {
|
|
2967
|
+
removeHover();
|
|
2659
2968
|
}
|
|
2660
2969
|
}
|
|
2970
|
+
else {
|
|
2971
|
+
removeHover();
|
|
2972
|
+
}
|
|
2973
|
+
|
|
2661
2974
|
}
|
|
2662
2975
|
|
|
2663
2976
|
onDblClick( e ) {
|
|
@@ -2749,30 +3062,35 @@ class ClipsTimeline extends Timeline {
|
|
|
2749
3062
|
this.tracksPerItem = {};
|
|
2750
3063
|
this.tracksDictionary = {};
|
|
2751
3064
|
this.animationClip = {
|
|
2752
|
-
name: animation.name,
|
|
2753
|
-
duration: animation.duration,
|
|
2754
|
-
speed: animation.speed
|
|
3065
|
+
name: (animation && animation.name) ? animation.name : "animationClip",
|
|
3066
|
+
duration: animation ? animation.duration : 0,
|
|
3067
|
+
speed: (animation && animation.speed ) ? animation.speed : this.speed,
|
|
2755
3068
|
tracks: []
|
|
2756
3069
|
};
|
|
2757
3070
|
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
3071
|
+
if (animation && animation.tracks){
|
|
3072
|
+
for( let i = 0; i < animation.tracks.length; ++i ) {
|
|
3073
|
+
|
|
3074
|
+
let track = animation.tracks[i];
|
|
3075
|
+
|
|
3076
|
+
const name = track.name;
|
|
3077
|
+
const type = track.type;
|
|
3078
|
+
|
|
3079
|
+
let trackInfo = {
|
|
3080
|
+
fullname: track.name,
|
|
3081
|
+
clips: track.clips,
|
|
3082
|
+
name: name, type: type,
|
|
3083
|
+
selected: [], edited: [], hovered: [], active: true,
|
|
3084
|
+
times: track.times,
|
|
3085
|
+
};
|
|
3086
|
+
|
|
3087
|
+
this.tracksDictionary[track.name] = name;
|
|
3088
|
+
|
|
3089
|
+
this.animationClip.tracks.push(trackInfo);
|
|
3090
|
+
}
|
|
3091
|
+
}
|
|
3092
|
+
else {
|
|
3093
|
+
this.addNewTrack();
|
|
2776
3094
|
}
|
|
2777
3095
|
}
|
|
2778
3096
|
|
|
@@ -2845,14 +3163,21 @@ class ClipsTimeline extends Timeline {
|
|
|
2845
3163
|
let newStart = this.currentTime + offsetTime + clip.start;
|
|
2846
3164
|
if(clip.fadein != undefined)
|
|
2847
3165
|
clip.fadein += (newStart - clip.start);
|
|
3166
|
+
else
|
|
3167
|
+
clip.fadein = 0;
|
|
3168
|
+
|
|
2848
3169
|
if(clip.fadeout != undefined)
|
|
2849
3170
|
clip.fadeout += (newStart - clip.start);
|
|
3171
|
+
else
|
|
3172
|
+
clip.fadeout = clip.duration;
|
|
3173
|
+
|
|
2850
3174
|
clip.start = newStart;
|
|
2851
3175
|
|
|
2852
3176
|
// Time slot with other clip?
|
|
2853
3177
|
let clipInCurrentSlot = null;
|
|
2854
|
-
if(!this.animationClip)
|
|
3178
|
+
if(!this.animationClip || !this.animationClip.tracks || !this.animationClip.tracks.length) {
|
|
2855
3179
|
this.addNewTrack();
|
|
3180
|
+
}
|
|
2856
3181
|
|
|
2857
3182
|
for(let i = 0; i < this.animationClip.tracks.length; i++) {
|
|
2858
3183
|
clipInCurrentSlot = this.animationClip.tracks[i].clips.find( t => {
|
|
@@ -3008,7 +3333,7 @@ class ClipsTimeline extends Timeline {
|
|
|
3008
3333
|
*/
|
|
3009
3334
|
addClips( clips, offsetTime = 0, callback = null ) {
|
|
3010
3335
|
|
|
3011
|
-
if(!this.animationClip)
|
|
3336
|
+
if(!this.animationClip || !this.animationClip.tracks || !this.animationClip.tracks.length)
|
|
3012
3337
|
this.addNewTrack();
|
|
3013
3338
|
|
|
3014
3339
|
//Search track where to place each new clip
|
|
@@ -3037,7 +3362,7 @@ class ClipsTimeline extends Timeline {
|
|
|
3037
3362
|
if(!this.animationClip.tracks[i+1]) {
|
|
3038
3363
|
this.addNewTrack();
|
|
3039
3364
|
|
|
3040
|
-
trackIdxs[c] = {trackIdx: i+1,
|
|
3365
|
+
trackIdxs[c] = {trackIdx: i+1, start: newStart, end: newStart + clip.duration};
|
|
3041
3366
|
}
|
|
3042
3367
|
else {
|
|
3043
3368
|
|
|
@@ -3288,15 +3613,16 @@ class ClipsTimeline extends Timeline {
|
|
|
3288
3613
|
addNewTrack() {
|
|
3289
3614
|
|
|
3290
3615
|
if(!this.animationClip)
|
|
3291
|
-
this.animationClip = {tracks:[]};
|
|
3616
|
+
this.animationClip = {duration:0, tracks:[]};
|
|
3292
3617
|
|
|
3293
3618
|
let trackInfo = {
|
|
3294
3619
|
idx: this.animationClip.tracks.length,
|
|
3295
3620
|
clips: [],
|
|
3296
|
-
selected: [], edited: [], hovered: []
|
|
3621
|
+
selected: [], edited: [], hovered: [], active: true
|
|
3297
3622
|
};
|
|
3298
3623
|
|
|
3299
3624
|
this.animationClip.tracks.push(trackInfo);
|
|
3625
|
+
this.updateLeftPanel();
|
|
3300
3626
|
return trackInfo.idx;
|
|
3301
3627
|
}
|
|
3302
3628
|
|
|
@@ -3456,15 +3782,32 @@ class ClipsTimeline extends Timeline {
|
|
|
3456
3782
|
|
|
3457
3783
|
let indices = [];
|
|
3458
3784
|
|
|
3785
|
+
// for(let i = 0; i < track.clips.length; ++i) {
|
|
3786
|
+
// let t = track.clips[i];
|
|
3787
|
+
// if((t.start + t.duration <= (maxTime + threshold) || t.start <= (maxTime + threshold)) &&
|
|
3788
|
+
// (t.start + t.duration >= (minTime - threshold) || t.start >= (minTime - threshold)) )
|
|
3789
|
+
// {
|
|
3790
|
+
// indices.push(i);
|
|
3791
|
+
// }
|
|
3792
|
+
// }
|
|
3793
|
+
|
|
3459
3794
|
for(let i = 0; i < track.clips.length; ++i) {
|
|
3460
3795
|
let t = track.clips[i];
|
|
3461
|
-
if(
|
|
3462
|
-
(
|
|
3796
|
+
if( (minTime - threshold >= t.start) &&
|
|
3797
|
+
(minTime - threshold <= t.start + t.duration) ||
|
|
3798
|
+
(minTime + threshold >= t.start) &&
|
|
3799
|
+
(minTime + threshold <= t.start + t.duration) ||
|
|
3800
|
+
(maxTime - threshold >= t.start) &&
|
|
3801
|
+
(maxTime - threshold <= t.start + t.duration) ||
|
|
3802
|
+
(maxTime + threshold >= t.start) &&
|
|
3803
|
+
(maxTime + threshold <= t.start + t.duration) ||
|
|
3804
|
+
(minTime - threshold <= t.start || minTime + threshold <= t.start) &&
|
|
3805
|
+
(maxTime - threshold >= t.start + t.duration || maxTime + threshold >= t.start + t.duration)
|
|
3806
|
+
)
|
|
3463
3807
|
{
|
|
3464
3808
|
indices.push(i);
|
|
3465
3809
|
}
|
|
3466
3810
|
}
|
|
3467
|
-
|
|
3468
3811
|
return indices;
|
|
3469
3812
|
}
|
|
3470
3813
|
|
|
@@ -3558,22 +3901,7 @@ class CurvesTimeline extends Timeline {
|
|
|
3558
3901
|
if(!discard && track) {
|
|
3559
3902
|
this.processCurrentKeyFrame( e, null, track, localX );
|
|
3560
3903
|
|
|
3561
|
-
}
|
|
3562
|
-
else {
|
|
3563
|
-
let x = e.offsetX;
|
|
3564
|
-
let y = e.offsetY - this.topMargin;
|
|
3565
|
-
for( const b of this.buttonsDrawn ) {
|
|
3566
|
-
b.pressed = false;
|
|
3567
|
-
const bActive = x >= b[2] && x <= (b[2] + b[4]) && y >= b[3] && y <= (b[3] + b[5]);
|
|
3568
|
-
if(bActive) {
|
|
3569
|
-
const callback = b[6];
|
|
3570
|
-
if(callback) callback(e);
|
|
3571
|
-
else this[ b[1] ] = !this[ b[1] ];
|
|
3572
|
-
break;
|
|
3573
|
-
}
|
|
3574
|
-
}
|
|
3575
|
-
}
|
|
3576
|
-
|
|
3904
|
+
}
|
|
3577
3905
|
}
|
|
3578
3906
|
|
|
3579
3907
|
this.boxSelection = false;
|
|
@@ -3589,7 +3917,6 @@ class CurvesTimeline extends Timeline {
|
|
|
3589
3917
|
let track = e.track;
|
|
3590
3918
|
|
|
3591
3919
|
if(e.shiftKey) {
|
|
3592
|
-
|
|
3593
3920
|
this.boxSelection = true;
|
|
3594
3921
|
this.boxSelectionStart = [localX, localY - this.topMargin];
|
|
3595
3922
|
e.multipleSelection = true;
|
|
@@ -3617,13 +3944,7 @@ class CurvesTimeline extends Timeline {
|
|
|
3617
3944
|
}
|
|
3618
3945
|
}
|
|
3619
3946
|
else if(!track) {
|
|
3620
|
-
this.unSelectAllKeyFrames()
|
|
3621
|
-
let x = e.offsetX;
|
|
3622
|
-
let y = e.offsetY - this.topMargin;
|
|
3623
|
-
for( const b of this.buttonsDrawn ) {
|
|
3624
|
-
const bActive = x >= b[2] && x <= (b[2] + b[4]) && y >= b[3] && y <= (b[3] + b[5]);
|
|
3625
|
-
b.pressed = bActive;
|
|
3626
|
-
}
|
|
3947
|
+
this.unSelectAllKeyFrames()
|
|
3627
3948
|
}
|
|
3628
3949
|
}
|
|
3629
3950
|
|
|
@@ -3824,11 +4145,12 @@ class CurvesTimeline extends Timeline {
|
|
|
3824
4145
|
let values = track.values;
|
|
3825
4146
|
|
|
3826
4147
|
if(keyframes) {
|
|
3827
|
-
|
|
3828
|
-
ctx.fillStyle = "#2c303570";
|
|
4148
|
+
ctx.globalAlpha = 0.2;
|
|
4149
|
+
ctx.fillStyle = Timeline.TRACK_SELECTED_LIGHT//"#2c303570";
|
|
3829
4150
|
if(trackInfo.isSelected)
|
|
3830
4151
|
ctx.fillRect(0, y - 3, ctx.canvas.width, trackHeight );
|
|
3831
4152
|
|
|
4153
|
+
ctx.globalAlpha = 1;
|
|
3832
4154
|
this.tracksDrawn.push([track,y+this.topMargin,trackHeight]);
|
|
3833
4155
|
|
|
3834
4156
|
//draw lines
|
|
@@ -3957,43 +4279,47 @@ class CurvesTimeline extends Timeline {
|
|
|
3957
4279
|
this.tracksPerItem = {};
|
|
3958
4280
|
this.tracksDictionary = {};
|
|
3959
4281
|
this.animationClip = {
|
|
3960
|
-
name: animation.name,
|
|
3961
|
-
duration: animation.duration,
|
|
3962
|
-
speed: animation.speed
|
|
4282
|
+
name: (animation && animation.name) ? animation.name : "animationClip",
|
|
4283
|
+
duration: animation ? animation.duration : 0,
|
|
4284
|
+
speed: (animation && animation.speed ) ? animation.speed : this.speed,
|
|
3963
4285
|
tracks: []
|
|
3964
4286
|
};
|
|
3965
|
-
for( let i = 0; i < animation.tracks.length; ++i ) {
|
|
3966
|
-
|
|
3967
|
-
let track = animation.tracks[i];
|
|
3968
4287
|
|
|
3969
|
-
|
|
4288
|
+
if (animation && animation.tracks) {
|
|
3970
4289
|
|
|
3971
|
-
let
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
|
|
4290
|
+
for( let i = 0; i < animation.tracks.length; ++i ) {
|
|
4291
|
+
|
|
4292
|
+
let track = animation.tracks[i];
|
|
4293
|
+
|
|
4294
|
+
const [name, type] = this.getTrackName(track.name);
|
|
4295
|
+
|
|
4296
|
+
let trackInfo = {
|
|
4297
|
+
fullname: track.name,
|
|
4298
|
+
name: name, type: type,
|
|
4299
|
+
dim: track.values.length/track.times.length,
|
|
4300
|
+
selected: [], edited: [], hovered: [], active: true,
|
|
4301
|
+
values: track.values,
|
|
4302
|
+
times: track.times
|
|
4303
|
+
|
|
4304
|
+
};
|
|
4305
|
+
|
|
4306
|
+
if(!this.tracksPerItem[name]) {
|
|
4307
|
+
this.tracksPerItem[name] = [trackInfo];
|
|
4308
|
+
}else {
|
|
4309
|
+
this.tracksPerItem[name].push( trackInfo );
|
|
4310
|
+
}
|
|
4311
|
+
|
|
4312
|
+
|
|
4313
|
+
const trackIndex = this.tracksPerItem[name].length - 1;
|
|
4314
|
+
this.tracksPerItem[name][trackIndex].idx = trackIndex;
|
|
4315
|
+
this.tracksPerItem[name][trackIndex].clipIdx = i;
|
|
4316
|
+
|
|
4317
|
+
// Save index also in original track
|
|
4318
|
+
trackInfo.idx = trackIndex;
|
|
4319
|
+
this.tracksDictionary[track.name] = name;
|
|
4320
|
+
this.animationClip.tracks.push(trackInfo);
|
|
3978
4321
|
|
|
3979
|
-
};
|
|
3980
|
-
|
|
3981
|
-
if(!this.tracksPerItem[name]) {
|
|
3982
|
-
this.tracksPerItem[name] = [trackInfo];
|
|
3983
|
-
}else {
|
|
3984
|
-
this.tracksPerItem[name].push( trackInfo );
|
|
3985
4322
|
}
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
const trackIndex = this.tracksPerItem[name].length - 1;
|
|
3989
|
-
this.tracksPerItem[name][trackIndex].idx = trackIndex;
|
|
3990
|
-
this.tracksPerItem[name][trackIndex].clipIdx = i;
|
|
3991
|
-
|
|
3992
|
-
// Save index also in original track
|
|
3993
|
-
trackInfo.idx = trackIndex;
|
|
3994
|
-
this.tracksDictionary[track.name] = name;
|
|
3995
|
-
this.animationClip.tracks.push(trackInfo);
|
|
3996
|
-
|
|
3997
4323
|
}
|
|
3998
4324
|
}
|
|
3999
4325
|
|