lexgui 0.1.40 → 0.1.42
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 +63 -26
- package/build/components/codeeditor.js +91 -35
- package/build/components/imui.js +1 -1
- package/build/components/nodegraph.js +2 -2
- package/build/components/timeline.js +223 -160
- package/build/lexgui.css +65 -1
- package/build/lexgui.js +466 -262
- package/build/lexgui.module.js +466 -261
- package/changelog.md +33 -2
- package/demo.js +12 -12
- package/examples/asset_view.html +13 -9
- package/examples/code_editor.html +8 -6
- package/package.json +1 -1
|
@@ -15,7 +15,7 @@ class Session {
|
|
|
15
15
|
|
|
16
16
|
constructor() {
|
|
17
17
|
|
|
18
|
-
this.start_time = -
|
|
18
|
+
this.start_time = -0.01;
|
|
19
19
|
this.left_margin = 0;
|
|
20
20
|
// this.current_time = 0;
|
|
21
21
|
// this.last_time = 0;
|
|
@@ -62,7 +62,7 @@ class Timeline {
|
|
|
62
62
|
this.onBeforeCreateTopBar = options.onBeforeCreateTopBar;
|
|
63
63
|
this.onAfterCreateTopBar = options.onAfterCreateTopBar;
|
|
64
64
|
this.onChangePlayMode = options.onChangePlayMode;
|
|
65
|
-
this.
|
|
65
|
+
this.onShowConfiguration = options.onShowConfiguration;
|
|
66
66
|
this.onBeforeDrawContent = options.onBeforeDrawContent;
|
|
67
67
|
|
|
68
68
|
this.playing = false;
|
|
@@ -74,8 +74,8 @@ class Timeline {
|
|
|
74
74
|
|
|
75
75
|
this.duration = 1;
|
|
76
76
|
this.speed = 1;
|
|
77
|
-
this.position = [0, 0];
|
|
78
|
-
this.size = [ options.width ?? 400, options.height ?? 100];
|
|
77
|
+
this.position = [ 0, 0 ];
|
|
78
|
+
this.size = [ options.width ?? 400, options.height ?? 100 ];
|
|
79
79
|
|
|
80
80
|
this.currentScroll = 0; //in percentage
|
|
81
81
|
this.currentScrollInPixels = 0; //in pixels
|
|
@@ -107,17 +107,17 @@ class Timeline {
|
|
|
107
107
|
let height = options.height ? options.height - this.header_offset : null;
|
|
108
108
|
|
|
109
109
|
let area = new LX.Area( {id: "bottom-timeline-area", width: width || "calc(100% - 7px)", height: height || "100%"});
|
|
110
|
-
area.split({ type: "horizontal", sizes: ["15%", "85%"]});
|
|
110
|
+
area.split({ type: "horizontal", sizes: ["15%", "85%"] });
|
|
111
|
+
area.splitBar.style.zIndex = 1; // for some reason this is needed here
|
|
111
112
|
this.content_area = area;
|
|
112
|
-
let [left, right] = area.sections;
|
|
113
|
+
let [ left, right ] = area.sections;
|
|
113
114
|
|
|
114
|
-
|
|
115
|
-
right.root.appendChild(this.canvas);
|
|
115
|
+
right.root.appendChild( this.canvas );
|
|
116
116
|
this.canvasArea = right;
|
|
117
117
|
this.canvasArea.root.classList.add("lextimelinearea");
|
|
118
118
|
this.updateHeader();
|
|
119
|
-
this.updateLeftPanel(left);
|
|
120
|
-
this.root.root.appendChild(area.root);
|
|
119
|
+
this.updateLeftPanel( left );
|
|
120
|
+
this.root.root.appendChild( area.root );
|
|
121
121
|
|
|
122
122
|
if(!options.canvas && this.name != '') {
|
|
123
123
|
this.root.root.id = this.name;
|
|
@@ -151,35 +151,41 @@ class Timeline {
|
|
|
151
151
|
|
|
152
152
|
updateHeader() {
|
|
153
153
|
|
|
154
|
-
if(this.header)
|
|
154
|
+
if( this.header )
|
|
155
|
+
{
|
|
155
156
|
this.header.clear();
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
157
|
+
}
|
|
158
|
+
else
|
|
159
|
+
{
|
|
160
|
+
this.header = new LX.Panel( { id: 'lextimelineheader', height: this.header_offset + "px" } );
|
|
161
|
+
this.root.root.appendChild( this.header.root );
|
|
159
162
|
}
|
|
160
163
|
|
|
161
164
|
let header = this.header;
|
|
162
165
|
LX.DEFAULT_NAME_WIDTH = "50%";
|
|
163
166
|
header.sameLine();
|
|
164
167
|
|
|
165
|
-
if(this.name)
|
|
166
|
-
|
|
168
|
+
if( this.name )
|
|
169
|
+
{
|
|
170
|
+
header.addTitle(this.name );
|
|
167
171
|
}
|
|
168
172
|
|
|
169
173
|
header.addButton('', '<i class="fa-solid fa-'+ (this.playing ? 'pause' : 'play') +'"></i>', (value, event) => {
|
|
170
174
|
this.changeState();
|
|
171
|
-
}, {width: "40px", buttonClass: "accept"});
|
|
175
|
+
}, { width: "40px", buttonClass: "accept", title: "Play" });
|
|
172
176
|
|
|
173
|
-
header.addButton('', '<i class="fa-solid fa-rotate"></i>', (value, event) => {
|
|
177
|
+
header.addButton('', '<i class="fa-solid fa-rotate"></i>', ( value, event ) => {
|
|
174
178
|
this.loop = !this.loop;
|
|
175
|
-
if(this.onChangePlayMode)
|
|
176
|
-
|
|
179
|
+
if( this.onChangePlayMode )
|
|
180
|
+
{
|
|
181
|
+
this.onChangePlayMode( this.loop );
|
|
177
182
|
}
|
|
178
|
-
|
|
179
|
-
}, {width: "40px", selectable: true, selected: this.loop});
|
|
183
|
+
}, { width: "40px", selectable: true, selected: this.loop, title: 'Loop' });
|
|
180
184
|
|
|
181
|
-
if(this.onBeforeCreateTopBar)
|
|
182
|
-
|
|
185
|
+
if( this.onBeforeCreateTopBar )
|
|
186
|
+
{
|
|
187
|
+
this.onBeforeCreateTopBar( header );
|
|
188
|
+
}
|
|
183
189
|
|
|
184
190
|
header.addNumber("Current Time", this.currentTime, (value, event) => {
|
|
185
191
|
this.setTime(value)}, {signal: "@on_set_time_" + this.name, step: 0.01, min: 0, precision: 3, skipSlider: true});
|
|
@@ -191,29 +197,35 @@ class Timeline {
|
|
|
191
197
|
header.addNumber("Speed", + this.speed.toFixed(3), (value, event) => {
|
|
192
198
|
this.setSpeed(value)}, {step: 0.01, signal: "@on_set_speed_" + this.name});
|
|
193
199
|
|
|
194
|
-
if(this.onAfterCreateTopBar)
|
|
195
|
-
|
|
200
|
+
if( this.onAfterCreateTopBar )
|
|
201
|
+
{
|
|
202
|
+
this.onAfterCreateTopBar( header );
|
|
203
|
+
}
|
|
196
204
|
|
|
197
|
-
if(this.onShowOptimizeMenu)
|
|
198
|
-
|
|
205
|
+
if( this.onShowOptimizeMenu )
|
|
206
|
+
{
|
|
207
|
+
header.addButton("", '<i class="fa-solid fa-filter"></i>', (value, event) => {this.onShowOptimizeMenu(event)}, { width: "40px", title: "Optimize" });
|
|
208
|
+
}
|
|
199
209
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
this.configurationDialog
|
|
204
|
-
|
|
205
|
-
}
|
|
206
|
-
this.configurationDialog = new LX.Dialog("Configuration", d => {
|
|
207
|
-
if ( this.onConfiguration ){
|
|
208
|
-
this.onConfiguration(d);
|
|
209
|
-
}
|
|
210
|
-
}, {
|
|
211
|
-
onclose: (root) => {
|
|
212
|
-
root.remove();
|
|
210
|
+
if( this.onShowConfiguration )
|
|
211
|
+
{
|
|
212
|
+
header.addButton("", '<i class="fa-solid fa-gear"></i>', (value, event) => {
|
|
213
|
+
if(this.configurationDialog){
|
|
214
|
+
this.configurationDialog.close();
|
|
213
215
|
this.configurationDialog = null;
|
|
216
|
+
return;
|
|
214
217
|
}
|
|
215
|
-
|
|
216
|
-
|
|
218
|
+
this.configurationDialog = new LX.Dialog("Configuration", dialog => {
|
|
219
|
+
this.onShowConfiguration(dialog);
|
|
220
|
+
}, {
|
|
221
|
+
onclose: (root) => {
|
|
222
|
+
this.configurationDialog.panel.clear(); // clear signals
|
|
223
|
+
this.configurationDialog = null;
|
|
224
|
+
root.remove();
|
|
225
|
+
}
|
|
226
|
+
})
|
|
227
|
+
}, { width: "40px" })
|
|
228
|
+
}
|
|
217
229
|
|
|
218
230
|
header.endLine();
|
|
219
231
|
LX.DEFAULT_NAME_WIDTH = "30%";
|
|
@@ -223,46 +235,53 @@ class Timeline {
|
|
|
223
235
|
* @method updateLeftPanel
|
|
224
236
|
*
|
|
225
237
|
*/
|
|
226
|
-
updateLeftPanel(area) {
|
|
227
|
-
|
|
238
|
+
updateLeftPanel( area ) {
|
|
228
239
|
|
|
229
240
|
let scrollTop = 0;
|
|
230
|
-
if(this.leftPanel)
|
|
231
|
-
|
|
241
|
+
if( this.leftPanel )
|
|
242
|
+
{
|
|
243
|
+
scrollTop = this.leftPanel.root.children[ 1 ].scrollTop;
|
|
232
244
|
this.leftPanel.clear();
|
|
233
245
|
}
|
|
234
|
-
else
|
|
235
|
-
|
|
246
|
+
else
|
|
247
|
+
{
|
|
248
|
+
this.leftPanel = area.addPanel( { className: 'lextimelinepanel', width: "100%", height: "100%" } );
|
|
236
249
|
}
|
|
237
250
|
|
|
238
251
|
let panel = this.leftPanel;
|
|
239
|
-
panel.sameLine(2);
|
|
240
|
-
|
|
252
|
+
panel.sameLine( 2 );
|
|
253
|
+
|
|
254
|
+
let title = panel.addTitle( "Tracks" );
|
|
241
255
|
|
|
242
|
-
if(!this.disableNewTracks)
|
|
256
|
+
if( !this.disableNewTracks )
|
|
243
257
|
{
|
|
244
258
|
panel.addButton('', '<i class = "fa-solid fa-plus"></i>', (value, event) => {
|
|
245
259
|
this.addNewTrack();
|
|
246
260
|
}, {width: "40px", height: "40px"});
|
|
247
261
|
}
|
|
262
|
+
|
|
248
263
|
panel.endLine();
|
|
249
264
|
|
|
250
|
-
const styles = window.getComputedStyle(title);
|
|
265
|
+
const styles = window.getComputedStyle( title );
|
|
251
266
|
const titleHeight = title.clientHeight + parseFloat(styles['marginTop']) + parseFloat(styles['marginBottom']);
|
|
252
267
|
|
|
253
268
|
let p = new LX.Panel({height: "calc(100% - " + titleHeight + "px)"});
|
|
254
|
-
|
|
255
|
-
|
|
269
|
+
|
|
270
|
+
if( this.animationClip && this.selectedItems.length )
|
|
271
|
+
{
|
|
272
|
+
let items = { 'id': '', 'children': [] };
|
|
256
273
|
|
|
257
274
|
const tracksPerItem = this.animationClip.tracksPerItem;
|
|
258
|
-
for(let i = 0; i < this.selectedItems.length; i++ )
|
|
259
|
-
|
|
275
|
+
for( let i = 0; i < this.selectedItems.length; i++ )
|
|
276
|
+
{
|
|
277
|
+
let selected = this.selectedItems[ i ];
|
|
260
278
|
let t = {
|
|
261
279
|
'id': selected,
|
|
262
280
|
'skipVisibility': true,
|
|
263
281
|
'children': []
|
|
264
282
|
}
|
|
265
|
-
for(let j = 0; j < tracksPerItem[selected].length; j++)
|
|
283
|
+
for( let j = 0; j < tracksPerItem[selected].length; j++ )
|
|
284
|
+
{
|
|
266
285
|
let track = tracksPerItem[selected][j];
|
|
267
286
|
let id = track.type ? track.type : track.name;
|
|
268
287
|
|
|
@@ -299,7 +318,9 @@ class Timeline {
|
|
|
299
318
|
}]})
|
|
300
319
|
// panel.addTitle(track.name + (track.type? '(' + track.type + ')' : ''));
|
|
301
320
|
}
|
|
302
|
-
|
|
321
|
+
|
|
322
|
+
items.children.push( t );
|
|
323
|
+
|
|
303
324
|
let el = p.addTree(null, t, {filter: false, rename: false, draggable: false, onevent: (e) => {
|
|
304
325
|
switch(e.type) {
|
|
305
326
|
case LX.TreeEvent.NODE_SELECTED:
|
|
@@ -315,12 +336,14 @@ class Timeline {
|
|
|
315
336
|
}
|
|
316
337
|
break;
|
|
317
338
|
case LX.TreeEvent.NODE_VISIBILITY:
|
|
318
|
-
if (e.node.parent)
|
|
319
|
-
|
|
339
|
+
if ( e.node.parent )
|
|
340
|
+
{
|
|
341
|
+
const tracksInItem = this.animationClip.tracksPerItem[ e.node.parent.id ];
|
|
320
342
|
const type = e.node.id;
|
|
321
343
|
for(let i = 0; i < tracksInItem.length; i++) {
|
|
322
|
-
if(tracksInItem[i].type == type)
|
|
323
|
-
|
|
344
|
+
if(tracksInItem[i].type == type)
|
|
345
|
+
{
|
|
346
|
+
this.changeTrackVisibility( tracksInItem[ i ].clipIdx, e.value );
|
|
324
347
|
break;
|
|
325
348
|
}
|
|
326
349
|
}
|
|
@@ -328,8 +351,9 @@ class Timeline {
|
|
|
328
351
|
break;
|
|
329
352
|
case LX.TreeEvent.NODE_CARETCHANGED:
|
|
330
353
|
const tracksInItem = this.animationClip.tracksPerItem[e.node.id];
|
|
331
|
-
for( let i = 0; i < tracksInItem; ++i )
|
|
332
|
-
|
|
354
|
+
for( let i = 0; i < tracksInItem; ++i )
|
|
355
|
+
{
|
|
356
|
+
this.changeTrackDisplay( tracksInItem[ i ].clipIdx, e.node.closed );
|
|
333
357
|
}
|
|
334
358
|
break;
|
|
335
359
|
}
|
|
@@ -337,19 +361,23 @@ class Timeline {
|
|
|
337
361
|
|
|
338
362
|
}
|
|
339
363
|
}
|
|
340
|
-
|
|
364
|
+
|
|
365
|
+
panel.attach( p.root )
|
|
341
366
|
p.root.style.overflowY = "scroll";
|
|
342
|
-
p.root.addEventListener("scroll",
|
|
367
|
+
p.root.addEventListener("scroll", e => {
|
|
343
368
|
this.currentScroll = e.currentTarget.scrollTop/(e.currentTarget.scrollHeight - e.currentTarget.clientHeight);
|
|
344
|
-
|
|
369
|
+
});
|
|
345
370
|
// for(let i = 0; i < this.animationClip.tracks.length; i++) {
|
|
346
371
|
// let track = this.animationClip.tracks[i];
|
|
347
372
|
// panel.addTitle(track.name + (track.type? '(' + track.type + ')' : ''));
|
|
348
373
|
// }
|
|
349
|
-
this.leftPanel.root.children[1].scrollTop = scrollTop;
|
|
374
|
+
this.leftPanel.root.children[ 1 ].scrollTop = scrollTop;
|
|
350
375
|
|
|
351
|
-
if(this.leftPanel.parent.root.classList.contains("hidden") || !this.root.root.parent)
|
|
376
|
+
if( this.leftPanel.parent.root.classList.contains("hidden") || !this.root.root.parent )
|
|
377
|
+
{
|
|
352
378
|
return;
|
|
379
|
+
}
|
|
380
|
+
|
|
353
381
|
this.resizeCanvas([ this.root.root.clientWidth - this.leftPanel.root.clientWidth - 8, this.size[1]]);
|
|
354
382
|
}
|
|
355
383
|
|
|
@@ -359,8 +387,10 @@ class Timeline {
|
|
|
359
387
|
|
|
360
388
|
addNewTrack() {
|
|
361
389
|
|
|
362
|
-
if(!this.animationClip)
|
|
390
|
+
if( !this.animationClip )
|
|
391
|
+
{
|
|
363
392
|
this.animationClip = {tracks:[]};
|
|
393
|
+
}
|
|
364
394
|
|
|
365
395
|
let trackInfo = {
|
|
366
396
|
idx: this.animationClip.tracks.length,
|
|
@@ -368,7 +398,7 @@ class Timeline {
|
|
|
368
398
|
selected: [], edited: [], hovered: []
|
|
369
399
|
};
|
|
370
400
|
|
|
371
|
-
this.animationClip.tracks.push(trackInfo);
|
|
401
|
+
this.animationClip.tracks.push( trackInfo );
|
|
372
402
|
this.updateLeftPanel();
|
|
373
403
|
return trackInfo.idx;
|
|
374
404
|
}
|
|
@@ -378,30 +408,36 @@ class Timeline {
|
|
|
378
408
|
let tracks = [];
|
|
379
409
|
|
|
380
410
|
// Manage negative selection
|
|
381
|
-
if(minY > maxY)
|
|
411
|
+
if( minY > maxY )
|
|
412
|
+
{
|
|
382
413
|
let aux = minY;
|
|
383
414
|
minY = maxY;
|
|
384
415
|
maxY = aux;
|
|
385
416
|
}
|
|
386
417
|
|
|
387
|
-
for(let i = this.tracksDrawn.length - 1; i >= 0; --i)
|
|
388
|
-
|
|
389
|
-
let
|
|
418
|
+
for(let i = this.tracksDrawn.length - 1; i >= 0; --i)
|
|
419
|
+
{
|
|
420
|
+
let t = this.tracksDrawn[ i ];
|
|
421
|
+
let pos = t[ 1 ] - this.topMargin, size = t[ 2 ];
|
|
390
422
|
if( pos + threshold >= minY && (pos + size - threshold) <= maxY ) {
|
|
391
|
-
tracks.push( t[0] );
|
|
423
|
+
tracks.push( t[ 0 ] );
|
|
392
424
|
}
|
|
393
425
|
}
|
|
394
426
|
|
|
395
427
|
return tracks;
|
|
396
428
|
}
|
|
397
429
|
|
|
398
|
-
getCurrentContent(track, time, threshold) {
|
|
430
|
+
getCurrentContent( track, time, threshold ) {
|
|
399
431
|
|
|
400
|
-
if(this.getCurrentKeyFrame)
|
|
401
|
-
|
|
432
|
+
if( this.getCurrentKeyFrame )
|
|
433
|
+
{
|
|
434
|
+
return this.getCurrentKeyFrame( track, time, threshold );
|
|
435
|
+
}
|
|
402
436
|
|
|
403
|
-
if(this.getCurrentClip)
|
|
404
|
-
|
|
437
|
+
if( this.getCurrentClip )
|
|
438
|
+
{
|
|
439
|
+
return this.getCurrentClip( track, time, threshold );
|
|
440
|
+
}
|
|
405
441
|
}
|
|
406
442
|
|
|
407
443
|
/**
|
|
@@ -412,17 +448,21 @@ class Timeline {
|
|
|
412
448
|
* [KeyFrameTimeline] - each track should contain an attribute "dim" to indicate the value dimension (e.g. vector3 -> dim=3). Otherwise dimensions will be infered from track's values and times. Default is 1
|
|
413
449
|
*/
|
|
414
450
|
setAnimationClip( animation, needsToProcess = true ) {
|
|
415
|
-
|
|
451
|
+
|
|
452
|
+
if ( this.unSelectAllKeyFrames )
|
|
453
|
+
{
|
|
416
454
|
this.unSelectAllKeyFrames();
|
|
417
455
|
this.unHoverAll();
|
|
418
456
|
this.unSelectAllTracks();
|
|
419
457
|
this.selectedItems = [];
|
|
420
458
|
}
|
|
421
459
|
|
|
422
|
-
if(!animation || !animation.tracks || needsToProcess)
|
|
423
|
-
|
|
460
|
+
if( !animation || !animation.tracks || needsToProcess )
|
|
461
|
+
{
|
|
462
|
+
this.processTracks( animation ); // generate default animationclip or process the user's one
|
|
424
463
|
}
|
|
425
|
-
else
|
|
464
|
+
else
|
|
465
|
+
{
|
|
426
466
|
this.animationClip = animation;
|
|
427
467
|
}
|
|
428
468
|
|
|
@@ -431,12 +471,13 @@ class Timeline {
|
|
|
431
471
|
|
|
432
472
|
//this.updateHeader();
|
|
433
473
|
this.updateLeftPanel();
|
|
474
|
+
|
|
434
475
|
return this.animationClip;
|
|
435
476
|
}
|
|
436
477
|
|
|
437
|
-
drawTimeInfo
|
|
478
|
+
drawTimeInfo( w, h = this.topMargin ) {
|
|
438
479
|
|
|
439
|
-
let ctx = this.canvas.getContext("2d");
|
|
480
|
+
let ctx = this.canvas.getContext( "2d" );
|
|
440
481
|
ctx.font = "11px " + Timeline.FONT;//"11px Calibri";
|
|
441
482
|
ctx.textAlign = "center";
|
|
442
483
|
|
|
@@ -449,57 +490,57 @@ class Timeline {
|
|
|
449
490
|
ctx.strokeStyle = LX.Timeline.FONT_COLOR;
|
|
450
491
|
|
|
451
492
|
// set tick and sub tick times
|
|
452
|
-
let
|
|
453
|
-
if ( this.secondsToPixels > 900 ){
|
|
454
|
-
else if ( this.secondsToPixels > 100 ){
|
|
455
|
-
else if ( this.secondsToPixels > 50 ){
|
|
493
|
+
let tickTime = 4;
|
|
494
|
+
if ( this.secondsToPixels > 900 ) { tickTime = 1; }
|
|
495
|
+
else if ( this.secondsToPixels > 100 ) { tickTime = 2; }
|
|
496
|
+
else if ( this.secondsToPixels > 50 ) { tickTime = 3; }
|
|
456
497
|
|
|
457
|
-
let
|
|
458
|
-
|
|
498
|
+
let subtickTime = this.timeSeparators[tickTime - 1];
|
|
499
|
+
tickTime = this.timeSeparators[tickTime];
|
|
459
500
|
|
|
460
|
-
//
|
|
461
|
-
let
|
|
462
|
-
let
|
|
501
|
+
// Transform times into pixel coords
|
|
502
|
+
let tickX = this.timeToX( this.startTime + tickTime ) - this.timeToX( this.startTime );
|
|
503
|
+
let subtickX = subtickTime * tickX / tickTime;
|
|
463
504
|
|
|
464
|
-
let startx = this.timeToX( Math.floor( this.startTime /
|
|
505
|
+
let startx = this.timeToX( Math.floor( this.startTime / tickTime) * tickTime ); // floor because might need to draw previous subticks
|
|
465
506
|
let endx = this.timeToX( this.endTime ); // draw up to endTime
|
|
466
507
|
|
|
467
|
-
//
|
|
508
|
+
// Begin drawing
|
|
468
509
|
ctx.beginPath();
|
|
469
510
|
ctx.fillStyle = Timeline.FONT_COLOR//"#888";
|
|
470
511
|
ctx.globalAlpha = this.opacity;
|
|
471
512
|
|
|
472
|
-
for( let x = startx; x <= endx; x +=
|
|
473
|
-
|
|
474
|
-
//
|
|
475
|
-
ctx.moveTo(Math.round(x) + 0.5, h * 0.4 + h * 0.3 );
|
|
476
|
-
ctx.lineTo(Math.round(x) + 0.5, h * 0.95 );
|
|
477
|
-
|
|
478
|
-
//
|
|
479
|
-
let endsub = x +
|
|
480
|
-
for (let
|
|
481
|
-
|
|
482
|
-
ctx.
|
|
513
|
+
for( let x = startx; x <= endx; x += tickX )
|
|
514
|
+
{
|
|
515
|
+
// Draw main line
|
|
516
|
+
ctx.moveTo( Math.round( x ) + 0.5, h * 0.4 + h * 0.3 );
|
|
517
|
+
ctx.lineTo( Math.round( x ) + 0.5, h * 0.95 );
|
|
518
|
+
|
|
519
|
+
// Draw following sub lines
|
|
520
|
+
let endsub = x + tickX - subtickX * 0.5;
|
|
521
|
+
for ( let subX = x; subX < endsub && subX < endx; subX += subtickX )
|
|
522
|
+
{
|
|
523
|
+
ctx.moveTo( Math.round( subX ) + 0.5, h * 0.4 + h * 0.45 );
|
|
524
|
+
ctx.lineTo( Math.round( subX ) + 0.5, h * 0.95 );
|
|
483
525
|
}
|
|
484
526
|
|
|
485
|
-
//
|
|
527
|
+
// Draw time number
|
|
486
528
|
let t = this.xToTime( x );
|
|
487
|
-
ctx.fillText( t.toFixed(
|
|
529
|
+
ctx.fillText( t.toFixed( tickTime < 1 ? 1 : 0 ), x, h * 0.6 );
|
|
488
530
|
}
|
|
489
531
|
|
|
490
532
|
ctx.stroke();
|
|
491
|
-
|
|
492
|
-
|
|
493
533
|
ctx.restore();
|
|
494
534
|
}
|
|
495
535
|
|
|
496
|
-
drawTracksBackground(w, h) {
|
|
536
|
+
drawTracksBackground( w, h ) {
|
|
497
537
|
|
|
498
538
|
let canvas = this.canvas;
|
|
499
539
|
let ctx = canvas.getContext("2d");
|
|
500
540
|
let duration = this.duration;
|
|
501
541
|
ctx.globalAlpha = this.opacity;
|
|
502
|
-
|
|
542
|
+
|
|
543
|
+
// Content
|
|
503
544
|
let margin = this.session.left_margin;
|
|
504
545
|
let timeline_height = this.topMargin;
|
|
505
546
|
let line_height = this.trackHeight;
|
|
@@ -509,19 +550,14 @@ class Timeline {
|
|
|
509
550
|
let max_tracks = Math.ceil( (h - timeline_height + this.currentScrollInPixels) / line_height );
|
|
510
551
|
|
|
511
552
|
ctx.save();
|
|
512
|
-
ctx.fillStyle = Timeline.
|
|
513
|
-
|
|
553
|
+
ctx.fillStyle = "#f0f0f003"//Timeline.TRACK_COLOR_SECONDARY;
|
|
554
|
+
ctx.globalAlpha = 1;
|
|
555
|
+
for(let i = 0; i <= max_tracks; i+=2)
|
|
514
556
|
{
|
|
515
|
-
ctx.fillStyle = i % 2 == 0 ? Timeline.TRACK_COLOR_PRIMARY: Timeline.BACKGROUND_COLOR;
|
|
516
557
|
ctx.fillRect(0, timeline_height + i * line_height - this.currentScrollInPixels, w, line_height );
|
|
517
558
|
}
|
|
518
|
-
|
|
519
|
-
//black bg
|
|
520
|
-
ctx.globalAlpha = 0.7;
|
|
521
|
-
ctx.fillStyle = Timeline.BACKGROUND_COLOR;
|
|
522
|
-
ctx.fillRect( margin, 0, canvas.width - margin, canvas.height);
|
|
523
559
|
ctx.globalAlpha = this.opacity;
|
|
524
|
-
|
|
560
|
+
|
|
525
561
|
//bg lines
|
|
526
562
|
ctx.strokeStyle = "#444";
|
|
527
563
|
ctx.beginPath();
|
|
@@ -529,6 +565,7 @@ class Timeline {
|
|
|
529
565
|
let pos = this.timeToX( 0 );
|
|
530
566
|
if(pos < margin)
|
|
531
567
|
pos = margin;
|
|
568
|
+
ctx.lineWidth = 1;
|
|
532
569
|
ctx.moveTo( pos + 0.5, timeline_height);
|
|
533
570
|
ctx.lineTo( pos + 0.5, canvas.height);
|
|
534
571
|
ctx.moveTo( Math.round( this.timeToX( duration ) ) + 0.5, timeline_height);
|
|
@@ -704,7 +741,7 @@ class Timeline {
|
|
|
704
741
|
* @param {Number} t
|
|
705
742
|
*/
|
|
706
743
|
|
|
707
|
-
setDuration( t, updateHeader = true ) {
|
|
744
|
+
setDuration( t, updateHeader = true, skipCallback = false ) {
|
|
708
745
|
let v = this.validateDuration(t);
|
|
709
746
|
let decimals = t.toString().split('.')[1] ? t.toString().split('.')[1].length : 0;
|
|
710
747
|
updateHeader = (updateHeader || +v.toFixed(decimals) != t);
|
|
@@ -714,7 +751,7 @@ class Timeline {
|
|
|
714
751
|
LX.emit( "@on_set_duration_" + this.name, +this.duration.toFixed(3)); // skipcallback = true
|
|
715
752
|
}
|
|
716
753
|
|
|
717
|
-
if( this.onSetDuration )
|
|
754
|
+
if( this.onSetDuration && !skipCallback )
|
|
718
755
|
this.onSetDuration( this.duration );
|
|
719
756
|
}
|
|
720
757
|
|
|
@@ -733,19 +770,19 @@ class Timeline {
|
|
|
733
770
|
* @param {Number} speed
|
|
734
771
|
*/
|
|
735
772
|
|
|
736
|
-
setSpeed(speed) {
|
|
773
|
+
setSpeed(speed, skipCallback = false) {
|
|
737
774
|
this.speed = speed;
|
|
738
775
|
LX.emit( "@on_set_speed_" + this.name, +this.speed.toFixed(3)); // skipcallback = true
|
|
739
776
|
|
|
740
|
-
if( this.onSetSpeed )
|
|
777
|
+
if( this.onSetSpeed && !skipCallback)
|
|
741
778
|
this.onSetSpeed( this.speed );
|
|
742
779
|
}
|
|
743
780
|
|
|
744
|
-
setTime(time){
|
|
781
|
+
setTime(time, skipCallback = false ){
|
|
745
782
|
this.currentTime = Math.max(0,Math.min(time,this.duration));
|
|
746
783
|
LX.emit( "@on_set_time_" + this.name, +this.currentTime.toFixed(2)); // skipcallback = true
|
|
747
784
|
|
|
748
|
-
if(this.onSetTime)
|
|
785
|
+
if(this.onSetTime && !skipCallback)
|
|
749
786
|
this.onSetTime(this.currentTime);
|
|
750
787
|
}
|
|
751
788
|
|
|
@@ -832,6 +869,9 @@ class Timeline {
|
|
|
832
869
|
this.leftPanel.root.children[1].scrollTop += e.deltaY; // wheel deltaY
|
|
833
870
|
}
|
|
834
871
|
|
|
872
|
+
if ( this.onMouse ){
|
|
873
|
+
this.onMouse(e, time);
|
|
874
|
+
}
|
|
835
875
|
return;
|
|
836
876
|
}
|
|
837
877
|
|
|
@@ -969,8 +1009,8 @@ class Timeline {
|
|
|
969
1009
|
return true;
|
|
970
1010
|
}
|
|
971
1011
|
|
|
972
|
-
if( this.onMouse
|
|
973
|
-
|
|
1012
|
+
if( this.onMouse )
|
|
1013
|
+
this.onMouse( e, time, this );
|
|
974
1014
|
|
|
975
1015
|
return true;
|
|
976
1016
|
}
|
|
@@ -1159,21 +1199,38 @@ class Timeline {
|
|
|
1159
1199
|
* // NOTE: to select a track from outside of the timeline, a this.leftPanelTrackTree.select(item) needs to be called.
|
|
1160
1200
|
*/
|
|
1161
1201
|
selectTrack( trackIdx ) {
|
|
1202
|
+
|
|
1203
|
+
if( !this.animationClip )
|
|
1204
|
+
{
|
|
1205
|
+
return;
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1162
1208
|
this.unSelectAllTracks();
|
|
1163
1209
|
|
|
1164
|
-
let track = this.animationClip.tracks[trackIdx];
|
|
1210
|
+
let track = this.animationClip.tracks[ trackIdx ];
|
|
1165
1211
|
track.isSelected = true;
|
|
1166
1212
|
|
|
1167
|
-
if(this.onSelectTrack)
|
|
1213
|
+
if( this.onSelectTrack )
|
|
1214
|
+
{
|
|
1168
1215
|
this.onSelectTrack(track);
|
|
1216
|
+
}
|
|
1169
1217
|
}
|
|
1170
1218
|
|
|
1171
1219
|
unSelectAllTracks() {
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1220
|
+
|
|
1221
|
+
if( !this.animationClip )
|
|
1222
|
+
{
|
|
1223
|
+
return;
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
for(let i = 0; i < this.selectedItems.length; i++)
|
|
1227
|
+
{
|
|
1228
|
+
let item = this.selectedItems[ i ];
|
|
1229
|
+
let tracks = this.animationClip.tracksPerItem[ item ];
|
|
1230
|
+
|
|
1231
|
+
for( let t = 0; t < tracks.length; t++ )
|
|
1232
|
+
{
|
|
1233
|
+
tracks[ t ].isSelected = false;
|
|
1177
1234
|
}
|
|
1178
1235
|
}
|
|
1179
1236
|
}
|
|
@@ -2572,14 +2629,14 @@ class KeyFramesTimeline extends Timeline {
|
|
|
2572
2629
|
|
|
2573
2630
|
const currentSelection = this.selectKeyFrame(t, keyFrameIndex, !multiple); // changes time
|
|
2574
2631
|
|
|
2632
|
+
if( !multiple ) {
|
|
2633
|
+
this.setTime(this.animationClip.tracks[t.clipIdx].times[ keyFrameIndex ]);
|
|
2634
|
+
}
|
|
2575
2635
|
if( this.onSelectKeyFrame && this.onSelectKeyFrame(e, currentSelection)) {
|
|
2576
2636
|
// Event handled
|
|
2577
2637
|
return;
|
|
2578
2638
|
}
|
|
2579
|
-
|
|
2580
|
-
if( !multiple ) {
|
|
2581
|
-
this.setTime(this.animationClip.tracks[t.clipIdx].times[ keyFrameIndex ]);
|
|
2582
|
-
}
|
|
2639
|
+
|
|
2583
2640
|
}
|
|
2584
2641
|
|
|
2585
2642
|
/**
|
|
@@ -2605,7 +2662,6 @@ class KeyFramesTimeline extends Timeline {
|
|
|
2605
2662
|
/**
|
|
2606
2663
|
* @method clearTrack
|
|
2607
2664
|
*/
|
|
2608
|
-
|
|
2609
2665
|
clearTrack(idx, defaultValue) {
|
|
2610
2666
|
|
|
2611
2667
|
let track = this.animationClip.tracks[idx];
|
|
@@ -2615,11 +2671,14 @@ class KeyFramesTimeline extends Timeline {
|
|
|
2615
2671
|
return;
|
|
2616
2672
|
}
|
|
2617
2673
|
|
|
2674
|
+
this.unHoverAll();
|
|
2675
|
+
this.unSelectAllKeyFrames();
|
|
2676
|
+
|
|
2677
|
+
this.saveState(track.clipIdx);
|
|
2618
2678
|
const count = track.times.length;
|
|
2619
2679
|
for(let i = count - 1; i >= 0; i--)
|
|
2620
2680
|
{
|
|
2621
|
-
this
|
|
2622
|
-
this.#delete(track.clipIdx, i );
|
|
2681
|
+
this.#delete(track.clipIdx, i);
|
|
2623
2682
|
}
|
|
2624
2683
|
if(defaultValue != undefined) {
|
|
2625
2684
|
if(typeof(defaultValue) == 'number') {
|
|
@@ -2855,7 +2914,10 @@ class ClipsTimeline extends Timeline {
|
|
|
2855
2914
|
onMouseMove( e, time ) {
|
|
2856
2915
|
// function not called if shift is pressed (boxselection)
|
|
2857
2916
|
|
|
2858
|
-
if(this.
|
|
2917
|
+
if ( this.grabbingTimeBar || this.grabbingScroll ){
|
|
2918
|
+
return;
|
|
2919
|
+
}
|
|
2920
|
+
else if(this.grabbing && e.buttons != 2) {
|
|
2859
2921
|
this.unHoverAll();
|
|
2860
2922
|
|
|
2861
2923
|
let delta = time - this.grabTime;
|
|
@@ -2879,7 +2941,8 @@ class ClipsTimeline extends Timeline {
|
|
|
2879
2941
|
duration = Math.min( track.clips[this.lastClipsSelected[0][1] + 1].start - clip.start - 0.0001, duration );
|
|
2880
2942
|
}
|
|
2881
2943
|
clip.duration = duration;
|
|
2882
|
-
clip.fadeout = Math.max(Math.min((clip.fadeout
|
|
2944
|
+
clip.fadeout = Math.max(Math.min((clip.fadeout ?? (clip.start+clip.duration)) + delta, clip.start+clip.duration), clip.start);
|
|
2945
|
+
clip.fadein = Math.max(Math.min((clip.fadein ?? (clip.start+clip.duration)), (clip.fadeout ?? (clip.start+clip.duration))), clip.start);
|
|
2883
2946
|
if(this.duration < clip.start + clip.duration){
|
|
2884
2947
|
this.setDuration(clip.start + clip.duration);
|
|
2885
2948
|
}
|
|
@@ -3258,16 +3321,13 @@ class ClipsTimeline extends Timeline {
|
|
|
3258
3321
|
/**
|
|
3259
3322
|
* @method optimizeTrack
|
|
3260
3323
|
*/
|
|
3261
|
-
|
|
3262
3324
|
optimizeTrack(trackIdx) {
|
|
3263
3325
|
}
|
|
3264
3326
|
|
|
3265
3327
|
/**
|
|
3266
3328
|
* @method optimizeTracks
|
|
3267
3329
|
*/
|
|
3268
|
-
|
|
3269
3330
|
optimizeTracks() {
|
|
3270
|
-
this.addClip()
|
|
3271
3331
|
}
|
|
3272
3332
|
|
|
3273
3333
|
/**
|
|
@@ -5154,14 +5214,14 @@ class CurvesTimeline extends Timeline {
|
|
|
5154
5214
|
|
|
5155
5215
|
const currentSelection = this.selectKeyFrame(t, keyFrameIndex, !multiple, multiple); // changes time on the first keyframe selected
|
|
5156
5216
|
|
|
5217
|
+
if (!multiple){
|
|
5218
|
+
this.setTime(this.animationClip.tracks[t.clipIdx].times[ keyFrameIndex ]);
|
|
5219
|
+
}
|
|
5220
|
+
|
|
5157
5221
|
if( this.onSelectKeyFrame && this.onSelectKeyFrame(e, currentSelection)) {
|
|
5158
5222
|
// Event handled
|
|
5159
5223
|
return;
|
|
5160
5224
|
}
|
|
5161
|
-
|
|
5162
|
-
if (!multiple){
|
|
5163
|
-
this.setTime(this.animationClip.tracks[t.clipIdx].times[ keyFrameIndex ]);
|
|
5164
|
-
}
|
|
5165
5225
|
}
|
|
5166
5226
|
|
|
5167
5227
|
/**
|
|
@@ -5195,12 +5255,15 @@ class CurvesTimeline extends Timeline {
|
|
|
5195
5255
|
{
|
|
5196
5256
|
return;
|
|
5197
5257
|
}
|
|
5198
|
-
|
|
5258
|
+
|
|
5259
|
+
this.unHoverAll();
|
|
5260
|
+
this.unSelectAllKeyFrames();
|
|
5261
|
+
|
|
5262
|
+
this.saveState(track.clipIdx);
|
|
5199
5263
|
const count = track.times.length;
|
|
5200
5264
|
for(let i = count - 1; i >= 0; i--)
|
|
5201
5265
|
{
|
|
5202
|
-
this
|
|
5203
|
-
this.#delete(track, i );
|
|
5266
|
+
this.#delete(track.clipIdx, i );
|
|
5204
5267
|
}
|
|
5205
5268
|
if(defaultValue != undefined) {
|
|
5206
5269
|
if(typeof(defaultValue) == 'number') {
|
|
@@ -5292,4 +5355,4 @@ LX.UTILS.concatTypedArray = (arrays, ArrayType) => {
|
|
|
5292
5355
|
return result;
|
|
5293
5356
|
}
|
|
5294
5357
|
|
|
5295
|
-
export { Timeline, KeyFramesTimeline, ClipsTimeline, CurvesTimeline };
|
|
5358
|
+
export { Timeline, KeyFramesTimeline, ClipsTimeline, CurvesTimeline };
|