lexgui 8.0.0 → 8.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/README.md +3 -3
  2. package/build/components/AlertDialog.d.ts +7 -0
  3. package/build/components/Counter.d.ts +1 -0
  4. package/build/components/Dialog.d.ts +1 -1
  5. package/build/components/Footer.d.ts +1 -1
  6. package/build/components/Menubar.d.ts +2 -2
  7. package/build/core/Area.d.ts +22 -22
  8. package/build/core/Namespace.js +34 -34
  9. package/build/core/Namespace.js.map +1 -1
  10. package/build/core/Panel.d.ts +2 -3
  11. package/build/extensions/AssetView.d.ts +136 -134
  12. package/build/extensions/AssetView.js +1367 -1320
  13. package/build/extensions/AssetView.js.map +1 -1
  14. package/build/extensions/Audio.js +19 -19
  15. package/build/extensions/Audio.js.map +1 -1
  16. package/build/extensions/CodeEditor.js +867 -647
  17. package/build/extensions/CodeEditor.js.map +1 -1
  18. package/build/extensions/DocMaker.d.ts +1 -1
  19. package/build/extensions/DocMaker.js +73 -61
  20. package/build/extensions/DocMaker.js.map +1 -1
  21. package/build/extensions/GraphEditor.js +406 -305
  22. package/build/extensions/GraphEditor.js.map +1 -1
  23. package/build/extensions/ImUi.js +21 -20
  24. package/build/extensions/ImUi.js.map +1 -1
  25. package/build/extensions/Timeline.d.ts +29 -36
  26. package/build/extensions/Timeline.js +421 -424
  27. package/build/extensions/Timeline.js.map +1 -1
  28. package/build/extensions/VideoEditor.js +101 -97
  29. package/build/extensions/VideoEditor.js.map +1 -1
  30. package/build/extensions/index.d.ts +8 -8
  31. package/build/extensions/index.js +1 -1
  32. package/build/index.all.d.ts +2 -2
  33. package/build/index.css.d.ts +1 -1
  34. package/build/index.d.ts +56 -55
  35. package/build/lexgui.all.js +28488 -27640
  36. package/build/lexgui.all.js.map +1 -1
  37. package/build/lexgui.all.min.js +1 -1
  38. package/build/lexgui.all.module.js +28412 -27565
  39. package/build/lexgui.all.module.js.map +1 -1
  40. package/build/lexgui.all.module.min.js +1 -1
  41. package/build/lexgui.css +176 -69
  42. package/build/lexgui.js +13796 -13330
  43. package/build/lexgui.js.map +1 -1
  44. package/build/lexgui.min.css +1 -1
  45. package/build/lexgui.min.js +1 -1
  46. package/build/lexgui.module.js +13733 -13268
  47. package/build/lexgui.module.js.map +1 -1
  48. package/build/lexgui.module.min.js +1 -1
  49. package/changelog.md +22 -1
  50. package/demo.js +6 -5
  51. package/examples/all-components.html +3 -0
  52. package/examples/asset-view.html +52 -6
  53. package/examples/dialogs.html +3 -3
  54. package/examples/editor.html +1 -1
  55. package/examples/index.html +1 -1
  56. package/package.json +4 -1
@@ -3,11 +3,11 @@ import { LX } from '../core/Namespace.js';
3
3
 
4
4
  // Timeline.ts @evallsg, @japopra
5
5
  if (!LX) {
6
- throw ("Missing LX namespace!");
6
+ throw ('Missing LX namespace!');
7
7
  }
8
8
  LX.extensions.push('Timeline');
9
- LX.registerIcon("TimelineLock", '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path fill="none" d="M7 11V7a4 4 0 0 1 9 0v4 M5,11h13 a2 2 0 0 1 2 2 v7 a2 2 0 0 1 -2 2 h-13 a2 2 0 0 1 -2 -2 v-7 a2 2 0 0 1 2 -2 M12 16 v2"/></svg>');
10
- LX.registerIcon("TimelineLockOpen", '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path fill="none" d="M14 11V7a4 4 0 0 1 9 0v2 M3,11h13 a2 2 0 0 1 2 2 v7 a2 2 0 0 1 -2 2 h-13 a2 2 0 0 1 -2 -2 v-7 a2 2 0 0 1 2 -2 M8 17 h3"/></svg>');
9
+ LX.registerIcon('TimelineLock', '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path fill="none" d="M7 11V7a4 4 0 0 1 9 0v4 M5,11h13 a2 2 0 0 1 2 2 v7 a2 2 0 0 1 -2 2 h-13 a2 2 0 0 1 -2 -2 v-7 a2 2 0 0 1 2 -2 M12 16 v2"/></svg>');
10
+ LX.registerIcon('TimelineLockOpen', '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path fill="none" d="M14 11V7a4 4 0 0 1 9 0v2 M3,11h13 a2 2 0 0 1 2 2 v7 a2 2 0 0 1 -2 2 h-13 a2 2 0 0 1 -2 -2 v-7 a2 2 0 0 1 2 -2 M8 17 h3"/></svg>');
11
11
  const Area = LX.Area;
12
12
  const Panel = LX.Panel;
13
13
  const Dialog = LX.Dialog;
@@ -63,8 +63,8 @@ class Timeline {
63
63
  grabbingScroll = false;
64
64
  movingKeys = false;
65
65
  timeBeforeMove = 0;
66
- currentScroll = 0; //in percentage
67
- currentScrollInPixels = 0; //in pixels
66
+ currentScroll = 0; // in percentage
67
+ currentScrollInPixels = 0; // in pixels
68
68
  trackHeight = 32;
69
69
  timeSeparators = [0.01, 0.1, 0.5, 1, 5];
70
70
  playing = false;
@@ -128,8 +128,8 @@ class Timeline {
128
128
  this.onShowOptimizeMenu = options.onShowOptimizeMenu;
129
129
  this.onShowConfiguration = options.onShowConfiguration;
130
130
  this.canvas = document.createElement('canvas');
131
- this.canvas.style.width = "100%";
132
- this.canvas.style.height = "100%";
131
+ this.canvas.style.width = '100%';
132
+ this.canvas.style.height = '100%';
133
133
  this.secondsPerPixel = 1 / this.pixelsPerSecond;
134
134
  this.animationClip = this.instantiateAnimationClip();
135
135
  this.loop = options.loop ?? true;
@@ -139,35 +139,37 @@ class Timeline {
139
139
  // main area -- root
140
140
  this.mainArea = new Area({ className: 'lextimeline' });
141
141
  this.root = this.mainArea.root;
142
- this.mainArea.split({ type: "vertical", sizes: [this.header_offset, "auto"], resize: false });
142
+ this.mainArea.split({ type: 'vertical', sizes: [this.header_offset, 'auto'], resize: false });
143
143
  // header
144
144
  this.header = new Panel({ id: 'lextimelineheader' });
145
145
  this.mainArea.sections[0].attach(this.header);
146
146
  this.updateHeader();
147
147
  // content area
148
148
  const contentArea = this.mainArea.sections[1];
149
- contentArea.root.id = "bottom-timeline-area";
150
- contentArea.split({ type: "horizontal", sizes: ["15%", "85%"] });
149
+ contentArea.root.id = 'bottom-timeline-area';
150
+ contentArea.split({ type: 'horizontal', sizes: ['15%', '85%'] });
151
151
  let [left, right] = contentArea.sections;
152
152
  right.attach(this.canvas);
153
153
  this.canvasArea = right;
154
- this.canvasArea.root.classList.add("lextimelinearea");
155
- this.leftPanel = left.addPanel({ className: 'lextimelinepanel', width: "100%", height: "100%" });
154
+ this.canvasArea.root.classList.add('lextimelinearea');
155
+ this.leftPanel = left.addPanel({ className: 'lextimelinepanel', width: '100%', height: '100%' });
156
156
  this.updateLeftPanel();
157
157
  if (this.uniqueID.length) {
158
158
  this.root.id = this.uniqueID;
159
159
  this.canvas.id = this.uniqueID + '-canvas';
160
160
  }
161
161
  // Process mouse events
162
- this.canvas.addEventListener("mousedown", this.processMouse.bind(this));
163
- this.canvas.addEventListener("mouseup", this.processMouse.bind(this));
164
- this.canvas.addEventListener("mousemove", this.processMouse.bind(this));
165
- this.canvas.addEventListener("wheel", this.processMouse.bind(this));
166
- this.canvas.addEventListener("dblclick", this.processMouse.bind(this));
167
- this.canvas.addEventListener("contextmenu", this.processMouse.bind(this));
162
+ this.canvas.addEventListener('mousedown', this.processMouse.bind(this));
163
+ this.canvas.addEventListener('mouseup', this.processMouse.bind(this));
164
+ this.canvas.addEventListener('mousemove', this.processMouse.bind(this));
165
+ this.canvas.addEventListener('wheel', this.processMouse.bind(this));
166
+ this.canvas.addEventListener('dblclick', this.processMouse.bind(this));
167
+ this.canvas.addEventListener('contextmenu', this.processMouse.bind(this));
168
168
  this.canvas.tabIndex = 1;
169
169
  // Process keys events
170
- this.canvasArea.root.addEventListener("keydown", (e) => { this.processKeys(e); }); // so this.processKeys can be overwritten by the user
170
+ this.canvasArea.root.addEventListener('keydown', (e) => {
171
+ this.processKeys(e);
172
+ }); // so this.processKeys can be overwritten by the user
171
173
  this.canvasArea.onresize = (bounding) => {
172
174
  if (!(bounding.width && bounding.height)) {
173
175
  return;
@@ -179,23 +181,23 @@ class Timeline {
179
181
  * updates theme ( light - dark ) based on LX's current theme
180
182
  */
181
183
  function updateTheme() {
182
- Timeline.BACKGROUND_COLOR = LX.getThemeColor("global-blur-background");
183
- Timeline.TRACK_COLOR_PRIMARY = LX.getThemeColor("global-color-primary");
184
- Timeline.TRACK_COLOR_SECONDARY = LX.getThemeColor("global-color-secondary");
185
- Timeline.TRACK_COLOR_TERCIARY = LX.getThemeColor("global-color-terciary");
186
- Timeline.TRACK_COLOR_QUATERNARY = LX.getThemeColor("global-color-quaternary");
187
- Timeline.FONT = LX.getThemeColor("global-font");
188
- Timeline.FONT_COLOR_PRIMARY = LX.getThemeColor("global-text-primary");
189
- Timeline.FONT_COLOR_TERTIARY = LX.getThemeColor("global-text-tertiary");
190
- Timeline.FONT_COLOR_QUATERNARY = LX.getThemeColor("global-text-quaternary");
191
- Timeline.KEYFRAME_COLOR = LX.getThemeColor("lxTimeline-keyframe");
192
- Timeline.KEYFRAME_COLOR_SELECTED = Timeline.KEYFRAME_COLOR_HOVERED = LX.getThemeColor("lxTimeline-keyframe-selected");
193
- Timeline.KEYFRAME_COLOR_LOCK = LX.getThemeColor("lxTimeline-keyframe-locked");
194
- Timeline.KEYFRAME_COLOR_EDITED = LX.getThemeColor("lxTimeline-keyframe-edited");
195
- Timeline.KEYFRAME_COLOR_INACTIVE = LX.getThemeColor("lxTimeline-keyframe-inactive");
184
+ Timeline.BACKGROUND_COLOR = LX.getThemeColor('global-blur-background');
185
+ Timeline.TRACK_COLOR_PRIMARY = LX.getThemeColor('global-color-primary');
186
+ Timeline.TRACK_COLOR_SECONDARY = LX.getThemeColor('global-color-secondary');
187
+ Timeline.TRACK_COLOR_TERCIARY = LX.getThemeColor('global-color-terciary');
188
+ Timeline.TRACK_COLOR_QUATERNARY = LX.getThemeColor('global-color-quaternary');
189
+ Timeline.FONT = LX.getThemeColor('global-font');
190
+ Timeline.FONT_COLOR_PRIMARY = LX.getThemeColor('global-text-primary');
191
+ Timeline.FONT_COLOR_TERTIARY = LX.getThemeColor('global-text-tertiary');
192
+ Timeline.FONT_COLOR_QUATERNARY = LX.getThemeColor('global-text-quaternary');
193
+ Timeline.KEYFRAME_COLOR = LX.getThemeColor('lxTimeline-keyframe');
194
+ Timeline.KEYFRAME_COLOR_SELECTED = Timeline.KEYFRAME_COLOR_HOVERED = LX.getThemeColor('lxTimeline-keyframe-selected');
195
+ Timeline.KEYFRAME_COLOR_LOCK = LX.getThemeColor('lxTimeline-keyframe-locked');
196
+ Timeline.KEYFRAME_COLOR_EDITED = LX.getThemeColor('lxTimeline-keyframe-edited');
197
+ Timeline.KEYFRAME_COLOR_INACTIVE = LX.getThemeColor('lxTimeline-keyframe-inactive');
196
198
  }
197
199
  this.updateTheme = updateTheme.bind(this);
198
- LX.addSignal("@on_new_color_scheme", this.updateTheme);
200
+ LX.addSignal('@on_new_color_scheme', this.updateTheme);
199
201
  }
200
202
  // makes it ready to be deleted
201
203
  clear() {
@@ -206,7 +208,7 @@ class Timeline {
206
208
  this.leftPanel.clear();
207
209
  }
208
210
  if (this.updateTheme) {
209
- let signals = LX.signals["@on_new_color_scheme"] ?? [];
211
+ let signals = LX.signals['@on_new_color_scheme'] ?? [];
210
212
  for (let i = 0; i < signals.length; ++i) {
211
213
  if (signals[i] == this.updateTheme) {
212
214
  signals.splice(i, 1);
@@ -222,73 +224,78 @@ class Timeline {
222
224
  const header = this.header;
223
225
  header.sameLine();
224
226
  if (this.timelineTitle) {
225
- header.addTitle(this.timelineTitle, { style: { background: "none", fontSize: "18px", fontStyle: "bold", alignItems: "center" } });
227
+ header.addTitle(this.timelineTitle, {
228
+ style: { background: 'none', fontSize: '18px', fontStyle: 'bold', alignItems: 'center' }
229
+ });
226
230
  }
227
- const buttonContainer = LX.makeContainer(["auto", "100%"], "flex flex-row gap-1");
231
+ const buttonContainer = LX.makeContainer(['auto', '100%'], 'flex flex-row gap-1');
228
232
  header.queue(buttonContainer);
229
- const playbtn = header.addButton("playBtn", '', (value, event) => {
233
+ const playbtn = header.addButton('playBtn', '', (value, event) => {
230
234
  this.changeState();
231
- }, { buttonClass: "accept", title: "Play", hideName: true, icon: "Play@solid", swap: "Pause@solid" });
235
+ }, { buttonClass: 'accept', title: 'Play', hideName: true, icon: 'Play@solid', swap: 'Pause@solid' });
232
236
  playbtn.setState(this.playing, true);
233
- header.addButton("stopBtn", '', (value, event) => {
237
+ header.addButton('stopBtn', '', (value, event) => {
234
238
  this.setState(false, true); // skip callback of set state
235
239
  if (this.onStateStop) {
236
240
  this.onStateStop();
237
241
  }
238
- }, { buttonClass: "accept", title: "Stop", hideName: true, icon: "Stop@solid" });
239
- header.addButton("loopBtn", '', (value, event) => {
242
+ }, { buttonClass: 'accept', title: 'Stop', hideName: true, icon: 'Stop@solid' });
243
+ header.addButton('loopBtn', '', (value, event) => {
240
244
  this.setLoopMode(!this.loop);
241
- }, { selectable: true, selected: this.loop, title: 'Loop', hideName: true, icon: "RefreshCw" });
245
+ }, { selectable: true, selected: this.loop, title: 'Loop', hideName: true, icon: 'RefreshCw' });
242
246
  if (this.onCreateControlsButtons) {
243
247
  this.onCreateControlsButtons(header);
244
248
  }
245
249
  header.clearQueue(buttonContainer);
246
- header.addContent("header-buttons", buttonContainer);
250
+ header.addContent('header-buttons', buttonContainer);
247
251
  // time number inputs - duration, current time, etc
248
252
  if (this.onCreateBeforeTopBar) {
249
253
  this.onCreateBeforeTopBar(header);
250
254
  }
251
- header.addNumber("Current Time", this.currentTime, (value, event) => {
255
+ header.addNumber('Current Time', this.currentTime, (value, event) => {
252
256
  this.setTime(value);
253
257
  }, {
254
- units: "s",
255
- step: 0.01, min: 0, precision: 3,
258
+ units: 's',
259
+ step: 0.01,
260
+ min: 0,
261
+ precision: 3,
256
262
  skipSlider: true,
257
263
  skipReset: true,
258
- nameWidth: "auto"
264
+ nameWidth: 'auto'
259
265
  });
260
- header.addNumber("Duration", +this.duration.toFixed(3), (value, event) => {
266
+ header.addNumber('Duration', +this.duration.toFixed(3), (value, event) => {
261
267
  this.setDuration(value, false, false);
262
268
  }, {
263
- units: "s",
264
- step: 0.01, min: 0,
269
+ units: 's',
270
+ step: 0.01,
271
+ min: 0,
265
272
  skipReset: true,
266
- nameWidth: "auto"
273
+ nameWidth: 'auto'
267
274
  });
268
275
  if (this.onCreateAfterTopBar) {
269
276
  this.onCreateAfterTopBar(header);
270
277
  }
271
278
  // settings buttons - optimize, settings, etc
272
- const buttonContainerEnd = LX.makeContainer(["auto", "100%"], "flex flex-row gap-1");
279
+ const buttonContainerEnd = LX.makeContainer(['auto', '100%'], 'flex flex-row gap-1');
273
280
  header.queue(buttonContainerEnd);
274
281
  if (this.onCreateSettingsButtons) {
275
282
  this.onCreateSettingsButtons(header);
276
283
  }
277
284
  if (this.onShowOptimizeMenu) {
278
- header.addButton(null, "", (value, event) => {
285
+ header.addButton(null, '', (value, event) => {
279
286
  if (this.onShowOptimizeMenu) {
280
287
  this.onShowOptimizeMenu(event);
281
288
  }
282
- }, { tooltip: true, title: "Optimize", icon: "Filter" });
289
+ }, { tooltip: true, title: 'Optimize', icon: 'Filter' });
283
290
  }
284
291
  if (this.onShowConfiguration) {
285
- header.addButton(null, "", (value, event) => {
292
+ header.addButton(null, '', (value, event) => {
286
293
  if (this.configurationDialog) {
287
294
  this.configurationDialog.close();
288
295
  this.configurationDialog = null;
289
296
  return;
290
297
  }
291
- this.configurationDialog = new Dialog("Configuration", (p) => {
298
+ this.configurationDialog = new Dialog('Configuration', (p) => {
292
299
  if (this.onShowConfiguration) {
293
300
  this.onShowConfiguration(p);
294
301
  }
@@ -298,41 +305,43 @@ class Timeline {
298
305
  this.configurationDialog = null;
299
306
  }
300
307
  });
301
- }, { title: "Settings", icon: "Settings", tooltip: true });
308
+ }, { title: 'Settings', icon: 'Settings', tooltip: true });
302
309
  }
303
310
  header.clearQueue(buttonContainerEnd);
304
- header.addContent("header-buttons-end", buttonContainerEnd);
305
- header.endLine("justify-between");
311
+ header.addContent('header-buttons-end', buttonContainerEnd);
312
+ header.endLine('justify-between');
306
313
  }
307
314
  /**
308
- * @method updateLeftPanel
309
- *
310
- */
315
+ * @method updateLeftPanel
316
+ */
311
317
  updateLeftPanel() {
312
318
  this.leftPanel.clear();
313
319
  const panel = this.leftPanel;
314
320
  panel.sameLine();
315
- let titleComponent = panel.addTitle("Tracks", { style: { background: "none" }, className: "fg-secondary text-lg px-4" });
321
+ let titleComponent = panel.addTitle('Tracks', { style: { background: 'none' },
322
+ className: 'fg-secondary text-lg px-4' });
316
323
  let title = titleComponent.root;
317
324
  if (!this.disableNewTracks) {
318
- panel.addButton("addTrackBtn", '', (value, event) => {
325
+ panel.addButton('addTrackBtn', '', (value, event) => {
319
326
  if (this.onAddNewTrackButton) {
320
327
  this.onAddNewTrackButton();
321
328
  }
322
329
  else {
323
330
  this.addNewTrack();
324
331
  }
325
- }, { hideName: true, title: "Add Track", icon: "Plus" });
332
+ }, { hideName: true, title: 'Add Track', icon: 'Plus' });
326
333
  }
327
334
  panel.endLine();
328
335
  const styles = window.getComputedStyle(title);
329
- const titleHeight = title.clientHeight + parseFloat(styles['marginTop']) + parseFloat(styles['marginBottom']);
330
- let p = new LX.Panel({ height: "calc(100% - " + titleHeight + "px )" });
336
+ const titleHeight = title.clientHeight + parseFloat(styles['marginTop'])
337
+ + parseFloat(styles['marginBottom']);
338
+ let p = new LX.Panel({ height: 'calc(100% - ' + titleHeight + 'px )' });
331
339
  let treeTracks = [];
332
340
  if (this.animationClip && this.selectedItems.length) {
333
341
  treeTracks = this.generateSelectedItemsTreeData();
334
342
  }
335
- this.trackTreesComponent = p.addTree(null, treeTracks, { filter: false, rename: false, draggable: false, onevent: (e) => {
343
+ this.trackTreesComponent = p.addTree(null, treeTracks, { filter: false, rename: false, draggable: false,
344
+ onevent: (e) => {
336
345
  switch (e.type) {
337
346
  case LX.TreeEvent.NODE_SELECTED:
338
347
  if (!e.event.shiftKey) {
@@ -363,13 +372,14 @@ class Timeline {
363
372
  this._updateTrackTreeSelection(); // select visible tracks
364
373
  }
365
374
  // setting a name in the addTree function adds an undesired node
366
- this.trackTreesComponent.name = "tracksTrees";
375
+ this.trackTreesComponent.name = 'tracksTrees';
367
376
  p.components[this.trackTreesComponent.name] = this.trackTreesComponent;
368
377
  this.trackTreesPanel = p;
369
378
  panel.attach(p.root);
370
- p.root.addEventListener("scroll", (e) => {
379
+ p.root.addEventListener('scroll', (e) => {
371
380
  if (e.currentTarget.scrollHeight > e.currentTarget.clientHeight) {
372
- this.currentScroll = e.currentTarget.scrollTop / (e.currentTarget.scrollHeight - e.currentTarget.clientHeight);
381
+ this.currentScroll = e.currentTarget.scrollTop
382
+ / (e.currentTarget.scrollHeight - e.currentTarget.clientHeight);
373
383
  this.currentScrollInPixels = e.currentTarget.scrollTop;
374
384
  }
375
385
  else {
@@ -379,7 +389,7 @@ class Timeline {
379
389
  });
380
390
  this.trackTreesPanel.root.scrollTop = this.currentScrollInPixels;
381
391
  this.setTrackHeight(this.trackHeight);
382
- if (this.leftPanel.parent.root.classList.contains("hidden") || !this.root.parentElement) {
392
+ if (this.leftPanel.parent.root.classList.contains('hidden') || !this.root.parentElement) {
383
393
  return;
384
394
  }
385
395
  this.resizeCanvas();
@@ -393,9 +403,9 @@ class Timeline {
393
403
  return;
394
404
  }
395
405
  trackHeight -= gapSize;
396
- const tracks = this.trackTreesComponent.root.querySelector("ul").children;
406
+ const tracks = this.trackTreesComponent.root.querySelector('ul').children;
397
407
  for (let i = 0; i < tracks.length; ++i) {
398
- tracks[i].style.height = trackHeight + "px";
408
+ tracks[i].style.height = trackHeight + 'px';
399
409
  }
400
410
  }
401
411
  /**
@@ -467,9 +477,9 @@ class Timeline {
467
477
  return this.animationClip;
468
478
  }
469
479
  drawTimeInfo(w, h = this.topMargin) {
470
- let ctx = this.canvas.getContext("2d");
471
- ctx.font = "11px " + Timeline.FONT; //"11px Calibri";
472
- ctx.textAlign = "center";
480
+ let ctx = this.canvas.getContext('2d');
481
+ ctx.font = '11px ' + Timeline.FONT; // "11px Calibri";
482
+ ctx.textAlign = 'center';
473
483
  // Draw time markers
474
484
  ctx.save();
475
485
  // background of timeinfo
@@ -478,15 +488,12 @@ class Timeline {
478
488
  ctx.strokeStyle = Timeline.FONT_COLOR_PRIMARY;
479
489
  // set tick and sub tick times
480
490
  let tickTime = 4;
481
- if (this.pixelsPerSecond > 900) {
491
+ if (this.pixelsPerSecond > 900)
482
492
  tickTime = 1;
483
- }
484
- else if (this.pixelsPerSecond > 100) {
493
+ else if (this.pixelsPerSecond > 100)
485
494
  tickTime = 2;
486
- }
487
- else if (this.pixelsPerSecond > 50) {
495
+ else if (this.pixelsPerSecond > 50)
488
496
  tickTime = 3;
489
- }
490
497
  let subtickTime = this.timeSeparators[tickTime - 1];
491
498
  tickTime = this.timeSeparators[tickTime];
492
499
  const startTime = this.visualTimeRange[0];
@@ -520,14 +527,14 @@ class Timeline {
520
527
  }
521
528
  drawTracksBackground(w, h) {
522
529
  let canvas = this.canvas;
523
- let ctx = canvas.getContext("2d");
530
+ let ctx = canvas.getContext('2d');
524
531
  let duration = this.duration;
525
532
  ctx.globalAlpha = 1;
526
533
  // Content
527
534
  const topMargin = this.topMargin;
528
535
  const treeOffset = this.lastTrackTreesComponentOffset;
529
536
  const line_height = this.trackHeight;
530
- //fill track lines
537
+ // fill track lines
531
538
  w = w || canvas.width;
532
539
  let max_tracks = Math.ceil((h - topMargin) / line_height) + 1;
533
540
  ctx.save();
@@ -537,13 +544,12 @@ class Timeline {
537
544
  for (let i = blackOrWhite; i <= max_tracks; i += 2) {
538
545
  ctx.fillRect(0, treeOffset - rectsOffset + i * line_height, w, line_height);
539
546
  }
540
- //bg lines
547
+ // bg lines
541
548
  ctx.strokeStyle = Timeline.TRACK_COLOR_TERCIARY;
542
549
  ctx.beginPath();
543
550
  let pos = this.timeToX(0);
544
- if (pos < 0) {
551
+ if (pos < 0)
545
552
  pos = 0;
546
- }
547
553
  ctx.lineWidth = 1;
548
554
  ctx.moveTo(pos + 0.5, topMargin);
549
555
  ctx.lineTo(pos + 0.5, canvas.height);
@@ -556,19 +562,20 @@ class Timeline {
556
562
  * @method draw
557
563
  */
558
564
  draw() {
559
- let ctx = this.canvas.getContext("2d");
560
- ctx.textBaseline = "bottom";
561
- ctx.font = "11px " + Timeline.FONT; //"11px Calibri";
565
+ let ctx = this.canvas.getContext('2d');
566
+ ctx.textBaseline = 'bottom';
567
+ ctx.font = '11px ' + Timeline.FONT; // "11px Calibri";
562
568
  ctx.globalAlpha = 1;
563
569
  const w = ctx.canvas.width;
564
570
  const h = ctx.canvas.height;
565
571
  const scrollableHeight = this.trackTreesComponent.root.scrollHeight;
566
572
  // tree has gaps of 0.25rem (4px ) inbetween entries but not in the beginning nor ending. Move half gap upwards.
567
- const treeOffset = this.lastTrackTreesComponentOffset = this.trackTreesComponent.innerTree.domEl.offsetTop - this.canvas.offsetTop - 2;
568
- //zoom
569
- let startTime = this.visualOriginTime; //seconds
573
+ const treeOffset = this.lastTrackTreesComponentOffset = this.trackTreesComponent.innerTree.domEl.offsetTop
574
+ - this.canvas.offsetTop - 2;
575
+ // zoom
576
+ let startTime = this.visualOriginTime; // seconds
570
577
  startTime = Math.min(this.duration, Math.max(0, startTime));
571
- let endTime = this.visualOriginTime + w * this.secondsPerPixel; //seconds
578
+ let endTime = this.visualOriginTime + w * this.secondsPerPixel; // seconds
572
579
  endTime = Math.max(startTime, Math.min(this.duration, endTime));
573
580
  this.visualTimeRange[0] = startTime;
574
581
  this.visualTimeRange[1] = endTime;
@@ -585,9 +592,9 @@ class Timeline {
585
592
  this.drawContent(ctx);
586
593
  ctx.translate(0, -treeOffset);
587
594
  }
588
- //scrollbar
595
+ // scrollbar
589
596
  if ((h - this.topMargin) < scrollableHeight) {
590
- ctx.fillStyle = "#222";
597
+ ctx.fillStyle = '#222';
591
598
  ctx.fillRect(w - 10, 0, 10, h);
592
599
  ctx.fillStyle = this.grabbingScroll ? Timeline.FONT_COLOR_TERTIARY : Timeline.FONT_COLOR_QUATERNARY;
593
600
  let scrollBarHeight = Math.max(10, (h - this.topMargin) * (h - this.topMargin) / this.trackTreesPanel.root.scrollHeight);
@@ -603,7 +610,7 @@ class Timeline {
603
610
  ctx.globalAlpha = 1;
604
611
  ctx.beginPath();
605
612
  ctx.moveTo(posx, posy * 0.6);
606
- ctx.lineTo(posx, this.canvas.height); //line
613
+ ctx.lineTo(posx, this.canvas.height); // line
607
614
  ctx.stroke();
608
615
  ctx.closePath();
609
616
  ctx.shadowBlur = 8;
@@ -617,9 +624,9 @@ class Timeline {
617
624
  ctx.shadowOffsetY = 0;
618
625
  }
619
626
  // Current time seconds in text
620
- ctx.font = "11px " + Timeline.FONT; //"11px Calibri";
621
- ctx.textAlign = "center";
622
- //ctx.textBaseline = "middle";
627
+ ctx.font = '11px ' + Timeline.FONT; // "11px Calibri";
628
+ ctx.textAlign = 'center';
629
+ // ctx.textBaseline = "middle";
623
630
  ctx.fillStyle = Timeline.TIME_MARKER_COLOR_TEXT;
624
631
  ctx.fillText((Math.floor(this.currentTime * 10) * 0.1).toFixed(1), posx, this.topMargin * 0.6);
625
632
  // Selections
@@ -650,7 +657,7 @@ class Timeline {
650
657
  let v = Math.max(0, t);
651
658
  this.duration = this.animationClip.duration = v;
652
659
  if (updateHeader) {
653
- this.header.components["Duration"].set(+this.duration.toFixed(2), true); // skipcallback = true
660
+ this.header.components['Duration'].set(+this.duration.toFixed(2), true); // skipcallback = true
654
661
  }
655
662
  if (this.onSetDuration && !skipCallback) {
656
663
  this.onSetDuration(this.duration);
@@ -658,7 +665,7 @@ class Timeline {
658
665
  }
659
666
  setTime(time, skipCallback = false) {
660
667
  this.currentTime = Math.max(0, Math.min(time, this.duration));
661
- this.header.components["Current Time"].set(+this.currentTime.toFixed(2), true); // skipcallback = true
668
+ this.header.components['Current Time'].set(+this.currentTime.toFixed(2), true); // skipcallback = true
662
669
  if (this.onSetTime && !skipCallback) {
663
670
  this.onSetTime(this.currentTime);
664
671
  }
@@ -731,22 +738,22 @@ class Timeline {
731
738
  let localX = e.offsetX;
732
739
  let localY = e.offsetY;
733
740
  let timeX = this.timeToX(this.currentTime);
734
- let isHoveringTimeBar = localY < this.topMargin &&
735
- localX > (timeX - 6) && localX < (timeX + 6);
741
+ let isHoveringTimeBar = localY < this.topMargin
742
+ && localX > (timeX - 6) && localX < (timeX + 6);
736
743
  const time = this.xToTime(x);
737
744
  if (isHoveringTimeBar) {
738
- this.canvas.style.cursor = "col-resize";
745
+ this.canvas.style.cursor = 'col-resize';
739
746
  }
740
747
  else if (this.movingKeys) {
741
- this.canvas.style.cursor = "grabbing";
748
+ this.canvas.style.cursor = 'grabbing';
742
749
  }
743
750
  else if (e.shiftKey) {
744
- this.canvas.style.cursor = "crosshair";
751
+ this.canvas.style.cursor = 'crosshair';
745
752
  }
746
753
  else {
747
- this.canvas.style.cursor = "default";
754
+ this.canvas.style.cursor = 'default';
748
755
  }
749
- if (e.type == "wheel") {
756
+ if (e.type == 'wheel') {
750
757
  if (e.shiftKey) {
751
758
  if (e.wheelDelta) {
752
759
  let mouseTime = this.xToTime(localX);
@@ -762,14 +769,14 @@ class Timeline {
762
769
  }
763
770
  return;
764
771
  }
765
- const is_inside = x >= 0 && x <= this.size[0] &&
766
- y >= 0 && y <= this.size[1];
772
+ const is_inside = x >= 0 && x <= this.size[0]
773
+ && y >= 0 && y <= this.size[1];
767
774
  let track = this.getTracksInRange(localY, localY);
768
775
  track = track.length ? track[0] : null;
769
776
  e.track = track;
770
777
  e.localX = localX;
771
778
  e.localY = localY;
772
- if (e.type == "mouseup") {
779
+ if (e.type == 'mouseup') {
773
780
  if (!this.active) {
774
781
  this.grabbing = false;
775
782
  this.grabbingTimeBar = false;
@@ -792,7 +799,7 @@ class Timeline {
792
799
  this.timeBeforeMove = 0;
793
800
  this.boxSelection = false; // after mouseup
794
801
  }
795
- if (e.type == "mousedown") {
802
+ if (e.type == 'mousedown') {
796
803
  window.getSelection()?.empty(); // if canvas DOM is selected, dragging does not work properly. Deselect it
797
804
  // e.preventDefault();
798
805
  this.clickTime = LX.getTime();
@@ -807,13 +814,12 @@ class Timeline {
807
814
  this.grabbingTimeBar = true;
808
815
  this.setTime(time);
809
816
  }
810
- else if ((h - this.topMargin) < this.trackTreesComponent.root.scrollHeight && x > w - 10) // grabbing scroll bar
811
- {
817
+ else if ((h - this.topMargin) < this.trackTreesComponent.root.scrollHeight && x > w - 10) { // grabbing scroll bar
812
818
  this.grabbing = true;
813
819
  this.grabbingScroll = true;
814
820
  }
815
- else // grabbing canvas
816
- {
821
+ // grabbing canvas
822
+ else {
817
823
  this.grabbing = true;
818
824
  this.grabTime = time;
819
825
  this.grabbingTimeBar = isHoveringTimeBar;
@@ -822,15 +828,14 @@ class Timeline {
822
828
  }
823
829
  }
824
830
  }
825
- else if (e.type == "mousemove") {
831
+ else if (e.type == 'mousemove') {
826
832
  if (e.shiftKey && this.active && this.boxSelection) {
827
833
  this.boxSelectionEnd[0] = localX;
828
834
  this.boxSelectionEnd[1] = localY;
829
835
  return; // Handled
830
836
  }
831
- else if (this.grabbing && e.button != 2 && !this.movingKeys) // e.buttons != 2 on mousemove needs to be plural
832
- {
833
- this.canvas.style.cursor = "grabbing";
837
+ else if (this.grabbing && e.button != 2 && !this.movingKeys) { // e.buttons != 2 on mousemove needs to be plural
838
+ this.canvas.style.cursor = 'grabbing';
834
839
  if (this.grabbingTimeBar && this.active) {
835
840
  this.setTime(time);
836
841
  }
@@ -840,14 +845,15 @@ class Timeline {
840
845
  this.trackTreesPanel.root.scrollTop = 0;
841
846
  }
842
847
  else {
843
- this.trackTreesPanel.root.scrollTop += this.trackTreesPanel.root.scrollHeight * e.deltay / (h - this.topMargin);
848
+ this.trackTreesPanel.root.scrollTop += this.trackTreesPanel.root.scrollHeight * e.deltay
849
+ / (h - this.topMargin);
844
850
  }
845
851
  }
846
852
  else {
847
853
  // Move timeline in X ( independent of current time )
848
854
  var old = this.xToTime(this.lastMouse[0]);
849
855
  var now = this.xToTime(e.offsetX);
850
- this.visualOriginTime += (old - now);
856
+ this.visualOriginTime += old - now;
851
857
  this.trackTreesPanel.root.scrollTop -= e.deltay; // will automatically call scroll event
852
858
  }
853
859
  }
@@ -855,10 +861,10 @@ class Timeline {
855
861
  this.onMouseMove(e, time);
856
862
  }
857
863
  }
858
- else if (e.type == "dblclick" && this.onDblClick) {
864
+ else if (e.type == 'dblclick' && this.onDblClick) {
859
865
  this.onDblClick(e);
860
866
  }
861
- else if (e.type == "contextmenu" && this.onShowContextMenu && this.active) {
867
+ else if (e.type == 'contextmenu' && this.onShowContextMenu && this.active) {
862
868
  this.onShowContextMenu(e);
863
869
  }
864
870
  this.lastMouse[0] = x;
@@ -884,23 +890,21 @@ class Timeline {
884
890
  break;
885
891
  case 'c':
886
892
  case 'C':
887
- if (e.ctrlKey) {
893
+ if (e.ctrlKey)
888
894
  this.copySelectedContent();
889
- }
890
895
  break;
891
896
  case 'v':
892
897
  case 'V':
893
- if (e.ctrlKey) {
898
+ if (e.ctrlKey)
894
899
  this.pasteContent(this.currentTime);
895
- }
896
900
  break;
897
901
  case ' ':
898
902
  e.preventDefault();
899
903
  e.stopImmediatePropagation();
900
904
  this.changeState();
901
905
  break;
902
- case "Shift":
903
- this.canvas.style.cursor = "crosshair";
906
+ case 'Shift':
907
+ this.canvas.style.cursor = 'crosshair';
904
908
  break;
905
909
  }
906
910
  }
@@ -908,7 +912,7 @@ class Timeline {
908
912
  * @method changeState
909
913
  * @param {Boolean} skipCallback defaults false
910
914
  * @description change play/pause state
911
- **/
915
+ */
912
916
  changeState(skipCallback = false) {
913
917
  this.setState(!this.playing, skipCallback);
914
918
  }
@@ -917,7 +921,7 @@ class Timeline {
917
921
  * @param {Boolean} state
918
922
  * @param {Boolean} skipCallback defaults false
919
923
  * @description change play/pause state
920
- **/
924
+ */
921
925
  setState(state, skipCallback = false) {
922
926
  this.playing = state;
923
927
  this.header.components.playBtn.setState(this.playing, true);
@@ -934,10 +938,10 @@ class Timeline {
934
938
  setLoopMode(loopState, skipCallback = false) {
935
939
  this.loop = loopState;
936
940
  if (this.loop) {
937
- this.header.components.loopBtn.root.children[0].classList.add("selected");
941
+ this.header.components.loopBtn.root.children[0].classList.add('selected');
938
942
  }
939
943
  else {
940
- this.header.components.loopBtn.root.children[0].classList.remove("selected");
944
+ this.header.components.loopBtn.root.children[0].classList.remove('selected');
941
945
  }
942
946
  if (this.onChangeLoopMode && !skipCallback) {
943
947
  this.onChangeLoopMode(this.loop);
@@ -1076,12 +1080,12 @@ class Timeline {
1076
1080
  deselectAllElements() {
1077
1081
  }
1078
1082
  /**
1079
- * @method setTrackState
1080
- * @param {Int} trackIdx
1081
- * @param {Boolean} isEnbaled
1082
- * @param {Boolean} skipCallback onSetTrackState
1083
- * @param {Boolean} updateTrackTree updates eye icon of the track, if it is visible in the timeline
1084
- */
1083
+ * @method setTrackState
1084
+ * @param {Int} trackIdx
1085
+ * @param {Boolean} isEnbaled
1086
+ * @param {Boolean} skipCallback onSetTrackState
1087
+ * @param {Boolean} updateTrackTree updates eye icon of the track, if it is visible in the timeline
1088
+ */
1085
1089
  setTrackState(trackIdx, isEnbaled = true, skipCallback = false, updateTrackTree = true) {
1086
1090
  const track = this.animationClip.tracks[trackIdx];
1087
1091
  const oldState = track.active;
@@ -1095,7 +1099,6 @@ class Timeline {
1095
1099
  }
1096
1100
  }
1097
1101
  /**
1098
- *
1099
1102
  * @param {Int} trackIdx
1100
1103
  * @param {Boolean} isLocked
1101
1104
  * @param {Boolean} skipCallback onSetTrackLock
@@ -1128,9 +1131,8 @@ class Timeline {
1128
1131
  else {
1129
1132
  this.historyUndo.push([undoStep]);
1130
1133
  }
1131
- if (this.historyUndo.length > this.historyMaxSteps) {
1132
- this.historyUndo.shift();
1133
- } // remove first ( oldest ) element
1134
+ if (this.historyUndo.length > this.historyMaxSteps)
1135
+ this.historyUndo.shift(); // remove first ( oldest ) element
1134
1136
  this.historyRedo = [];
1135
1137
  }
1136
1138
  #undoRedo(isUndo = true) {
@@ -1155,8 +1157,12 @@ class Timeline {
1155
1157
  toBeStored.push(combinedStateToStore);
1156
1158
  return true;
1157
1159
  }
1158
- undo() { return this.#undoRedo(true); }
1159
- redo() { return this.#undoRedo(false); }
1160
+ undo() {
1161
+ return this.#undoRedo(true);
1162
+ }
1163
+ redo() {
1164
+ return this.#undoRedo(false);
1165
+ }
1160
1166
  // historyApplyTrackStep( state, isUndo ) MUST BE IMPLEMENTED BY CHILD CLASS
1161
1167
  // historyGenerateTrackStep( trackIdx ) MUST BE IMPLEMENTED BY CHILD CLASS
1162
1168
  /**
@@ -1172,8 +1178,8 @@ class Timeline {
1172
1178
  this.size[0] = this.root.parentElement.clientWidth;
1173
1179
  this.size[1] = this.root.parentElement.clientHeight;
1174
1180
  }
1175
- //this.content_area.setSize([ size[ 0 ], size[ 1 ] - this.header_offset] );
1176
- this.mainArea.sections[1].root.style.height = "calc(100% - " + this.header_offset + "px )";
1181
+ // this.content_area.setSize([ size[ 0 ], size[ 1 ] - this.header_offset] );
1182
+ this.mainArea.sections[1].root.style.height = 'calc(100% - ' + this.header_offset + 'px )';
1177
1183
  this.size[0] - this.leftPanel.root.clientWidth - 8;
1178
1184
  this.mainArea.sections[1]._update(); // update area's this.size attribute
1179
1185
  this.resizeCanvas();
@@ -1183,16 +1189,16 @@ class Timeline {
1183
1189
  this.canvas.height = this.canvasArea.root.clientHeight;
1184
1190
  }
1185
1191
  /**
1186
- * @method hide
1187
- * Hide timeline area
1188
- */
1192
+ * @method hide
1193
+ * Hide timeline area
1194
+ */
1189
1195
  hide() {
1190
1196
  this.mainArea.hide();
1191
1197
  }
1192
1198
  /**
1193
- * @method show
1194
- * Show timeline area if it is hidden
1195
- */
1199
+ * @method show
1200
+ * Show timeline area if it is hidden
1201
+ */
1196
1202
  show() {
1197
1203
  this.mainArea.show();
1198
1204
  this.resize();
@@ -1213,7 +1219,8 @@ class Timeline {
1213
1219
  const treeTracks = [];
1214
1220
  for (let i = 0; i < this.selectedItems.length; i++) {
1215
1221
  const track = this.selectedItems[i];
1216
- treeTracks.push({ trackData: track, id: track.id, skipVisibility: this.skipVisibility, visible: track.active, children: [], actions: this.skipLock ? null : [{
1222
+ treeTracks.push({ trackData: track, id: track.id, skipVisibility: this.skipVisibility,
1223
+ visible: track.active, children: [], actions: this.skipLock ? null : [{
1217
1224
  'name': 'Lock edition',
1218
1225
  'icon': (track.locked ? 'TimelineLock' : 'TimelineLockOpen'),
1219
1226
  'swap': (track.locked ? 'TimelineLockOpen' : 'TimelineLock'),
@@ -1225,14 +1232,13 @@ class Timeline {
1225
1232
  return treeTracks;
1226
1233
  }
1227
1234
  /**
1228
- *
1229
1235
  * @param {Object} options set some values for the track instance ( groups and trackIdx not included )
1230
1236
  * @returns
1231
1237
  */
1232
1238
  instantiateTrack(options = {}, clone = false) {
1233
1239
  return {
1234
1240
  isTrack: true,
1235
- id: options.id ?? (Math.floor(performance.now()) + "_" + Math.floor(Math.random() * 0xffff)), //must be unique, at least inside a group
1241
+ id: options.id ?? (Math.floor(performance.now()) + '_' + Math.floor(Math.random() * 0xffff)), // must be unique, at least inside a group
1236
1242
  active: options.active ?? true,
1237
1243
  locked: options.locked ?? false,
1238
1244
  isSelected: false, // render and lexgui tree
@@ -1248,39 +1254,39 @@ class Timeline {
1248
1254
  */
1249
1255
  instantiateAnimationClip(options = {}, clone = false) {
1250
1256
  const animationClip = {
1251
- id: options.id ?? (options.name ?? "animationClip"),
1257
+ id: options.id ?? (options.name ?? 'animationClip'),
1252
1258
  duration: options.duration ?? 0,
1253
1259
  tracks: [],
1254
- data: options.data ?? null, // user defined data
1260
+ data: options.data ?? null // user defined data
1255
1261
  };
1256
1262
  return animationClip;
1257
1263
  }
1258
1264
  }
1259
- Timeline.BACKGROUND_COLOR = LX.getThemeColor("global-blur-background");
1260
- Timeline.TRACK_COLOR_PRIMARY = LX.getThemeColor("global-color-primary");
1261
- Timeline.TRACK_COLOR_SECONDARY = LX.getThemeColor("global-color-secondary");
1262
- Timeline.TRACK_COLOR_TERCIARY = LX.getThemeColor("global-color-terciary");
1263
- Timeline.TRACK_COLOR_QUATERNARY = LX.getThemeColor("global-color-quaternary");
1264
- Timeline.TRACK_SELECTED = LX.getThemeColor("global-color-accent");
1265
- Timeline.TRACK_SELECTED_LIGHT = LX.getThemeColor("global-color-accent-light");
1266
- Timeline.FONT = LX.getThemeColor("global-font");
1267
- Timeline.FONT_COLOR_PRIMARY = LX.getThemeColor("global-text-primary");
1268
- Timeline.FONT_COLOR_TERTIARY = LX.getThemeColor("global-text-tertiary");
1269
- Timeline.FONT_COLOR_QUATERNARY = LX.getThemeColor("global-text-quaternary");
1270
- Timeline.TIME_MARKER_COLOR = LX.getThemeColor("global-color-accent");
1271
- Timeline.TIME_MARKER_COLOR_TEXT = "#ffffff";
1272
- LX.setThemeColor("lxTimeline-keyframe", "light-dark(#2d69da,#2d69da )");
1273
- LX.setThemeColor("lxTimeline-keyframe-selected", "light-dark(#f5c700,#fafa14)");
1274
- LX.setThemeColor("lxTimeline-keyframe-hovered", "light-dark(#f5c700,#fafa14)");
1275
- LX.setThemeColor("lxTimeline-keyframe-locked", "light-dark(#c62e2e,#ff7d7d )");
1276
- LX.setThemeColor("lxTimeline-keyframe-edited", "light-dark(#00d000,#00d000 )");
1277
- LX.setThemeColor("lxTimeline-keyframe-inactive", "light-dark(#706b6b,#706b6b)");
1278
- Timeline.KEYFRAME_COLOR = LX.getThemeColor("lxTimeline-keyframe");
1279
- Timeline.KEYFRAME_COLOR_SELECTED = Timeline.KEYFRAME_COLOR_HOVERED = LX.getThemeColor("lxTimeline-keyframe-selected");
1280
- Timeline.KEYFRAME_COLOR_LOCK = LX.getThemeColor("lxTimeline-keyframe-locked");
1281
- Timeline.KEYFRAME_COLOR_EDITED = LX.getThemeColor("lxTimeline-keyframe-edited");
1282
- Timeline.KEYFRAME_COLOR_INACTIVE = LX.getThemeColor("lxTimeline-keyframe-inactive");
1283
- Timeline.BOX_SELECTION_COLOR = "#AAA";
1265
+ Timeline.BACKGROUND_COLOR = LX.getThemeColor('global-blur-background');
1266
+ Timeline.TRACK_COLOR_PRIMARY = LX.getThemeColor('global-color-primary');
1267
+ Timeline.TRACK_COLOR_SECONDARY = LX.getThemeColor('global-color-secondary');
1268
+ Timeline.TRACK_COLOR_TERCIARY = LX.getThemeColor('global-color-terciary');
1269
+ Timeline.TRACK_COLOR_QUATERNARY = LX.getThemeColor('global-color-quaternary');
1270
+ Timeline.TRACK_SELECTED = LX.getThemeColor('global-color-accent');
1271
+ Timeline.TRACK_SELECTED_LIGHT = LX.getThemeColor('global-color-accent-light');
1272
+ Timeline.FONT = LX.getThemeColor('global-font');
1273
+ Timeline.FONT_COLOR_PRIMARY = LX.getThemeColor('global-text-primary');
1274
+ Timeline.FONT_COLOR_TERTIARY = LX.getThemeColor('global-text-tertiary');
1275
+ Timeline.FONT_COLOR_QUATERNARY = LX.getThemeColor('global-text-quaternary');
1276
+ Timeline.TIME_MARKER_COLOR = LX.getThemeColor('global-color-accent');
1277
+ Timeline.TIME_MARKER_COLOR_TEXT = '#ffffff';
1278
+ LX.setThemeColor('lxTimeline-keyframe', 'light-dark(#2d69da,#2d69da )');
1279
+ LX.setThemeColor('lxTimeline-keyframe-selected', 'light-dark(#f5c700,#fafa14)');
1280
+ LX.setThemeColor('lxTimeline-keyframe-hovered', 'light-dark(#f5c700,#fafa14)');
1281
+ LX.setThemeColor('lxTimeline-keyframe-locked', 'light-dark(#c62e2e,#ff7d7d )');
1282
+ LX.setThemeColor('lxTimeline-keyframe-edited', 'light-dark(#00d000,#00d000 )');
1283
+ LX.setThemeColor('lxTimeline-keyframe-inactive', 'light-dark(#706b6b,#706b6b)');
1284
+ Timeline.KEYFRAME_COLOR = LX.getThemeColor('lxTimeline-keyframe');
1285
+ Timeline.KEYFRAME_COLOR_SELECTED = Timeline.KEYFRAME_COLOR_HOVERED = LX.getThemeColor('lxTimeline-keyframe-selected');
1286
+ Timeline.KEYFRAME_COLOR_LOCK = LX.getThemeColor('lxTimeline-keyframe-locked');
1287
+ Timeline.KEYFRAME_COLOR_EDITED = LX.getThemeColor('lxTimeline-keyframe-edited');
1288
+ Timeline.KEYFRAME_COLOR_INACTIVE = LX.getThemeColor('lxTimeline-keyframe-inactive');
1289
+ Timeline.BOX_SELECTION_COLOR = '#AAA';
1284
1290
  LX.Timeline = Timeline;
1285
1291
  /**
1286
1292
  * @class KeyFramesTimeline
@@ -1313,15 +1319,15 @@ class KeyFramesTimeline extends Timeline {
1313
1319
  this.defaultCurvesRange = [0, 1]; // whn a track with dim == 1 has no curves attribute, defaultCurves will be used instead. If true, track is rendered using curves
1314
1320
  this.keyframeSize = this.trackHeight * 0.5; // height of keyframe
1315
1321
  this.keyframeSizeHovered = this.trackHeight * 0.5 + 5;
1316
- if (options.onShowOptimizeMenu && typeof options.onShowOptimizeMenu == "boolean") {
1322
+ if (options.onShowOptimizeMenu && typeof options.onShowOptimizeMenu == 'boolean') {
1317
1323
  this.onShowOptimizeMenu = (e) => {
1318
1324
  if (this.selectedItems.length == 0) {
1319
1325
  return;
1320
1326
  }
1321
- LX.addContextMenu("Optimize", e, (m) => {
1322
- this.selectedItems.forEach(item => {
1327
+ LX.addContextMenu('Optimize', e, (m) => {
1328
+ this.selectedItems.forEach((item) => {
1323
1329
  if (item.isTrack) {
1324
- m.add((item.groupId ? item.groupId : "") + "@" + item.id, () => {
1330
+ m.add((item.groupId ? item.groupId : '') + '@' + item.id, () => {
1325
1331
  this.optimizeTrack(item.trackIdx, false);
1326
1332
  });
1327
1333
  }
@@ -1329,7 +1335,7 @@ class KeyFramesTimeline extends Timeline {
1329
1335
  const tracks = this.animationClip.tracksPerGroup[item];
1330
1336
  for (let i = 0; i < tracks.length; ++i) {
1331
1337
  const t = tracks[i];
1332
- m.add((t.groupId ? t.groupId : "") + "@" + t.id, () => {
1338
+ m.add((t.groupId ? t.groupId : '') + '@' + t.id, () => {
1333
1339
  this.optimizeTrack(t.trackIdx, false);
1334
1340
  });
1335
1341
  }
@@ -1344,20 +1350,20 @@ class KeyFramesTimeline extends Timeline {
1344
1350
  let actions = [];
1345
1351
  if (this.lastKeyFramesSelected && this.lastKeyFramesSelected.length) {
1346
1352
  actions.push({
1347
- title: "Copy",
1353
+ title: 'Copy',
1348
1354
  callback: () => {
1349
1355
  this.copySelectedContent();
1350
1356
  }
1351
1357
  });
1352
1358
  actions.push({
1353
- title: "Delete",
1359
+ title: 'Delete',
1354
1360
  callback: () => {
1355
1361
  this.deleteSelectedContent();
1356
1362
  }
1357
1363
  });
1358
1364
  if (this.lastKeyFramesSelected.length == 1 && this.clipboard && this.clipboard.value) {
1359
1365
  actions.push({
1360
- title: "Paste Value",
1366
+ title: 'Paste Value',
1361
1367
  callback: () => {
1362
1368
  this.pasteContentValue();
1363
1369
  }
@@ -1366,7 +1372,7 @@ class KeyFramesTimeline extends Timeline {
1366
1372
  }
1367
1373
  else {
1368
1374
  actions.push({
1369
- title: "Add Here",
1375
+ title: 'Add Here',
1370
1376
  callback: () => {
1371
1377
  if (!e.track)
1372
1378
  return;
@@ -1376,7 +1382,7 @@ class KeyFramesTimeline extends Timeline {
1376
1382
  }
1377
1383
  });
1378
1384
  actions.push({
1379
- title: "Add",
1385
+ title: 'Add',
1380
1386
  callback: () => {
1381
1387
  if (!e.track)
1382
1388
  return;
@@ -1388,19 +1394,19 @@ class KeyFramesTimeline extends Timeline {
1388
1394
  }
1389
1395
  if (this.clipboard && this.clipboard.keyframes) {
1390
1396
  actions.push({
1391
- title: "Paste Here",
1397
+ title: 'Paste Here',
1392
1398
  callback: () => {
1393
1399
  this.pasteContent(this.xToTime(e.localX));
1394
1400
  }
1395
1401
  });
1396
1402
  actions.push({
1397
- title: "Paste",
1403
+ title: 'Paste',
1398
1404
  callback: () => {
1399
1405
  this.pasteContent(this.currentTime);
1400
1406
  }
1401
1407
  });
1402
1408
  }
1403
- LX.addContextMenu("Options", e, (m) => {
1409
+ LX.addContextMenu('Options', e, (m) => {
1404
1410
  for (let i = 0; i < actions.length; i++) {
1405
1411
  m.add(actions[i].title, actions[i].callback);
1406
1412
  }
@@ -1421,7 +1427,8 @@ class KeyFramesTimeline extends Timeline {
1421
1427
  const nodes = [];
1422
1428
  for (let j = 0; j < itemTracks.length; j++) {
1423
1429
  const track = itemTracks[j];
1424
- nodes.push({ 'trackData': track, 'id': track.id, 'skipVisibility': this.skipVisibility, visible: track.active, 'children': [], actions: this.skipLock ? null : [{
1430
+ nodes.push({ 'trackData': track, 'id': track.id, 'skipVisibility': this.skipVisibility,
1431
+ visible: track.active, 'children': [], actions: this.skipLock ? null : [{
1425
1432
  'name': 'Lock edition',
1426
1433
  'icon': (track.locked ? 'TimelineLock' : 'TimelineLockOpen'),
1427
1434
  'swap': (track.locked ? 'TimelineLockOpen' : 'TimelineLock'),
@@ -1453,8 +1460,7 @@ class KeyFramesTimeline extends Timeline {
1453
1460
  instantiateTrack(options = {}, clone = false) {
1454
1461
  const track = super.instantiateTrack(options);
1455
1462
  track.dim = Math.max(1, options.dim ?? 1); // >= 1
1456
- track.groupId = null,
1457
- track.groupTrackIdx = -1, // track Idx inside group only if in group
1463
+ track.groupId = null, track.groupTrackIdx = -1, // track Idx inside group only if in group
1458
1464
  track.values = new Float32Array(0);
1459
1465
  track.times = new Float32Array(0);
1460
1466
  track.selected = [];
@@ -1504,9 +1510,8 @@ class KeyFramesTimeline extends Timeline {
1504
1510
  let values = track.values ?? [];
1505
1511
  let valueDim = track.dim;
1506
1512
  if (!valueDim || valueDim < 0) {
1507
- if (times.length && values.length) {
1513
+ if (times.length && values.length)
1508
1514
  valueDim = Math.round(values.length / times.length);
1509
- }
1510
1515
  else {
1511
1516
  valueDim = 1;
1512
1517
  }
@@ -1541,7 +1546,10 @@ class KeyFramesTimeline extends Timeline {
1541
1546
  // overwrite trackspergroup
1542
1547
  if (animation.tracksPerGroup) {
1543
1548
  // ungroup all tracks (just in case )
1544
- animationClip.tracks.forEach((v, i) => { v.groupId = null; v.groupTrackIdx = -1; });
1549
+ animationClip.tracks.forEach((v, i) => {
1550
+ v.groupId = null;
1551
+ v.groupTrackIdx = -1;
1552
+ });
1545
1553
  animationClip.tracksPerGroup = {};
1546
1554
  let tpg = animation.tracksPerGroup;
1547
1555
  for (let groupId in tpg) {
@@ -1590,8 +1598,7 @@ class KeyFramesTimeline extends Timeline {
1590
1598
  if (itemsToAdd) {
1591
1599
  for (let i = 0; i < itemsToAdd.length; ++i) {
1592
1600
  const v = itemsToAdd[i];
1593
- if (isNaN(v)) // assuming it is a string
1594
- {
1601
+ if (isNaN(v)) { // assuming it is a string
1595
1602
  if (tracksPerGroup[v]) {
1596
1603
  this.selectedItems.push(v);
1597
1604
  }
@@ -1642,7 +1649,7 @@ class KeyFramesTimeline extends Timeline {
1642
1649
  for (let i = 0; i < groupTracks.length; ++i) {
1643
1650
  const v = groupTracks[i];
1644
1651
  let track = null;
1645
- if (typeof v == "string") {
1652
+ if (typeof v == 'string') {
1646
1653
  // v is an id ( string)
1647
1654
  for (let t = 0; t < tracks.length; ++t) {
1648
1655
  if (tracks[t].id == v) {
@@ -1692,7 +1699,6 @@ class KeyFramesTimeline extends Timeline {
1692
1699
  return null;
1693
1700
  }
1694
1701
  /**
1695
- *
1696
1702
  * @param {Number} size pixels, height of keyframe
1697
1703
  * @param {Number} sizeHovered optional, size in pixels when hovered
1698
1704
  */
@@ -1710,9 +1716,9 @@ class KeyFramesTimeline extends Timeline {
1710
1716
  const thresholdPixels = this.keyframeSize * 0.5; // radius of circle ( curves ) or rotated square (keyframes )
1711
1717
  const keyFrameIdx = this.getCurrentKeyFrame(track, this.xToTime(localX), this.secondsPerPixel * thresholdPixels);
1712
1718
  if (keyFrameIdx > -1) {
1713
- track.selected[keyFrameIdx] ?
1714
- this.deselectKeyFrame(track.trackIdx, keyFrameIdx) :
1715
- this.processSelectionKeyFrame(track.trackIdx, keyFrameIdx, true);
1719
+ track.selected[keyFrameIdx]
1720
+ ? this.deselectKeyFrame(track.trackIdx, keyFrameIdx)
1721
+ : this.processSelectionKeyFrame(track.trackIdx, keyFrameIdx, true);
1716
1722
  }
1717
1723
  }
1718
1724
  // Box selection
@@ -1728,8 +1734,7 @@ class KeyFramesTimeline extends Timeline {
1728
1734
  }
1729
1735
  }
1730
1736
  }
1731
- else if (!this.movingKeys && !discard) // if not moving timeline and not adding keyframes through e.shiftkey (just a click )
1732
- {
1737
+ else if (!this.movingKeys && !discard) { // if not moving timeline and not adding keyframes through e.shiftkey (just a click )
1733
1738
  if (this.lastKeyFramesSelected.length) {
1734
1739
  if (this.onDeselectKeyFrames) {
1735
1740
  this.onDeselectKeyFrames(this.lastKeyFramesSelected);
@@ -1751,17 +1756,15 @@ class KeyFramesTimeline extends Timeline {
1751
1756
  let localX = e.localX;
1752
1757
  e.localY;
1753
1758
  e.track;
1754
- if ((e.ctrlKey || e.altKey) && this.lastKeyFramesSelected.length) // move keyframes
1755
- {
1759
+ if ((e.ctrlKey || e.altKey) && this.lastKeyFramesSelected.length) { // move keyframes
1756
1760
  this.movingKeys = true;
1757
- this.canvas.style.cursor = "grab";
1761
+ this.canvas.style.cursor = 'grab';
1758
1762
  this.canvas.classList.add('grabbing');
1759
1763
  // Set pre-move state
1760
1764
  this.moveKeyMinTime = Infinity;
1761
1765
  const tracks = this.animationClip.tracks;
1762
1766
  let lastTrackIdx = -1;
1763
- for (let selectedKey of this.lastKeyFramesSelected) // WARNING assumes lasKeyFramesSelected is sorted, so all keyframes of the same track are grouped
1764
- {
1767
+ for (let selectedKey of this.lastKeyFramesSelected) { // WARNING assumes lasKeyFramesSelected is sorted, so all keyframes of the same track are grouped
1765
1768
  let [trackIdx, keyIndex, keyTime] = selectedKey;
1766
1769
  const track = tracks[trackIdx];
1767
1770
  selectedKey[2] = track.times[keyIndex]; // update original time just in case
@@ -1787,8 +1790,7 @@ class KeyFramesTimeline extends Timeline {
1787
1790
  let localX = e.localX;
1788
1791
  e.localY;
1789
1792
  let track = e.track;
1790
- if (this.movingKeys) // move keyframes
1791
- {
1793
+ if (this.movingKeys) { // move keyframes
1792
1794
  let newTime = this.xToTime(localX);
1793
1795
  let deltaTime = newTime - this.timeBeforeMove;
1794
1796
  if (deltaTime + this.moveKeyMinTime < 0) {
@@ -1808,7 +1810,7 @@ class KeyFramesTimeline extends Timeline {
1808
1810
  if (track && track.locked) {
1809
1811
  continue;
1810
1812
  }
1811
- this.canvas.style.cursor = "grabbing";
1813
+ this.canvas.style.cursor = 'grabbing';
1812
1814
  const times = this.animationClip.tracks[track.trackIdx].times;
1813
1815
  times[keyIndex] = Math.max(0, times[keyIndex] + deltaTime);
1814
1816
  if (times[keyIndex] > this.duration) {
@@ -1866,8 +1868,7 @@ class KeyFramesTimeline extends Timeline {
1866
1868
  }
1867
1869
  lastTrackChanged = track.trackIdx;
1868
1870
  }
1869
- if (this.onUpdateTrack && lastTrackChanged > -1) // do the last update, once the last track has been processed
1870
- {
1871
+ if (this.onUpdateTrack && lastTrackChanged > -1) { // do the last update, once the last track has been processed
1871
1872
  this.onUpdateTrack([track.trackIdx]);
1872
1873
  }
1873
1874
  return;
@@ -1902,14 +1903,14 @@ class KeyFramesTimeline extends Timeline {
1902
1903
  let offset = scrollY;
1903
1904
  // compute track from which to start rendering ( avoid rendering unseen tracks )
1904
1905
  let startElIdx = 0;
1905
- if (offset < -this.lastTrackTreesComponentOffset) // offset 0 = ( 0 of canvas ) + track-Tree-Offset. This renders tracks under the time zone
1906
- {
1906
+ if (offset < -this.lastTrackTreesComponentOffset) { // offset 0 = ( 0 of canvas ) + track-Tree-Offset. This renders tracks under the time zone
1907
1907
  startElIdx = Math.floor(-(offset + this.lastTrackTreesComponentOffset) / this.trackHeight); // how many tracks to skip
1908
1908
  offset += startElIdx * this.trackHeight;
1909
1909
  }
1910
1910
  ctx.translate(0, offset);
1911
1911
  // compute track to end rendering ( avoid rendering unseen tracks )
1912
- let endElIdx = startElIdx + Math.ceil((ctx.canvas.height - this.lastTrackTreesComponentOffset - offset) / this.trackHeight);
1912
+ let endElIdx = startElIdx
1913
+ + Math.ceil((ctx.canvas.height - this.lastTrackTreesComponentOffset - offset) / this.trackHeight);
1913
1914
  endElIdx = endElIdx > visibleElements.length ? visibleElements.length : endElIdx;
1914
1915
  for (let t = startElIdx; t < endElIdx; t++) {
1915
1916
  const track = visibleElements[t].treeData.trackData;
@@ -1925,13 +1926,12 @@ class KeyFramesTimeline extends Timeline {
1925
1926
  }
1926
1927
  ctx.restore();
1927
1928
  }
1928
- ;
1929
1929
  /**
1930
1930
  * @method drawTrackWithKeyframes
1931
1931
  * @param {*} ctx
1932
1932
  * ...
1933
1933
  * @description helper function, you can call it from drawContent to render all the keyframes
1934
- */
1934
+ */
1935
1935
  drawTrackWithKeyframes(ctx, trackHeight, track) {
1936
1936
  if (track.isSelected) {
1937
1937
  ctx.globalAlpha = 0.2;
@@ -1990,23 +1990,27 @@ class KeyFramesTimeline extends Timeline {
1990
1990
  const values = track.values;
1991
1991
  const defaultPointSize = this.keyframeSize * 0.5; // radius
1992
1992
  const hoverPointSize = this.keyframeSizeHovered * 0.5; // radius
1993
- const valueRange = track.curvesRange; //[ min, max ]
1993
+ const valueRange = track.curvesRange; // [ min, max ]
1994
1994
  const displayRange = trackHeight - defaultPointSize * 2;
1995
1995
  const startTime = this.visualTimeRange[0];
1996
1996
  const endTime = this.visualTimeRange[1] + 0.0000001;
1997
- //draw lines
1997
+ // draw lines
1998
1998
  ctx.strokeStyle = KeyFramesTimeline.FONT_COLOR_PRIMARY;
1999
1999
  ctx.beginPath();
2000
2000
  if (keyframes.length > 1) {
2001
2001
  let startPosX = this.timeToX(keyframes[0]);
2002
2002
  let startValue = values[0];
2003
- startValue = LX.clamp((startValue - valueRange[0]) / (valueRange[1] - valueRange[0]), 0, 1) * (-displayRange) + (trackHeight - defaultPointSize); // normalize and offset
2003
+ startValue =
2004
+ LX.clamp((startValue - valueRange[0]) / (valueRange[1] - valueRange[0]), 0, 1) * (-displayRange)
2005
+ + (trackHeight - defaultPointSize); // normalize and offset
2004
2006
  ctx.moveTo(startPosX, startValue);
2005
2007
  for (let j = 1; j < keyframes.length; ++j) {
2006
2008
  let time = keyframes[j];
2007
2009
  let keyframePosX = this.timeToX(time);
2008
2010
  let value = values[j];
2009
- value = LX.clamp((value - valueRange[0]) / (valueRange[1] - valueRange[0]), 0, 1) * (-displayRange) + (trackHeight - defaultPointSize); // normalize and offset
2011
+ value =
2012
+ LX.clamp((value - valueRange[0]) / (valueRange[1] - valueRange[0]), 0, 1) * (-displayRange)
2013
+ + (trackHeight - defaultPointSize); // normalize and offset
2010
2014
  if (time < startTime) {
2011
2015
  ctx.moveTo(keyframePosX, value);
2012
2016
  continue;
@@ -2016,41 +2020,49 @@ class KeyFramesTimeline extends Timeline {
2016
2020
  let dt = keyframePosX - lastKeyframePosX;
2017
2021
  if (dt > 0) {
2018
2022
  let lastValue = values[j - 1];
2019
- lastValue = LX.clamp((lastValue - valueRange[0]) / (valueRange[1] - valueRange[0]), 0, 1) * (-displayRange) + (trackHeight - defaultPointSize); // normalize and offset
2023
+ lastValue = LX.clamp((lastValue - valueRange[0]) / (valueRange[1] - valueRange[0]), 0, 1)
2024
+ * (-displayRange) + (trackHeight - defaultPointSize); // normalize and offset
2020
2025
  let f = (this.timeToX(endTime) - lastKeyframePosX) / dt;
2021
2026
  ctx.lineTo(lastKeyframePosX + dt * f, lastValue * (1 - f) + value * f);
2022
2027
  }
2023
- break; //end loop, but print line
2028
+ break; // end loop, but print line
2024
2029
  }
2025
- //convert to timeline track range
2030
+ // convert to timeline track range
2026
2031
  ctx.lineTo(keyframePosX, value);
2027
2032
  }
2028
2033
  ctx.stroke();
2029
2034
  }
2030
- //draw points
2035
+ // draw points
2031
2036
  ctx.fillStyle = Timeline.KEYFRAME_COLOR;
2032
2037
  for (let j = 0; j < keyframes.length; ++j) {
2033
2038
  let time = keyframes[j];
2034
- if (time < startTime || time > endTime)
2039
+ if (time < startTime || time > endTime) {
2035
2040
  continue;
2041
+ }
2036
2042
  let size = defaultPointSize;
2037
2043
  let keyframePosX = this.timeToX(time);
2038
- if (!this.active || !track.active)
2044
+ if (!this.active || !track.active) {
2039
2045
  ctx.fillStyle = Timeline.KEYFRAME_COLOR_INACTIVE;
2040
- else if (track.locked)
2046
+ }
2047
+ else if (track.locked) {
2041
2048
  ctx.fillStyle = Timeline.KEYFRAME_COLOR_LOCK;
2049
+ }
2042
2050
  else if (track.hovered[j]) {
2043
2051
  size = hoverPointSize;
2044
2052
  ctx.fillStyle = Timeline.KEYFRAME_COLOR_HOVERED;
2045
2053
  }
2046
- else if (track.selected[j])
2054
+ else if (track.selected[j]) {
2047
2055
  ctx.fillStyle = Timeline.KEYFRAME_COLOR_SELECTED;
2048
- else if (track.edited[j])
2056
+ }
2057
+ else if (track.edited[j]) {
2049
2058
  ctx.fillStyle = Timeline.KEYFRAME_COLOR_EDITED;
2050
- else
2059
+ }
2060
+ else {
2051
2061
  ctx.fillStyle = Timeline.KEYFRAME_COLOR;
2062
+ }
2052
2063
  let value = values[j];
2053
- value = LX.clamp((value - valueRange[0]) / (valueRange[1] - valueRange[0]), 0, 1) * (-displayRange) + (trackHeight - defaultPointSize); // normalize, clamp and offset
2064
+ value = LX.clamp((value - valueRange[0]) / (valueRange[1] - valueRange[0]), 0, 1) * (-displayRange)
2065
+ + (trackHeight - defaultPointSize); // normalize, clamp and offset
2054
2066
  ctx.beginPath();
2055
2067
  ctx.arc(keyframePosX, value, size, 0, Math.PI * 2);
2056
2068
  ctx.fill();
@@ -2062,12 +2074,12 @@ class KeyFramesTimeline extends Timeline {
2062
2074
  let trackId = null;
2063
2075
  let trackNameInfo;
2064
2076
  // Support other versions
2065
- if (uglyName.includes("[")) {
2077
+ if (uglyName.includes('[')) {
2066
2078
  const nameIndex = uglyName.indexOf('[');
2067
- trackNameInfo = uglyName.substring(nameIndex + 1).split("].");
2079
+ trackNameInfo = uglyName.substring(nameIndex + 1).split('].');
2068
2080
  }
2069
2081
  else {
2070
- trackNameInfo = uglyName.split(".");
2082
+ trackNameInfo = uglyName.split('.');
2071
2083
  }
2072
2084
  if (trackNameInfo.length > 1) {
2073
2085
  groupId = trackNameInfo[0];
@@ -2085,8 +2097,9 @@ class KeyFramesTimeline extends Timeline {
2085
2097
  * @returns
2086
2098
  */
2087
2099
  updateTrack(trackIdx, newTrack) {
2088
- if (!this.animationClip)
2100
+ if (!this.animationClip) {
2089
2101
  return false;
2102
+ }
2090
2103
  const track = this.animationClip.tracks[trackIdx];
2091
2104
  track.values = newTrack.values;
2092
2105
  track.times = newTrack.times;
@@ -2109,7 +2122,9 @@ class KeyFramesTimeline extends Timeline {
2109
2122
  if (track.locked) {
2110
2123
  return;
2111
2124
  }
2112
- let cmpFunction = (v, p, n, t) => { return Math.abs(v - p) >= t || Math.abs(v - n) >= t; };
2125
+ let cmpFunction = (v, p, n, t) => {
2126
+ return Math.abs(v - p) >= t || Math.abs(v - n) >= t;
2127
+ };
2113
2128
  let lastSavedIndex = 0;
2114
2129
  const lastIndex = times.length - 1;
2115
2130
  this.saveState(track.trackIdx);
@@ -2221,22 +2236,19 @@ class KeyFramesTimeline extends Timeline {
2221
2236
  track.times = state.t;
2222
2237
  track.values = state.v;
2223
2238
  track.edited = state.edited;
2224
- if (track.selected.length != track.times.length) {
2239
+ if (track.selected.length != track.times.length)
2225
2240
  track.selected.length = track.times.length;
2226
- }
2227
- if (track.hovered.length != track.times.length) {
2241
+ if (track.hovered.length != track.times.length)
2228
2242
  track.hovered.length = track.times.length;
2229
- }
2230
2243
  track.selected.fill(false);
2231
2244
  track.hovered.fill(false);
2232
2245
  return stateToReturn;
2233
2246
  }
2234
2247
  /**
2235
- *
2236
- * @param {*} track
2237
- * @param {Number} srcIdx keyFrame index
2238
- * @param {Number} trgIdx keyFrame index
2239
- */
2248
+ * @param {*} track
2249
+ * @param {Number} srcIdx keyFrame index
2250
+ * @param {Number} trgIdx keyFrame index
2251
+ */
2240
2252
  swapKeyFrames(track, srcIdx, trgIdx) {
2241
2253
  const times = track.times;
2242
2254
  const values = track.values;
@@ -2352,9 +2364,8 @@ class KeyFramesTimeline extends Timeline {
2352
2364
  const clipboardItem = this.animationClip.tracks[trackIdx];
2353
2365
  // ensure all tracks are visible
2354
2366
  const idx = this.selectedItems.findIndex((item) => {
2355
- if (item.isTrack) {
2367
+ if (item.isTrack)
2356
2368
  return (item === clipboardItem);
2357
- }
2358
2369
  return item === clipboardItem.groupId;
2359
2370
  });
2360
2371
  if (idx == -1) {
@@ -2499,7 +2510,7 @@ class KeyFramesTimeline extends Timeline {
2499
2510
  return resultIndices;
2500
2511
  }
2501
2512
  deleteSelectedContent(skipCallback = false) {
2502
- //*********** WARNING: RELIES ON SORTED lastKeyFramesSelected ***********
2513
+ // *********** WARNING: RELIES ON SORTED lastKeyFramesSelected ***********
2503
2514
  if (!this.lastKeyFramesSelected.length)
2504
2515
  return;
2505
2516
  const tracks = this.animationClip.tracks;
@@ -2560,8 +2571,9 @@ class KeyFramesTimeline extends Timeline {
2560
2571
  track.times = newTimes;
2561
2572
  track.values = newValues;
2562
2573
  // Update animation action interpolation info
2563
- if (this.onDeleteKeyFrames && !skipCallback)
2574
+ if (this.onDeleteKeyFrames && !skipCallback) {
2564
2575
  this.onDeleteKeyFrames(trackIdx, indices);
2576
+ }
2565
2577
  if ((newTimes[newTimes.length - 1]) > this.duration) {
2566
2578
  this.setDuration(newTimes[newTimes.length - 1]);
2567
2579
  }
@@ -2583,7 +2595,7 @@ class KeyFramesTimeline extends Timeline {
2583
2595
  if (!track || !track.times || !track.times.length) {
2584
2596
  return -1;
2585
2597
  }
2586
- //binary search
2598
+ // binary search
2587
2599
  const times = track.times;
2588
2600
  let min = 0, max = times.length - 1;
2589
2601
  // edge cases
@@ -2596,12 +2608,10 @@ class KeyFramesTimeline extends Timeline {
2596
2608
  // time is between first and last frame
2597
2609
  let half = Math.floor((min + max) / 2);
2598
2610
  while (min < half && half < max) {
2599
- if (time < times[half]) {
2611
+ if (time < times[half])
2600
2612
  max = half;
2601
- }
2602
- else {
2613
+ else
2603
2614
  min = half;
2604
- }
2605
2615
  half = Math.floor((min + max) / 2);
2606
2616
  }
2607
2617
  if (mode == 0) {
@@ -2620,8 +2630,9 @@ class KeyFramesTimeline extends Timeline {
2620
2630
  * @returns returns a postive/zero value if there is a frame inside the threshold range. Otherwise, -1
2621
2631
  */
2622
2632
  getCurrentKeyFrame(track, time, threshold = 0.0) {
2623
- if (!track || !track.times.length)
2633
+ if (!track || !track.times.length) {
2624
2634
  return -1;
2635
+ }
2625
2636
  let frame = this.getNearestKeyFrame(track, time);
2626
2637
  if (frame > -1) {
2627
2638
  frame = Math.abs(track.times[frame] - time) > threshold ? -1 : frame;
@@ -2679,8 +2690,9 @@ class KeyFramesTimeline extends Timeline {
2679
2690
  */
2680
2691
  selectKeyFrame(trackIdx, frameIdx, skipCallback = false) {
2681
2692
  const track = this.animationClip.tracks[trackIdx];
2682
- if (track.locked || !track.active || track.selected[frameIdx])
2693
+ if (track.locked || !track.active || track.selected[frameIdx]) {
2683
2694
  return null;
2695
+ }
2684
2696
  // [ track idx, keyframe, keyframe time ]
2685
2697
  const selection = [track.trackIdx, frameIdx, track.times[frameIdx]];
2686
2698
  // sort lastkeyframeselected ascending order ( track and frame )
@@ -2700,8 +2712,9 @@ class KeyFramesTimeline extends Timeline {
2700
2712
  }
2701
2713
  deselectKeyFrame(trackIdx, frameIdx) {
2702
2714
  const track = this.animationClip.tracks[trackIdx];
2703
- if (track.locked || !track.active || !track.selected[frameIdx])
2715
+ if (track.locked || !track.active || !track.selected[frameIdx]) {
2704
2716
  return false;
2717
+ }
2705
2718
  track.selected[frameIdx] = false;
2706
2719
  for (let i = 0; i < this.lastKeyFramesSelected.length; ++i) {
2707
2720
  const sk = this.lastKeyFramesSelected[i];
@@ -2724,8 +2737,9 @@ class KeyFramesTimeline extends Timeline {
2724
2737
  */
2725
2738
  processSelectionKeyFrame(trackIdx, keyFrameIndex, multipleSelection = false) {
2726
2739
  const track = this.animationClip.tracks[trackIdx];
2727
- if (track.locked)
2740
+ if (track.locked) {
2728
2741
  return;
2742
+ }
2729
2743
  if (!multipleSelection) {
2730
2744
  this.deselectAllKeyFrames();
2731
2745
  }
@@ -2764,7 +2778,7 @@ class ClipsTimeline extends Timeline {
2764
2778
  static CLONEREASON_TRACKCLONE = 4;
2765
2779
  lastClipsSelected = [];
2766
2780
  lastTrackClipsMove = 0; // vertical movement of clips, onMouseMove onMousedown
2767
- dragClipMode = "";
2781
+ dragClipMode = '';
2768
2782
  lastHovered = null;
2769
2783
  onSelectClip = null;
2770
2784
  onContentMoved = null;
@@ -2778,7 +2792,7 @@ class ClipsTimeline extends Timeline {
2778
2792
  super(name, options);
2779
2793
  this.lastClipsSelected = [];
2780
2794
  this.lastTrackClipsMove = 0; // vertical movement of clips, onMouseMove onMousedown
2781
- this.dragClipMode = "";
2795
+ this.dragClipMode = '';
2782
2796
  this.setAnimationClip(this.animationClip);
2783
2797
  this.onDblClick = (e) => {
2784
2798
  const track = e.track;
@@ -2794,11 +2808,13 @@ class ClipsTimeline extends Timeline {
2794
2808
  let actions = [];
2795
2809
  if (this.lastClipsSelected.length) {
2796
2810
  actions.push({
2797
- title: "Copy",
2798
- callback: () => { this.copySelectedContent(); }
2811
+ title: 'Copy',
2812
+ callback: () => {
2813
+ this.copySelectedContent();
2814
+ }
2799
2815
  });
2800
2816
  actions.push({
2801
- title: "Delete",
2817
+ title: 'Delete',
2802
2818
  callback: () => {
2803
2819
  this.deleteSelectedContent();
2804
2820
  }
@@ -2807,20 +2823,20 @@ class ClipsTimeline extends Timeline {
2807
2823
  else {
2808
2824
  if (this.clipboard) {
2809
2825
  actions.push({
2810
- title: "Paste",
2826
+ title: 'Paste',
2811
2827
  callback: () => {
2812
2828
  this.pasteContent();
2813
2829
  }
2814
2830
  });
2815
2831
  actions.push({
2816
- title: "Paste Here",
2832
+ title: 'Paste Here',
2817
2833
  callback: () => {
2818
2834
  this.pasteContent(this.xToTime(e.localX));
2819
2835
  }
2820
2836
  });
2821
2837
  }
2822
2838
  }
2823
- LX.addContextMenu("Options", e, (m) => {
2839
+ LX.addContextMenu('Options', e, (m) => {
2824
2840
  for (let i = 0; i < actions.length; i++) {
2825
2841
  m.add(actions[i].title, actions[i].callback);
2826
2842
  }
@@ -2844,10 +2860,9 @@ class ClipsTimeline extends Timeline {
2844
2860
  return animationClip;
2845
2861
  }
2846
2862
  /**
2847
- *
2848
2863
  * @param {Object} options set some values for the track instance ( groups and trackIdx not included )
2849
2864
  * @returns
2850
- */
2865
+ */
2851
2866
  instantiateTrack(options = {}, clone = false) {
2852
2867
  const track = super.instantiateTrack(options);
2853
2868
  track.trackIdx = this.animationClip.tracks.length;
@@ -2855,7 +2870,9 @@ class ClipsTimeline extends Timeline {
2855
2870
  track.edited = [];
2856
2871
  track.hovered = [];
2857
2872
  if (options.clips) {
2858
- track.clips = clone ? this.cloneClips(options.clips, 0, ClipsTimeline.CLONEREASON_TRACKCLONE) : options.clips;
2873
+ track.clips = clone
2874
+ ? this.cloneClips(options.clips, 0, ClipsTimeline.CLONEREASON_TRACKCLONE)
2875
+ : options.clips;
2859
2876
  }
2860
2877
  else {
2861
2878
  track.clips = [];
@@ -2888,15 +2905,15 @@ class ClipsTimeline extends Timeline {
2888
2905
  // provides an base example of a proper clip
2889
2906
  instantiateClip(options = {}) {
2890
2907
  return {
2891
- id: options.id ?? (options.name ?? "clip"),
2908
+ id: options.id ?? (options.name ?? 'clip'),
2892
2909
  start: options.start ?? 0,
2893
2910
  duration: options.duration ?? 1,
2894
2911
  fadein: options.fadein ?? undefined,
2895
2912
  fadeout: options.fadeout ?? undefined,
2896
- clipColor: options.clipColor ?? LX.getThemeColor("global-color-accent"),
2913
+ clipColor: options.clipColor ?? LX.getThemeColor('global-color-accent'),
2897
2914
  fadeColor: options.fadeColor ?? null,
2898
2915
  active: options.active ?? true,
2899
- trackIdx: -1, // filled by addClip
2916
+ trackIdx: -1 // filled by addClip
2900
2917
  };
2901
2918
  }
2902
2919
  // use default updateleftpanel
@@ -2953,9 +2970,9 @@ class ClipsTimeline extends Timeline {
2953
2970
  if (track) {
2954
2971
  let clipIndex = this.getClipOnTime(track, this.xToTime(localX), this.secondsPerPixel * 5);
2955
2972
  if (clipIndex > -1) {
2956
- track.selected[clipIndex] ?
2957
- this.deselectClip(track.trackIdx, clipIndex) :
2958
- this.selectClip(track.trackIdx, clipIndex, false);
2973
+ track.selected[clipIndex]
2974
+ ? this.deselectClip(track.trackIdx, clipIndex)
2975
+ : this.selectClip(track.trackIdx, clipIndex, false);
2959
2976
  }
2960
2977
  }
2961
2978
  }
@@ -2965,16 +2982,18 @@ class ClipsTimeline extends Timeline {
2965
2982
  for (let t of tracks) {
2966
2983
  let clipsIndices = this.getClipsInRange(t, this.xToTime(this.boxSelectionStart[0]), this.xToTime(this.boxSelectionEnd[0]), 0.000001);
2967
2984
  if (clipsIndices) {
2968
- for (let index of clipsIndices)
2985
+ for (let index of clipsIndices) {
2969
2986
  this.selectClip(t.trackIdx, index, false);
2987
+ }
2970
2988
  }
2971
2989
  }
2972
2990
  }
2973
2991
  }
2974
2992
  else {
2975
2993
  let boundingBox = this.canvas.getBoundingClientRect();
2976
- if (e.y < boundingBox.top || e.y > boundingBox.bottom)
2994
+ if (e.y < boundingBox.top || e.y > boundingBox.bottom) {
2977
2995
  return;
2996
+ }
2978
2997
  // Check exact track clip
2979
2998
  if (!discard && track) {
2980
2999
  if (e.button != 2) {
@@ -2993,12 +3012,11 @@ class ClipsTimeline extends Timeline {
2993
3012
  if (e.button > 0) {
2994
3013
  return;
2995
3014
  }
2996
- if (e.ctrlKey && track) // move clips
2997
- {
3015
+ if (e.ctrlKey && track) { // move clips
2998
3016
  let x = e.offsetX;
2999
3017
  // clip selection is done on MouseUP
3000
3018
  const selectedClips = this.lastClipsSelected;
3001
- this.canvas.style.cursor = "grab";
3019
+ this.canvas.style.cursor = 'grab';
3002
3020
  let curTrackIdx = -1;
3003
3021
  this.lastTrackClipsMove = Math.floor((e.localY - this.topMargin + this.trackTreesPanel.root.scrollTop) / this.trackHeight);
3004
3022
  for (let i = 0; i < selectedClips.length; i++) {
@@ -3006,13 +3024,13 @@ class ClipsTimeline extends Timeline {
3006
3024
  const clip = this.animationClip.tracks[trackIndex].clips[clipIndex];
3007
3025
  let endingX = this.timeToX(clip.start + clip.duration);
3008
3026
  if (Math.abs(endingX - x) < 5) {
3009
- this.dragClipMode = "duration";
3010
- this.canvas.style.cursor = "column-resize";
3027
+ this.dragClipMode = 'duration';
3028
+ this.canvas.style.cursor = 'column-resize';
3011
3029
  }
3012
3030
  else {
3013
- this.dragClipMode = "move";
3031
+ this.dragClipMode = 'move';
3014
3032
  }
3015
- //*********** WARNING: RELIES ON SORTED lastClipsSelected ***********
3033
+ // *********** WARNING: RELIES ON SORTED lastClipsSelected ***********
3016
3034
  if (curTrackIdx != trackIndex) {
3017
3035
  this.saveState(trackIndex, curTrackIdx != -1);
3018
3036
  curTrackIdx = trackIndex;
@@ -3020,8 +3038,7 @@ class ClipsTimeline extends Timeline {
3020
3038
  }
3021
3039
  this.movingKeys = true;
3022
3040
  }
3023
- else if (!track || track && this.getClipOnTime(track, time, 0.001) == -1) // clicked on empty space
3024
- {
3041
+ else if (!track || track && this.getClipOnTime(track, time, 0.001) == -1) { // clicked on empty space
3025
3042
  if (this.lastClipsSelected.length) {
3026
3043
  this.deselectAllClips();
3027
3044
  if (this.onSelectClip) {
@@ -3029,8 +3046,8 @@ class ClipsTimeline extends Timeline {
3029
3046
  }
3030
3047
  }
3031
3048
  }
3032
- else if (track && (this.dragClipMode == "duration" || this.dragClipMode == "fadein" || this.dragClipMode == "fadeout")) // clicked while mouse was over fadeIn, fadeOut, duration
3033
- {
3049
+ else if (track
3050
+ && (this.dragClipMode == 'duration' || this.dragClipMode == 'fadein' || this.dragClipMode == 'fadeout')) { // clicked while mouse was over fadeIn, fadeOut, duration
3034
3051
  const clipIdx = this.getClipOnTime(track, this.xToTime(localX), 0.001);
3035
3052
  this.selectClip(track.trackIdx, clipIdx); // select current clip if any ( deselect others )
3036
3053
  if (this.lastClipsSelected.length) {
@@ -3048,30 +3065,29 @@ class ClipsTimeline extends Timeline {
3048
3065
  this.unHoverAll();
3049
3066
  let delta = time - this.grabTime;
3050
3067
  this.grabTime = time;
3051
- if (time < 0 && delta > 0) {
3068
+ if (time < 0 && delta > 0)
3052
3069
  delta = 0;
3053
- }
3054
- if (this.dragClipMode != "move" && this.lastClipsSelected.length == 1) // change fade and duration of clips
3055
- {
3070
+ if (this.dragClipMode != 'move' && this.lastClipsSelected.length == 1) { // change fade and duration of clips
3056
3071
  const track = this.animationClip.tracks[this.lastClipsSelected[0][0]];
3057
3072
  let clip = track.clips[this.lastClipsSelected[0][1]];
3058
- if (this.dragClipMode == "fadein") {
3073
+ if (this.dragClipMode == 'fadein') {
3059
3074
  clip.fadein = Math.min(Math.max(clip.fadein + delta, clip.start), clip.fadeout ?? (clip.start + clip.duration));
3060
3075
  }
3061
- else if (this.dragClipMode == "fadeout") {
3076
+ else if (this.dragClipMode == 'fadeout') {
3062
3077
  clip.fadeout = Math.max(Math.min(clip.fadeout + delta, clip.start + clip.duration), clip.fadein ?? clip.start);
3063
3078
  }
3064
- else if (this.dragClipMode == "duration") {
3079
+ else if (this.dragClipMode == 'duration') {
3065
3080
  let duration = Math.max(0, clip.duration + delta);
3066
- if (this.lastClipsSelected[0][1] < track.clips.length - 1) // max next clip's start
3067
- {
3081
+ if (this.lastClipsSelected[0][1] < track.clips.length - 1) { // max next clip's start
3068
3082
  duration = Math.min(track.clips[this.lastClipsSelected[0][1] + 1].start - clip.start - 0.0001, duration);
3069
3083
  }
3070
3084
  clip.duration = duration;
3071
- if (clip.fadeout != undefined)
3085
+ if (clip.fadeout != undefined) {
3072
3086
  clip.fadeout = Math.max(Math.min((clip.fadeout ?? (clip.start + clip.duration)) + delta, clip.start + clip.duration), clip.start);
3073
- if (clip.fadein != undefined)
3074
- clip.fadein = Math.max(Math.min((clip.fadein ?? (clip.start + clip.duration)), (clip.fadeout ?? (clip.start + clip.duration))), clip.start);
3087
+ }
3088
+ if (clip.fadein != undefined) {
3089
+ clip.fadein = Math.max(Math.min(clip.fadein ?? (clip.start + clip.duration), clip.fadeout ?? (clip.start + clip.duration)), clip.start);
3090
+ }
3075
3091
  if (this.duration < clip.start + clip.duration)
3076
3092
  this.setDuration(clip.start + clip.duration);
3077
3093
  }
@@ -3079,9 +3095,8 @@ class ClipsTimeline extends Timeline {
3079
3095
  this.onContentMoved(clip, 0);
3080
3096
  }
3081
3097
  }
3082
- else if (this.dragClipMode == "move" && this.lastClipsSelected.length) // move clips
3083
- {
3084
- //*********** WARNING: RELIES ON SORTED lastClipsSelected ***********
3098
+ else if (this.dragClipMode == 'move' && this.lastClipsSelected.length) { // move clips
3099
+ // *********** WARNING: RELIES ON SORTED lastClipsSelected ***********
3085
3100
  const treeOffset = this.lastTrackTreesComponentOffset;
3086
3101
  let newTrackClipsMove = Math.floor((e.localY - treeOffset) / this.trackHeight);
3087
3102
  // move clips vertically
@@ -3117,7 +3132,8 @@ class ClipsTimeline extends Timeline {
3117
3132
  this.historySaveEnabler = false;
3118
3133
  const selectedClips = this.lastClipsSelected;
3119
3134
  this.lastClipsSelected = []; // avoid delete and addclips index reassignment loop ( not necessary because of order of operations in for )
3120
- for (let i = selectedClips[selectedClips.length - 1][0] + deltaTracks - this.animationClip.tracks.length + 1; i > 0; --i) {
3135
+ for (let i = selectedClips[selectedClips.length - 1][0] + deltaTracks
3136
+ - this.animationClip.tracks.length + 1; i > 0; --i) {
3121
3137
  this.addNewTrack(null, i == 1);
3122
3138
  if (i == 1) {
3123
3139
  this.updateLeftPanel();
@@ -3138,9 +3154,8 @@ class ClipsTimeline extends Timeline {
3138
3154
  const undoState = this.historyUndo[this.historyUndo.length - 1];
3139
3155
  let state = 0;
3140
3156
  for (; state < undoState.length; ++state) {
3141
- if (newTrackIdx == undoState[state].trackIdx) {
3157
+ if (newTrackIdx == undoState[state].trackIdx)
3142
3158
  break;
3143
- }
3144
3159
  }
3145
3160
  if (state == undoState.length) {
3146
3161
  this.historySaveEnabler = true;
@@ -3183,21 +3198,20 @@ class ClipsTimeline extends Timeline {
3183
3198
  const trackClips = track.clips;
3184
3199
  const clip = track.clips[clipIdx];
3185
3200
  if (delta >= 0) {
3186
- if (trackClips.length - 1 == clipIdx) {
3187
- continue;
3188
- } // all alowed
3201
+ if (trackClips.length - 1 == clipIdx)
3202
+ continue; // all alowed
3189
3203
  if (!track.selected[clipIdx + 1]) { // if next is selected, force AllOrNothing and let next clip manage the leastDelta
3190
- if (trackClips[clipIdx + 1].start >= (clip.start + clip.duration + delta)) {
3191
- continue;
3192
- } //has not reached next clip. Enough space. All allowed
3204
+ if (trackClips[clipIdx + 1].start >= (clip.start + clip.duration + delta))
3205
+ continue; // has not reached next clip. Enough space. All allowed
3193
3206
  const nextClip = trackClips[clipIdx + 1];
3194
3207
  leastDelta = Math.max(0, Math.min(leastDelta, nextClip.start - clip.start - clip.duration));
3195
3208
  }
3196
3209
  }
3197
3210
  else if (delta < 0) {
3198
- if (clipIdx > 0 && (trackClips[clipIdx - 1].start + trackClips[clipIdx - 1].duration) <= (clip.start + delta)) {
3199
- continue;
3200
- } // has not reached previous clip. Enough space
3211
+ if (clipIdx > 0
3212
+ && (trackClips[clipIdx - 1].start + trackClips[clipIdx - 1].duration)
3213
+ <= (clip.start + delta))
3214
+ continue; // has not reached previous clip. Enough space
3201
3215
  if (clipIdx > 0) {
3202
3216
  const prevClip = trackClips[clipIdx - 1];
3203
3217
  leastDelta = Math.min(0, Math.max(leastDelta, prevClip.start + prevClip.duration - clip.start)); // delta is a negative value, that is why the leastDelta is the max
@@ -3210,7 +3224,8 @@ class ClipsTimeline extends Timeline {
3210
3224
  if (!moveAccepted)
3211
3225
  continue;
3212
3226
  let clipsInRange = this.getClipsInRange(track, clip.start + delta, clip.start + clip.duration + delta, 0.01);
3213
- if (clipsInRange && (clipsInRange[0] != clipIdx || clipsInRange[clipsInRange.length - 1] != clipIdx)) {
3227
+ if (clipsInRange
3228
+ && (clipsInRange[0] != clipIdx || clipsInRange[clipsInRange.length - 1] != clipIdx)) {
3214
3229
  for (let c = 0; c < clipsInRange.length; ++c) {
3215
3230
  if (!track.selected[clipsInRange[c]]) {
3216
3231
  moveAccepted = false;
@@ -3221,25 +3236,22 @@ class ClipsTimeline extends Timeline {
3221
3236
  }
3222
3237
  // if moveAccepted -> use full delta
3223
3238
  // if !moveAccepted -> use leastDelta
3224
- if (moveAccepted) {
3239
+ if (moveAccepted)
3225
3240
  leastDelta = delta;
3226
- }
3227
3241
  this.grabTime = time - delta + leastDelta;
3228
- //*********** WARNING: RELIES ON SORTED lastClipsSelected ***********
3242
+ // *********** WARNING: RELIES ON SORTED lastClipsSelected ***********
3229
3243
  // move all selected clips using the computed delta.
3230
3244
  for (let i = 0; i < this.lastClipsSelected.length; ++i) {
3231
- const lcs = this.lastClipsSelected[delta > 0 ? (this.lastClipsSelected.length - 1 - i) : i]; //delta > 0, move last-to-first; delta < 0, move first-to-last
3245
+ const lcs = this.lastClipsSelected[delta > 0 ? (this.lastClipsSelected.length - 1 - i) : i]; // delta > 0, move last-to-first; delta < 0, move first-to-last
3232
3246
  const track = this.animationClip.tracks[lcs[0]];
3233
3247
  const trackClips = track.clips;
3234
3248
  let clipIdx = lcs[1];
3235
3249
  const clip = track.clips[clipIdx];
3236
3250
  clip.start += leastDelta;
3237
- if (clip.fadein != undefined) {
3251
+ if (clip.fadein != undefined)
3238
3252
  clip.fadein += leastDelta;
3239
- }
3240
- if (clip.fadeout != undefined) {
3253
+ if (clip.fadeout != undefined)
3241
3254
  clip.fadeout += leastDelta;
3242
- }
3243
3255
  // prepare swap
3244
3256
  const editedFlag = track.edited[clipIdx];
3245
3257
  const selectedFlag = track.selected[clipIdx];
@@ -3286,8 +3298,7 @@ class ClipsTimeline extends Timeline {
3286
3298
  }
3287
3299
  return true;
3288
3300
  }
3289
- else if (e.track && e.buttons == 0) // mouse not dragging, just hovering
3290
- {
3301
+ else if (e.track && e.buttons == 0) { // mouse not dragging, just hovering
3291
3302
  this.unHoverAll();
3292
3303
  let clips = this.getClipsInRange(e.track, time, time, 0.00001);
3293
3304
  if (!e.track.locked && clips) {
@@ -3297,23 +3308,20 @@ class ClipsTimeline extends Timeline {
3297
3308
  if (!clip) {
3298
3309
  return;
3299
3310
  }
3300
- if (Math.abs(e.localX - this.timeToX(clip.start + clip.duration)) < 8) // duration
3301
- {
3302
- this.canvas.style.cursor = "col-resize";
3303
- this.dragClipMode = "duration";
3311
+ if (Math.abs(e.localX - this.timeToX(clip.start + clip.duration)) < 8) { // duration
3312
+ this.canvas.style.cursor = 'col-resize';
3313
+ this.dragClipMode = 'duration';
3304
3314
  }
3305
- else if (clip.fadein != undefined && Math.abs(e.localX - this.timeToX(clip.fadein)) < 8) // fadein
3306
- {
3307
- this.canvas.style.cursor = "e-resize";
3308
- this.dragClipMode = "fadein";
3315
+ else if (clip.fadein != undefined && Math.abs(e.localX - this.timeToX(clip.fadein)) < 8) { // fadein
3316
+ this.canvas.style.cursor = 'e-resize';
3317
+ this.dragClipMode = 'fadein';
3309
3318
  }
3310
- else if (clip.fadeout != undefined && Math.abs(e.localX - this.timeToX(clip.fadeout)) < 8) // fadeout
3311
- {
3312
- this.canvas.style.cursor = "e-resize";
3313
- this.dragClipMode = "fadeout";
3319
+ else if (clip.fadeout != undefined && Math.abs(e.localX - this.timeToX(clip.fadeout)) < 8) { // fadeout
3320
+ this.canvas.style.cursor = 'e-resize';
3321
+ this.dragClipMode = 'fadeout';
3314
3322
  }
3315
3323
  else {
3316
- this.dragClipMode = "";
3324
+ this.dragClipMode = '';
3317
3325
  }
3318
3326
  }
3319
3327
  }
@@ -3350,13 +3358,13 @@ class ClipsTimeline extends Timeline {
3350
3358
  const offset = (trackHeight * 0.4) * 0.5;
3351
3359
  trackHeight *= 0.6;
3352
3360
  let selectedClipArea = null;
3353
- ctx.font = Math.floor(trackHeight * 0.8) + "px" + Timeline.FONT;
3354
- ctx.textAlign = "left";
3355
- ctx.textBaseline = "middle";
3361
+ ctx.font = Math.floor(trackHeight * 0.8) + 'px' + Timeline.FONT;
3362
+ ctx.textAlign = 'left';
3363
+ ctx.textBaseline = 'middle';
3356
3364
  for (var j = 0; j < clips.length; ++j) {
3357
3365
  selectedClipArea = null;
3358
3366
  const clip = clips[j];
3359
- //let selected = track.selected[ j ];
3367
+ // let selected = track.selected[ j ];
3360
3368
  var x = Math.floor(this.timeToX(clip.start)) + 0.5;
3361
3369
  var x2 = Math.floor(this.timeToX(clip.start + clip.duration)) + 0.5;
3362
3370
  var w = x2 - x;
@@ -3365,21 +3373,24 @@ class ClipsTimeline extends Timeline {
3365
3373
  }
3366
3374
  // Overwrite clip color state depending on its state
3367
3375
  ctx.globalAlpha = 1;
3368
- ctx.fillStyle = clip.clipColor || (track.hovered[j] ? Timeline.KEYFRAME_COLOR_HOVERED : (track.selected[j] ? Timeline.TRACK_SELECTED : Timeline.KEYFRAME_COLOR));
3376
+ ctx.fillStyle = clip.clipColor || (track.hovered[j]
3377
+ ? Timeline.KEYFRAME_COLOR_HOVERED
3378
+ : (track.selected[j] ? Timeline.TRACK_SELECTED : Timeline.KEYFRAME_COLOR));
3369
3379
  if (!this.active || !track.active || !clip.active) {
3370
3380
  ctx.fillStyle = Timeline.KEYFRAME_COLOR_INACTIVE;
3371
3381
  }
3372
3382
  // Draw clip background
3373
3383
  drawRoundRect(ctx, x, y + offset, w, trackHeight, 5, true);
3374
3384
  if (this.active && track.active && clip.active) {
3375
- ctx.fillStyle = clip.fadeColor ?? "#0004";
3385
+ ctx.fillStyle = clip.fadeColor ?? '#0004';
3376
3386
  if (clip.fadein != undefined) {
3377
3387
  const fadeinX = this.pixelsPerSecond * (clip.fadein - clip.start);
3378
3388
  drawRoundRect(ctx, x, y + offset, fadeinX, trackHeight, { tl: 5, bl: 5, tr: 0, br: 0 }, true);
3379
3389
  }
3380
3390
  if (clip.fadeout != undefined) {
3381
3391
  const fadeoutX = this.pixelsPerSecond * (clip.start + clip.duration - (clip.fadeout));
3382
- drawRoundRect(ctx, x + w - fadeoutX, y + offset, fadeoutX, trackHeight, { tl: 0, bl: 0, tr: 5, br: 5 }, true);
3392
+ drawRoundRect(ctx, x + w - fadeoutX, y + offset, fadeoutX, trackHeight, { tl: 0, bl: 0, tr: 5,
3393
+ br: 5 }, true);
3383
3394
  }
3384
3395
  }
3385
3396
  ctx.fillStyle = Timeline.TRACK_COLOR_PRIMARY;
@@ -3393,10 +3404,10 @@ class ClipsTimeline extends Timeline {
3393
3404
  ctx.shadowBlur = 0;
3394
3405
  ctx.shadowOffsetX = 0;
3395
3406
  ctx.shadowOffsetY = 0;
3396
- ctx.font = "bold" + Math.floor(trackHeight) + "px " + Timeline.FONT;
3407
+ ctx.font = 'bold' + Math.floor(trackHeight) + 'px ' + Timeline.FONT;
3397
3408
  ctx.fillStyle = Timeline.FONT_COLOR_PRIMARY;
3398
3409
  }
3399
- let text = clip.id ?? ""; //clip.id.replaceAll("_", " ").replaceAll("-", " ");
3410
+ let text = clip.id ?? ''; // clip.id.replaceAll("_", " ").replaceAll("-", " ");
3400
3411
  const textInfo = ctx.measureText(text);
3401
3412
  let textWidth = textInfo.width;
3402
3413
  if (textWidth > w && textWidth > 0) {
@@ -3405,12 +3416,12 @@ class ClipsTimeline extends Timeline {
3405
3416
  textWidth = w;
3406
3417
  }
3407
3418
  ctx.fillText(text, x + (w - textWidth) * 0.5, y + offset + trackHeight * 0.5);
3408
- ctx.fillStyle = track.hovered[j] ? "white" : "#f5f5f5"; //track.hovered[ j ] ? "white" : Timeline.FONT_COLOR_QUATERNARY;
3409
- ctx.strokeStyle = "rgba(125,125,125,0.4)";
3419
+ ctx.fillStyle = track.hovered[j] ? 'white' : '#f5f5f5'; // track.hovered[ j ] ? "white" : Timeline.FONT_COLOR_QUATERNARY;
3420
+ ctx.strokeStyle = 'rgba(125,125,125,0.4)';
3410
3421
  // Draw resize bounding
3411
3422
  drawRoundRect(ctx, x + w - 8, y + offset, 8, trackHeight, { tl: 4, bl: 4, tr: 4, br: 4 }, true, true);
3412
3423
  }
3413
- ctx.font = "12px" + Timeline.FONT;
3424
+ ctx.font = '12px' + Timeline.FONT;
3414
3425
  }
3415
3426
  /**
3416
3427
  * @method optimizeTrack
@@ -3423,34 +3434,30 @@ class ClipsTimeline extends Timeline {
3423
3434
  optimizeTracks() {
3424
3435
  }
3425
3436
  /**
3426
- *
3427
- * @param {Object} clip clip to be added
3428
- * @param {Int} trackIdx ( optional ) track where to put the clip. -1 will find the first free slot. ***WARNING*** Must call getClipsInRange, before calling this function with a valid trackdIdx
3429
- * @param {Number} offsetTime ( optional ) offset time of current time
3430
- * @param {Number} searchStartTrackIdx ( optional ) if trackIdx is set to -1, this idx will be used as the starting point to find a valid track
3431
- * @returns a zero/positive value if successful. Otherwise, -1
3432
- */
3437
+ * @param {Object} clip clip to be added
3438
+ * @param {Int} trackIdx ( optional ) track where to put the clip. -1 will find the first free slot. ***WARNING*** Must call getClipsInRange, before calling this function with a valid trackdIdx
3439
+ * @param {Number} offsetTime ( optional ) offset time of current time
3440
+ * @param {Number} searchStartTrackIdx ( optional ) if trackIdx is set to -1, this idx will be used as the starting point to find a valid track
3441
+ * @returns a zero/positive value if successful. Otherwise, -1
3442
+ */
3433
3443
  addClip(clip, trackIdx = -1, offsetTime = 0, searchStartTrackIdx = 0) {
3434
- if (!this.animationClip) {
3444
+ if (!this.animationClip)
3435
3445
  return -1;
3436
- }
3437
3446
  this.deselectAllElements(); // TODO: consider adjusting values of hovered and selected instead of deselecting everything
3438
3447
  // Update clip information
3439
3448
  let newStart = clip.start + offsetTime;
3440
3449
  if (clip.fadein != undefined)
3441
- clip.fadein += (newStart - clip.start);
3450
+ clip.fadein += newStart - clip.start;
3442
3451
  if (clip.fadeout != undefined)
3443
- clip.fadeout += (newStart - clip.start);
3452
+ clip.fadeout += newStart - clip.start;
3444
3453
  clip.start = newStart;
3445
3454
  // sanity check
3446
3455
  clip.active = clip.active ?? true;
3447
3456
  // find appropriate track
3448
- if (trackIdx >= this.animationClip.tracks.length) // new track ad the end
3449
- {
3457
+ if (trackIdx >= this.animationClip.tracks.length) { // new track ad the end
3450
3458
  trackIdx = this.addNewTrack();
3451
3459
  }
3452
- else if (trackIdx < 0) // find first free track slot
3453
- {
3460
+ else if (trackIdx < 0) { // find first free track slot
3454
3461
  for (let i = searchStartTrackIdx; i < this.animationClip.tracks.length; i++) {
3455
3462
  let clipInCurrentSlot = this.animationClip.tracks[i].clips.find((t) => {
3456
3463
  return LX.compareThresholdRange(newStart, clip.start + clip.duration, t.start, t.start + t.duration);
@@ -3473,10 +3480,10 @@ class ClipsTimeline extends Timeline {
3473
3480
  if (newIdx < 0) {
3474
3481
  newIdx = track.clips.length;
3475
3482
  }
3476
- //Save track state before add the new clip
3483
+ // Save track state before add the new clip
3477
3484
  this.saveState(trackIdx);
3478
3485
  // Add clip
3479
- track.clips.splice(newIdx, 0, clip); //insert clip into newIdx ( or push at the end )
3486
+ track.clips.splice(newIdx, 0, clip); // insert clip into newIdx ( or push at the end )
3480
3487
  // Reset this clip's properties
3481
3488
  track.hovered.splice(newIdx, 0, false);
3482
3489
  track.selected.splice(newIdx, 0, false);
@@ -3513,10 +3520,11 @@ class ClipsTimeline extends Timeline {
3513
3520
  if (c == 0) { // last search failed, move one track down and check again
3514
3521
  ++baseTrackIdx;
3515
3522
  currTrackIdx = baseTrackIdx;
3516
- while (currTrackIdx >= tracks.length) {
3523
+ while (currTrackIdx >= tracks.length)
3517
3524
  this.addNewTrack(null, false);
3518
- }
3519
- let clipsInCurrentSlot = tracks[baseTrackIdx].clips.find((t) => { return LX.compareThresholdRange(clipStart, clipEnd, t.start, t.start + t.duration); });
3525
+ let clipsInCurrentSlot = tracks[baseTrackIdx].clips.find((t) => {
3526
+ return LX.compareThresholdRange(clipStart, clipEnd, t.start, t.start + t.duration);
3527
+ });
3520
3528
  // reset search
3521
3529
  if (clipsInCurrentSlot) {
3522
3530
  c = -1;
@@ -3527,21 +3535,23 @@ class ClipsTimeline extends Timeline {
3527
3535
  }
3528
3536
  else {
3529
3537
  // check if it fits in current track
3530
- let clipsInCurrentSlot = tracks[currTrackIdx].clips.find((t) => { return LX.compareThresholdRange(clipStart, clipEnd, t.start, t.start + t.duration); });
3538
+ let clipsInCurrentSlot = tracks[currTrackIdx].clips.find((t) => {
3539
+ return LX.compareThresholdRange(clipStart, clipEnd, t.start, t.start + t.duration);
3540
+ });
3531
3541
  // check no previous added clips are in the way
3532
3542
  for (let i = c - 1; i > -1; --i) {
3533
- if (clipTrackIdxs[i] != currTrackIdx || clipsInCurrentSlot) {
3543
+ if (clipTrackIdxs[i] != currTrackIdx || clipsInCurrentSlot)
3534
3544
  break;
3535
- }
3536
3545
  clipsInCurrentSlot = LX.compareThresholdRange(clipStart, clipEnd, clips[i].start + offsetTime, clips[i].start + offsetTime + clips[i].duration);
3537
3546
  }
3538
3547
  // check if it fits in the next track
3539
3548
  if (clipsInCurrentSlot) {
3540
3549
  ++currTrackIdx;
3541
- if (currTrackIdx >= tracks.length) {
3550
+ if (currTrackIdx >= tracks.length)
3542
3551
  this.addNewTrack(null, false);
3543
- }
3544
- clipsInCurrentSlot = tracks[currTrackIdx].clips.find((t) => { return LX.compareThresholdRange(clipStart, clipEnd, t.start, t.start + t.duration); });
3552
+ clipsInCurrentSlot = tracks[currTrackIdx].clips.find((t) => {
3553
+ return LX.compareThresholdRange(clipStart, clipEnd, t.start, t.start + t.duration);
3554
+ });
3545
3555
  }
3546
3556
  // reset search
3547
3557
  if (clipsInCurrentSlot) {
@@ -3571,7 +3581,7 @@ class ClipsTimeline extends Timeline {
3571
3581
  return true;
3572
3582
  }
3573
3583
  deleteSelectedContent(skipCallback = false) {
3574
- //*********** WARNING: RELIES ON SORTED lastClipsSelected ***********
3584
+ // *********** WARNING: RELIES ON SORTED lastClipsSelected ***********
3575
3585
  if (!this.lastClipsSelected.length) {
3576
3586
  return;
3577
3587
  }
@@ -3594,7 +3604,7 @@ class ClipsTimeline extends Timeline {
3594
3604
  /** Delete clip from the timeline
3595
3605
  * @param {Number} trackIdx
3596
3606
  * @param {Number} clipIdx clip to be deleted
3597
- */
3607
+ */
3598
3608
  deleteClip(trackIdx, clipIdx, skipCallback = false) {
3599
3609
  this.saveState(trackIdx);
3600
3610
  const clip = this.#delete(trackIdx, clipIdx);
@@ -3620,12 +3630,10 @@ class ClipsTimeline extends Timeline {
3620
3630
  }
3621
3631
  }
3622
3632
  if (this.lastHovered && this.lastHovered[0] == trackIdx) {
3623
- if (this.lastHovered[1] == clipIdx) {
3633
+ if (this.lastHovered[1] == clipIdx)
3624
3634
  this.unHoverAll();
3625
- }
3626
- else if (this.lastHovered[1] > clipIdx) {
3635
+ else if (this.lastHovered[1] > clipIdx)
3627
3636
  this.lastHovered[1]--;
3628
- }
3629
3637
  }
3630
3638
  const clip = track[clipIdx];
3631
3639
  track.hovered.splice(clipIdx, 1);
@@ -3646,18 +3654,14 @@ class ClipsTimeline extends Timeline {
3646
3654
  for (let i = 0; i < clipsToReturn.length; ++i) {
3647
3655
  let clip = clipsToReturn[i];
3648
3656
  clip.start += timeOffset;
3649
- if (clip.fadein == null || clip.fadein == undefined) {
3657
+ if (clip.fadein == null || clip.fadein == undefined)
3650
3658
  clip.fadein = undefined;
3651
- }
3652
- else {
3659
+ else
3653
3660
  clip.fadein += timeOffset;
3654
- }
3655
- if (clip.fadeout == null || clip.fadeout == undefined) {
3661
+ if (clip.fadeout == null || clip.fadeout == undefined)
3656
3662
  clip.fadeout = undefined;
3657
- }
3658
- else {
3663
+ else
3659
3664
  clip.fadeout += timeOffset;
3660
- }
3661
3665
  }
3662
3666
  return clipsToReturn;
3663
3667
  }
@@ -3675,9 +3679,8 @@ class ClipsTimeline extends Timeline {
3675
3679
  for (let i = 0; i < lastClipsSelected.length; ++i) {
3676
3680
  let clip = tracks[lastClipsSelected[i][0]].clips[lastClipsSelected[i][1]];
3677
3681
  clipsToCopy.push(clip);
3678
- if (globalStart > clip.start) {
3682
+ if (globalStart > clip.start)
3679
3683
  globalStart = clip.start;
3680
- }
3681
3684
  }
3682
3685
  globalStart = Math.max(0, globalStart);
3683
3686
  this.clipboard = this.cloneClips(clipsToCopy, -globalStart, ClipsTimeline.CLONEREASON_COPY);
@@ -3718,9 +3721,8 @@ class ClipsTimeline extends Timeline {
3718
3721
  break;
3719
3722
  }
3720
3723
  }
3721
- if (this.lastHovered && this.lastHovered[0] == trackIdx) {
3724
+ if (this.lastHovered && this.lastHovered[0] == trackIdx)
3722
3725
  this.unHoverAll();
3723
- }
3724
3726
  return;
3725
3727
  }
3726
3728
  /**
@@ -3758,12 +3760,10 @@ class ClipsTimeline extends Timeline {
3758
3760
  };
3759
3761
  track.clips = state.clips;
3760
3762
  track.edited = state.edited;
3761
- if (track.selected.length < track.clips.length) {
3763
+ if (track.selected.length < track.clips.length)
3762
3764
  track.selected.length = track.clips.length;
3763
- }
3764
- if (track.hovered.length < track.clips.length) {
3765
+ if (track.hovered.length < track.clips.length)
3765
3766
  track.hovered.length = track.clips.length;
3766
- }
3767
3767
  track.selected.fill(false);
3768
3768
  track.hovered.fill(false);
3769
3769
  // sanity check. Also done in addClip
@@ -3788,7 +3788,6 @@ class ClipsTimeline extends Timeline {
3788
3788
  }
3789
3789
  return -1;
3790
3790
  }
3791
- ;
3792
3791
  deselectAllClips() {
3793
3792
  for (let [trackIdx, clipIdx] of this.lastClipsSelected) {
3794
3793
  this.animationClip.tracks[trackIdx].selected[clipIdx] = false;
@@ -3826,12 +3825,10 @@ class ClipsTimeline extends Timeline {
3826
3825
  let i = 0;
3827
3826
  for (; i < this.lastClipsSelected.length; ++i) {
3828
3827
  let t = this.lastClipsSelected[i];
3829
- if (t[0] < track.trackIdx) {
3828
+ if (t[0] < track.trackIdx)
3830
3829
  continue;
3831
- }
3832
- if (t[0] > track.trackIdx || t[1] > clipIndex) {
3830
+ if (t[0] > track.trackIdx || t[1] > clipIndex)
3833
3831
  break;
3834
- }
3835
3832
  }
3836
3833
  this.lastClipsSelected.splice(i, 0, [track.trackIdx, clipIndex, track.clips[clipIndex]]); //
3837
3834
  track.selected[clipIndex] = true;
@@ -3861,8 +3858,9 @@ class ClipsTimeline extends Timeline {
3861
3858
  return clipIndex;
3862
3859
  }
3863
3860
  getClipsInRange(track, minTime, maxTime, threshold = 0) {
3864
- if (!track || !track.clips.length)
3861
+ if (!track || !track.clips.length) {
3865
3862
  return null;
3863
+ }
3866
3864
  // Manage negative selection
3867
3865
  if (minTime > maxTime) {
3868
3866
  let aux = minTime;
@@ -3875,18 +3873,17 @@ class ClipsTimeline extends Timeline {
3875
3873
  minTime -= threshold;
3876
3874
  maxTime += threshold;
3877
3875
  const clips = track.clips;
3878
- if (maxTime < clips[0].start || minTime > (clips[clips.length - 1].start + clips[clips.length - 1].duration)) {
3876
+ if (maxTime < clips[0].start
3877
+ || minTime > (clips[clips.length - 1].start + clips[clips.length - 1].duration)) {
3879
3878
  return null;
3880
3879
  }
3881
3880
  let indices = [];
3882
3881
  for (let i = 0; i < clips.length; ++i) {
3883
3882
  const c = clips[i];
3884
- if (c.start + c.duration < minTime) {
3883
+ if (c.start + c.duration < minTime)
3885
3884
  continue;
3886
- }
3887
- if (c.start > maxTime) {
3885
+ if (c.start > maxTime)
3888
3886
  break;
3889
- }
3890
3887
  indices.push(i);
3891
3888
  }
3892
3889
  return indices.length ? indices : null;