@checksub_team/peaks_timeline 1.15.8-alpha.0 → 1.16.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@checksub_team/peaks_timeline",
3
- "version": "1.15.8-alpha.0",
3
+ "version": "1.16.0-alpha.0",
4
4
  "description": "JavaScript UI component for displaying audio waveforms",
5
5
  "main": "./peaks.js",
6
6
  "types": "./peaks.js.d.ts",
package/peaks.js CHANGED
@@ -14446,7 +14446,7 @@ module.exports = function (Data) {
14446
14446
  var data = new Data();
14447
14447
  this._data[url] = data;
14448
14448
  this._waitingForData[url] = [source];
14449
- this._fetch(url, data, 1000, 10);
14449
+ this._fetch(url, data, 2000, 3);
14450
14450
  };
14451
14451
  DataRetriever.prototype._fetch = function (url, data, delay, limit) {
14452
14452
  var self = this;
@@ -14459,12 +14459,15 @@ module.exports = function (Data) {
14459
14459
  if (timesTried >= limit) {
14460
14460
  return Promise.reject(err);
14461
14461
  }
14462
- return fetch(url).catch(function (err) {
14463
- later(delay).then(function () {
14464
- recur(timesTried + 1, err);
14465
- });
14466
- }).then(function (response) {
14462
+ return fetch(url).then(function (response) {
14463
+ if (!response.ok) {
14464
+ throw new Error('HTTP ' + response.status + ': ' + response.statusText);
14465
+ }
14467
14466
  return response.blob();
14467
+ }).catch(function (err) {
14468
+ return later(delay).then(function () {
14469
+ return recur(timesTried + 1, err);
14470
+ });
14468
14471
  }).then(function (blob) {
14469
14472
  var type = blob.type;
14470
14473
  if (type) {
@@ -15179,16 +15182,23 @@ module.exports = function (Konva, Utils) {
15179
15182
  var sourceGroup = this._sourcesGroup[source.id];
15180
15183
  delete this._sourcesGroup[source.id];
15181
15184
  if (isPermanent) {
15182
- if (this._sources[source.id].prevSourceId) {
15183
- this._sources[this._sources[source.id].prevSourceId].nextSourceId = this._sources[source.id].nextSourceId;
15185
+ var sourceData = this._sources[source.id];
15186
+ delete this._sources[source.id];
15187
+ if (Object.keys(this._sources).length === 0) {
15188
+ setTimeout(function () {
15189
+ this._peaks.emit('line.remove', this._position);
15190
+ }.bind(this), 0);
15191
+ return sourceGroup;
15184
15192
  }
15185
- if (this._sources[source.id].nextSourceId) {
15186
- this._sources[this._sources[source.id].nextSourceId].prevSourceId = this._sources[source.id].prevSourceId;
15193
+ if (sourceData.prevSourceId) {
15194
+ this._sources[sourceData.prevSourceId].nextSourceId = sourceData.nextSourceId;
15195
+ }
15196
+ if (sourceData.nextSourceId) {
15197
+ this._sources[sourceData.nextSourceId].prevSourceId = sourceData.prevSourceId;
15187
15198
  }
15188
15199
  if (this._firstSourceId === source.id) {
15189
- this._firstSourceId = this._sources[source.id].nextSourceId;
15200
+ this._firstSourceId = sourceData.nextSourceId;
15190
15201
  }
15191
- delete this._sources[source.id];
15192
15202
  this.updateLineHeight(sourceGroup, 'remove');
15193
15203
  }
15194
15204
  return sourceGroup;
@@ -15410,6 +15420,34 @@ module.exports = function (Konva, Utils) {
15410
15420
  }
15411
15421
  return sources;
15412
15422
  };
15423
+ Line.prototype.getSourcesAround = function (time) {
15424
+ var left = null;
15425
+ var right = null;
15426
+ var overlapping = null;
15427
+ var currentId = this._firstSourceId;
15428
+ while (currentId) {
15429
+ var lineSource = this._sources[currentId];
15430
+ var source = lineSource.source;
15431
+ if (time < source.startTime) {
15432
+ right = source;
15433
+ break;
15434
+ } else if (time >= source.startTime && time <= source.endTime) {
15435
+ overlapping = source;
15436
+ break;
15437
+ } else {
15438
+ left = source;
15439
+ }
15440
+ currentId = lineSource.nextSourceId;
15441
+ }
15442
+ if (overlapping) {
15443
+ return { overlapping: overlapping };
15444
+ } else {
15445
+ return {
15446
+ left: left,
15447
+ right: right
15448
+ };
15449
+ }
15450
+ };
15413
15451
  Line.prototype.updatePosition = function (pos) {
15414
15452
  for (var sourceId in this._sources) {
15415
15453
  if (Utils.objectHasProperty(this._sources, sourceId)) {
@@ -15436,11 +15474,13 @@ module.exports = function (SegmentsGroup, Line, LineIndicator, Utils) {
15436
15474
  this._peaks = peaks;
15437
15475
  this._view = view;
15438
15476
  this._layer = layer;
15439
- this._linesBySourceId = {};
15440
15477
  this._linesByPosition = {};
15441
15478
  this._autoAddToLayer = false;
15442
15479
  this._areSourceInteractionsAllowed = true;
15443
15480
  this._areSegmentInteractionsAllowed = true;
15481
+ this._automaticallyCreatedLineId = null;
15482
+ this._automaticLineCreationPosition = null;
15483
+ this._automaticLineCreationTimeout = null;
15444
15484
  this._segmentsGroups = {};
15445
15485
  this._segmentsGroupToLine = {};
15446
15486
  this._lineId = 0;
@@ -15497,9 +15537,8 @@ module.exports = function (SegmentsGroup, Line, LineIndicator, Utils) {
15497
15537
  this._updateLinesPosition(position);
15498
15538
  };
15499
15539
  Lines.prototype._onLineRemove = function (position) {
15500
- var oldLine = this.removeLine(position);
15501
- var lineNewY = oldLine.getY();
15502
- this._updateLinesPosition(position, lineNewY);
15540
+ this.removeLine(position);
15541
+ this._updateLinesPosition(position);
15503
15542
  };
15504
15543
  Lines.prototype.changeLineHeight = function (from, to) {
15505
15544
  for (var position in this._linesByPosition) {
@@ -15517,7 +15556,6 @@ module.exports = function (SegmentsGroup, Line, LineIndicator, Utils) {
15517
15556
  }
15518
15557
  sourceGroup.getSource().position = position;
15519
15558
  this._linesByPosition[position].addSourceGroup(sourceGroup);
15520
- this._linesBySourceId[sourceGroup.getSource().id] = this._linesByPosition[position];
15521
15559
  };
15522
15560
  Lines.prototype.addSegments = function (lineId, position) {
15523
15561
  this._createLine(position);
@@ -15528,22 +15566,28 @@ module.exports = function (SegmentsGroup, Line, LineIndicator, Utils) {
15528
15566
  this._updateLinesPosition(position);
15529
15567
  };
15530
15568
  Lines.prototype.removeSourceGroup = function (source, isPermanent) {
15569
+ if (!this._linesByPosition[source.position]) {
15570
+ return null;
15571
+ }
15531
15572
  var sourceGroup = this._linesByPosition[source.position].removeSourceGroup(source, isPermanent);
15532
15573
  if (isPermanent) {
15533
- delete this._linesBySourceId[source.id];
15534
15574
  this._updateLinesPosition(source.position);
15535
15575
  }
15536
15576
  return sourceGroup;
15537
15577
  };
15538
15578
  Lines.prototype.removeLine = function (pos) {
15539
15579
  var oldLine = this._linesByPosition[pos];
15580
+ var lineId = oldLine.getId();
15581
+ if (this._automaticallyCreatedLineId === lineId) {
15582
+ this._automaticallyCreatedLineId = null;
15583
+ }
15540
15584
  oldLine.destroy();
15541
15585
  delete this._linesByPosition[pos];
15542
- this._lineIndicator.removeIndicator(oldLine.getId(), false);
15586
+ this._lineIndicator.removeIndicator(lineId, false);
15543
15587
  return oldLine;
15544
15588
  };
15545
15589
  Lines.prototype.isLineVisible = function (position) {
15546
- return this._linesByPosition[position].isVisible();
15590
+ return this._linesByPosition[position] ? this._linesByPosition[position].isVisible() : false;
15547
15591
  };
15548
15592
  Lines.prototype.getVisibleLines = function () {
15549
15593
  var positions = {};
@@ -15573,14 +15617,18 @@ module.exports = function (SegmentsGroup, Line, LineIndicator, Utils) {
15573
15617
  Lines.prototype.updateLines = function (position) {
15574
15618
  this._updateLinesPosition(position);
15575
15619
  };
15576
- Lines.prototype._updateLinesPosition = function (position, forceNewY) {
15620
+ Lines.prototype._updateLinesPosition = function (position) {
15577
15621
  var line = this._linesByPosition[position];
15578
15622
  var dy = null;
15579
15623
  var newY;
15580
- if (forceNewY) {
15581
- newY = forceNewY;
15582
- } else {
15624
+ if (line) {
15583
15625
  newY = line.getY() + line.lineHeight() + this._peaks.options.interline;
15626
+ } else {
15627
+ var previousLine;
15628
+ while ((previousLine === undefined || previousLine === null) && position > 0) {
15629
+ previousLine = this._linesByPosition[--position];
15630
+ }
15631
+ newY = previousLine ? previousLine.getY() + previousLine.lineHeight() + this._peaks.options.interline : 0;
15584
15632
  }
15585
15633
  for (var pos in this._linesByPosition) {
15586
15634
  if (Utils.objectHasProperty(this._linesByPosition, pos)) {
@@ -15596,7 +15644,7 @@ module.exports = function (SegmentsGroup, Line, LineIndicator, Utils) {
15596
15644
  }
15597
15645
  this._lineIndicator.updateIndicators();
15598
15646
  this._lineIndicator.draw();
15599
- this._view.drawSourcesLayer();
15647
+ this._view.refresh();
15600
15648
  };
15601
15649
  Lines.prototype.setOffsetY = function (frameOffset) {
15602
15650
  for (var position in this._linesByPosition) {
@@ -15630,22 +15678,75 @@ module.exports = function (SegmentsGroup, Line, LineIndicator, Utils) {
15630
15678
  }
15631
15679
  return length;
15632
15680
  };
15633
- Lines.prototype.manageVerticalPosition = function (source, newY) {
15634
- if (newY !== null && newY !== undefined) {
15635
- var pos = this.getLineOnPosition(newY);
15636
- if (pos[0] === pos[1] && pos[0] !== source.position && !this._linesByPosition[pos[0]].isSegmentsLine()) {
15637
- this.moveSourceToPosition(source, pos[0]);
15681
+ Lines.prototype.stopAutomaticLineCreation = function () {
15682
+ if (this._automaticLineCreationTimeout) {
15683
+ clearTimeout(this._automaticLineCreationTimeout);
15684
+ }
15685
+ this._automaticLineCreationTimeout = null;
15686
+ this._automaticLineCreationPosition = null;
15687
+ this._automaticallyCreatedLineId = null;
15688
+ };
15689
+ Lines.prototype.manageAutomaticLineCreation = function (pos, source) {
15690
+ if (this._automaticallyCreatedLineId !== null) {
15691
+ return;
15692
+ } else if (this._automaticLineCreationPosition !== null && this._automaticLineCreationPosition !== pos) {
15693
+ this.stopAutomaticLineCreation();
15694
+ } else if (this._automaticLineCreationTimeout) {
15695
+ return;
15696
+ }
15697
+ this._automaticLineCreationPosition = pos;
15698
+ this._automaticLineCreationTimeout = setTimeout(function () {
15699
+ this._automaticLineCreationTimeout = null;
15700
+ this._automaticallyCreatedLineId = this._createLine(pos);
15701
+ this._setInteractions(pos);
15702
+ this.moveSourceToPosition(source, pos);
15703
+ }.bind(this), this._peaks.options.automaticLineCreationDelay);
15704
+ };
15705
+ Lines.prototype.manageVerticalPosition = function (source, mouseX, mouseY) {
15706
+ if (mouseY !== null && mouseY !== undefined) {
15707
+ var linePos = this.getLinesUnderY(mouseY);
15708
+ if (linePos[0] !== linePos[1]) {
15709
+ this.manageAutomaticLineCreation(linePos[0] + 1, source);
15710
+ } else {
15711
+ this.stopAutomaticLineCreation();
15712
+ if (mouseX !== null && mouseX !== undefined && linePos[0] !== source.position && !this._linesByPosition[linePos[0]].isSegmentsLine()) {
15713
+ var mouseTime = this._view.pixelsToTime(mouseX + this._view.getFrameOffset());
15714
+ var sourceDuration = Utils.roundTime(source.endTime - source.startTime);
15715
+ if (this._hasSpaceForSourceAt(linePos[0], mouseTime, sourceDuration)) {
15716
+ this.moveSourceToPosition(source, linePos[0]);
15717
+ }
15718
+ }
15638
15719
  }
15639
15720
  }
15640
15721
  };
15722
+ Lines.prototype._hasSpaceForSourceAt = function (linePosition, mouseTime, sourceDuration) {
15723
+ var line = this._linesByPosition[linePosition];
15724
+ if (!line || line.isSegmentsLine()) {
15725
+ return false;
15726
+ }
15727
+ var sourcesAround = line.getSourcesAround(mouseTime);
15728
+ if (sourcesAround.overlapping) {
15729
+ return false;
15730
+ } else if (!sourcesAround.right) {
15731
+ return true;
15732
+ } else {
15733
+ var leftLimit = sourcesAround.left ? sourcesAround.left.endTime : 0;
15734
+ var rightLimit = sourcesAround.right.startTime;
15735
+ return sourceDuration <= Utils.roundTime(rightLimit - leftLimit);
15736
+ }
15737
+ };
15641
15738
  Lines.prototype.getLineByPosition = function (pos) {
15642
15739
  return this._linesByPosition[pos];
15643
15740
  };
15644
- Lines.prototype.getLineOnPosition = function (y) {
15741
+ Lines.prototype.getLastPosition = function () {
15742
+ var keys = Object.keys(this._linesByPosition);
15743
+ return keys.pop();
15744
+ };
15745
+ Lines.prototype.getLinesUnderY = function (y) {
15645
15746
  var height;
15646
15747
  var pos = [
15647
15748
  -1,
15648
- Number.MAX_VALUE
15749
+ this.getLastPosition() + 1
15649
15750
  ];
15650
15751
  for (var position in this._linesByPosition) {
15651
15752
  if (Utils.objectHasProperty(this._linesByPosition, position)) {
@@ -15662,7 +15763,6 @@ module.exports = function (SegmentsGroup, Line, LineIndicator, Utils) {
15662
15763
  };
15663
15764
  Lines.prototype.moveSourceToPosition = function (source, pos) {
15664
15765
  var sourceGroup = this._linesByPosition[source.position].removeSourceGroup(source, true);
15665
- delete this._linesBySourceId[source.id];
15666
15766
  sourceGroup.moveTo(this._linesByPosition[pos].getKonvaGroup());
15667
15767
  this._updateLinesPosition(source.position);
15668
15768
  this.addSourceGroup(sourceGroup, pos);
@@ -15681,9 +15781,13 @@ module.exports = function (SegmentsGroup, Line, LineIndicator, Utils) {
15681
15781
  if (currentPos < position) {
15682
15782
  y += this._linesByPosition[pos].lineHeight() + this._peaks.options.interline;
15683
15783
  } else {
15684
- if (this._linesByPosition[position]) {
15685
- this._linesByPosition[currentPos].updatePosition(currentPos + 1);
15686
- newLinesByPosition[currentPos + 1] = this._linesByPosition[currentPos];
15784
+ if (Utils.objectHasProperty(this._linesByPosition, position)) {
15785
+ var newPosition = currentPos + 1;
15786
+ this._linesByPosition[currentPos].updatePosition(newPosition);
15787
+ newLinesByPosition[newPosition] = this._linesByPosition[currentPos];
15788
+ if (!this._linesByPosition[newPosition]) {
15789
+ break;
15790
+ }
15687
15791
  }
15688
15792
  }
15689
15793
  }
@@ -15695,6 +15799,7 @@ module.exports = function (SegmentsGroup, Line, LineIndicator, Utils) {
15695
15799
  }
15696
15800
  newLinesByPosition[position] = line;
15697
15801
  this._linesByPosition = newLinesByPosition;
15802
+ return line.getId();
15698
15803
  };
15699
15804
  Lines.prototype.updateSegments = function (frameStartTime, frameEndTime) {
15700
15805
  for (var lineId in this._segmentsGroups) {
@@ -15704,10 +15809,10 @@ module.exports = function (SegmentsGroup, Line, LineIndicator, Utils) {
15704
15809
  }
15705
15810
  };
15706
15811
  Lines.prototype.manageCollision = function (source, newTimes) {
15707
- return this._linesBySourceId[source.id].manageCollision(source, newTimes);
15812
+ return this._linesByPosition[source.position].manageCollision(source, newTimes);
15708
15813
  };
15709
15814
  Lines.prototype.manageSourceOrder = function (source, newTimes) {
15710
- return this._linesBySourceId[source.id].manageSourceOrder(source, newTimes);
15815
+ return this._linesByPosition[source.position].manageSourceOrder(source, newTimes);
15711
15816
  };
15712
15817
  Lines.prototype._setInteractions = function (position) {
15713
15818
  var line = this._linesByPosition[position];
@@ -15860,7 +15965,8 @@ module.exports = function (Colors, EventEmitter, TimelineSegments, TimelineSourc
15860
15965
  autoScrollThreshold: 0.05,
15861
15966
  minSourceSize: 0.05,
15862
15967
  minSegmentSize: 0.2,
15863
- canMoveSourcesBetweenLines: true
15968
+ canMoveSourcesBetweenLines: true,
15969
+ automaticLineCreationDelay: 100
15864
15970
  };
15865
15971
  this.logger = console.error.bind(console);
15866
15972
  return this;
@@ -20265,7 +20371,6 @@ module.exports = function (SourceGroup, Lines, DataRetriever, Utils, Invoker, Ko
20265
20371
  this._peaks.on('sources.setSelected', this._onSourcesSetSelected.bind(this));
20266
20372
  this._peaks.on('source.update', this._onSourceUpdate.bind(this));
20267
20373
  this._peaks.on('data.retrieved', this._onDataRetrieved.bind(this));
20268
- this._peaks.on('sources.refresh', this._onSourcesRefresh.bind(this));
20269
20374
  this._peaks.on('segments.show', this._onSegmentsShow.bind(this));
20270
20375
  this._peaks.on('options.set.line_height', this._onOptionsLineHeightChange.bind(this));
20271
20376
  this._peaks.on('source.setIndicators', this.setIndicators.bind(this));
@@ -20308,11 +20413,14 @@ module.exports = function (SourceGroup, Lines, DataRetriever, Utils, Invoker, Ko
20308
20413
  }
20309
20414
  }
20310
20415
  if (positions) {
20311
- var frameOffset = this._view.getFrameOffset();
20312
- var width = this._view.getWidth();
20313
- this.updateSources(this._view.pixelsToTime(frameOffset), this._view.pixelsToTime(frameOffset + width));
20416
+ this.refresh();
20314
20417
  }
20315
20418
  };
20419
+ SourcesLayer.prototype.refresh = function () {
20420
+ var frameOffset = this._view.getFrameOffset();
20421
+ var width = this._view.getWidth();
20422
+ this.updateSources(this._view.pixelsToTime(frameOffset), this._view.pixelsToTime(frameOffset + width));
20423
+ };
20316
20424
  SourcesLayer.prototype._onSourceUpdate = function (source) {
20317
20425
  var redraw = false;
20318
20426
  var sourceGroup = this._sourcesGroup[source.id];
@@ -20406,9 +20514,6 @@ module.exports = function (SourceGroup, Lines, DataRetriever, Utils, Invoker, Ko
20406
20514
  }
20407
20515
  }
20408
20516
  };
20409
- SourcesLayer.prototype._onSourcesRefresh = function () {
20410
- this._layer.draw();
20411
- };
20412
20517
  SourcesLayer.prototype._onSegmentsShow = function (lineId, position) {
20413
20518
  this._lines.addSegments(lineId, position);
20414
20519
  this._view.updateTimelineLength();
@@ -20476,6 +20581,7 @@ module.exports = function (SourceGroup, Lines, DataRetriever, Utils, Invoker, Ko
20476
20581
  var mousePos = Math.min(this._view.getWidth() - this._peaks.options.autoScrollThreshold * this._view.getWidth(), Math.max(0, this._view.getPointerPosition().x));
20477
20582
  const diff = this._view.pixelsToTime(mousePos - this._mouseDownX);
20478
20583
  const timeOffsetDiff = this._view.getTimeOffset() - this._initialTimeOffset;
20584
+ const mousePosX = this._view.getPointerPosition().x;
20479
20585
  const mousePosY = this._view.getPointerPosition().y;
20480
20586
  var newEnd = 0;
20481
20587
  var shouldRedraw = false;
@@ -20488,7 +20594,7 @@ module.exports = function (SourceGroup, Lines, DataRetriever, Utils, Invoker, Ko
20488
20594
  }
20489
20595
  const {initialStartTime, initialEndTime} = this._activeElements[source.id];
20490
20596
  newEnd = Math.max(newEnd, source.endTime);
20491
- shouldRedraw = this.updateSource(source, initialStartTime + diff + timeOffsetDiff, initialEndTime + diff + timeOffsetDiff, mousePosY) || shouldRedraw;
20597
+ shouldRedraw = this.updateSource(source, initialStartTime + diff + timeOffsetDiff, initialEndTime + diff + timeOffsetDiff, mousePosX, mousePosY) || shouldRedraw;
20492
20598
  }.bind(this));
20493
20599
  if (shouldRedraw) {
20494
20600
  this.draw();
@@ -20502,13 +20608,13 @@ module.exports = function (SourceGroup, Lines, DataRetriever, Utils, Invoker, Ko
20502
20608
  return positions[source.position];
20503
20609
  });
20504
20610
  };
20505
- SourcesLayer.prototype.updateSource = function (source, startTime, endTime, newY) {
20611
+ SourcesLayer.prototype.updateSource = function (source, startTime, endTime, mouseX, mouseY) {
20506
20612
  var newTimes = {
20507
20613
  start: startTime,
20508
20614
  end: endTime
20509
20615
  };
20510
20616
  if (this._peaks.options.canMoveSourcesBetweenLines) {
20511
- this.manageVerticalPosition(source, newY);
20617
+ this.manageVerticalPosition(source, mouseX, mouseY);
20512
20618
  }
20513
20619
  newTimes = this.manageSourceOrder(source, newTimes);
20514
20620
  newTimes = this.manageCollision(source, newTimes);
@@ -20519,8 +20625,8 @@ module.exports = function (SourceGroup, Lines, DataRetriever, Utils, Invoker, Ko
20519
20625
  }
20520
20626
  return false;
20521
20627
  };
20522
- SourcesLayer.prototype.manageVerticalPosition = function (source, newY) {
20523
- return this._lines.manageVerticalPosition(source, newY);
20628
+ SourcesLayer.prototype.manageVerticalPosition = function (source, mouseX, mouseY) {
20629
+ return this._lines.manageVerticalPosition(source, mouseX, mouseY);
20524
20630
  };
20525
20631
  SourcesLayer.prototype.manageSourceOrder = function (source, newTimes) {
20526
20632
  return this._lines.manageSourceOrder(source, newTimes);
@@ -20660,7 +20766,6 @@ module.exports = function (SourceGroup, Lines, DataRetriever, Utils, Invoker, Ko
20660
20766
  this._peaks.off('sources.hide', this._onSourcesHide);
20661
20767
  this._peaks.off('source.update', this._onSourceUpdate);
20662
20768
  this._peaks.off('data.retrieved', this._onDataRetrieved);
20663
- this._peaks.off('sources.refresh', this._onSourcesRefresh);
20664
20769
  this._peaks.off('segments.show', this._onSegmentsShow);
20665
20770
  this._peaks.off('options.set.line_height', this._onOptionsLineHeightChange);
20666
20771
  this._peaks.off('source.setIndicators', this.setIndicators);
@@ -21497,6 +21602,9 @@ module.exports = function (MouseDragHandler, PlayheadLayer, SourcesLayer, ModeLa
21497
21602
  TimelineZoomView.prototype.drawSourcesLayer = function () {
21498
21603
  this._sourcesLayer.draw();
21499
21604
  };
21605
+ TimelineZoomView.prototype.refresh = function () {
21606
+ this._sourcesLayer.refresh();
21607
+ };
21500
21608
  TimelineZoomView.prototype.getSegmentsGroup = function () {
21501
21609
  return this._sourcesLayer.getSegmentsGroup();
21502
21610
  };
@@ -59,7 +59,7 @@ define([
59
59
  this._data[url] = data;
60
60
  this._waitingForData[url] = [source];
61
61
 
62
- this._fetch(url, data, 1000, 10);
62
+ this._fetch(url, data, 2000, 3);
63
63
  };
64
64
 
65
65
  DataRetriever.prototype._fetch = function(url, data, delay, limit) {
@@ -77,15 +77,19 @@ define([
77
77
  }
78
78
 
79
79
  return fetch(url)
80
+ .then(function(response) {
81
+ if (!response.ok) {
82
+ throw new Error('HTTP ' + response.status + ': ' + response.statusText);
83
+ }
84
+
85
+ return response.blob();
86
+ })
80
87
  .catch(function(err) {
81
- later(delay)
88
+ return later(delay)
82
89
  .then(function() {
83
- recur(timesTried + 1, err);
90
+ return recur(timesTried + 1, err);
84
91
  });
85
92
  })
86
- .then(function(response) {
87
- return response.blob();
88
- })
89
93
  .then(function(blob) {
90
94
  var type = blob.type;
91
95
 
package/src/line.js CHANGED
@@ -329,21 +329,30 @@ define([
329
329
  delete this._sourcesGroup[source.id];
330
330
 
331
331
  if (isPermanent) {
332
- if (this._sources[source.id].prevSourceId) {
333
- this._sources[this._sources[source.id].prevSourceId].nextSourceId
334
- = this._sources[source.id].nextSourceId;
332
+ var sourceData = this._sources[source.id];
333
+
334
+ delete this._sources[source.id];
335
+
336
+ if (Object.keys(this._sources).length === 0) {
337
+ setTimeout(function() {
338
+ this._peaks.emit('line.remove', this._position);
339
+ }.bind(this), 0);
340
+ return sourceGroup;
335
341
  }
336
342
 
337
- if (this._sources[source.id].nextSourceId) {
338
- this._sources[this._sources[source.id].nextSourceId].prevSourceId
339
- = this._sources[source.id].prevSourceId;
343
+ if (sourceData.prevSourceId) {
344
+ this._sources[sourceData.prevSourceId].nextSourceId
345
+ = sourceData.nextSourceId;
340
346
  }
341
347
 
342
- if (this._firstSourceId === source.id) {
343
- this._firstSourceId = this._sources[source.id].nextSourceId;
348
+ if (sourceData.nextSourceId) {
349
+ this._sources[sourceData.nextSourceId].prevSourceId
350
+ = sourceData.prevSourceId;
344
351
  }
345
352
 
346
- delete this._sources[source.id];
353
+ if (this._firstSourceId === source.id) {
354
+ this._firstSourceId = sourceData.nextSourceId;
355
+ }
347
356
 
348
357
  this.updateLineHeight(sourceGroup, 'remove');
349
358
  }
@@ -643,14 +652,6 @@ define([
643
652
  return newTimes;
644
653
  };
645
654
 
646
- // Line.prototype.rescale = function() {
647
- // for (var sourceId in this._sourcesGroup) {
648
- // if (Utils.objectHasProperty(this._sourcesGroup, sourceId)) {
649
- // this._sourcesGroup[sourceId].rescale();
650
- // }
651
- // }
652
- // };
653
-
654
655
  Line.prototype.getSourcesAfter = function(time) {
655
656
  const sources = [];
656
657
  var currentId = this._firstSourceId;
@@ -673,6 +674,38 @@ define([
673
674
  return sources;
674
675
  };
675
676
 
677
+ Line.prototype.getSourcesAround = function(time) {
678
+ var left = null;
679
+ var right = null;
680
+ var overlapping = null;
681
+ var currentId = this._firstSourceId;
682
+
683
+ while (currentId) {
684
+ var lineSource = this._sources[currentId];
685
+ var source = lineSource.source;
686
+
687
+ if (time < source.startTime) {
688
+ right = source;
689
+ break;
690
+ }
691
+ else if (time >= source.startTime && time <= source.endTime) {
692
+ overlapping = source;
693
+ break;
694
+ }
695
+ else {
696
+ left = source;
697
+ }
698
+ currentId = lineSource.nextSourceId;
699
+ }
700
+
701
+ if (overlapping) {
702
+ return { overlapping: overlapping };
703
+ }
704
+ else {
705
+ return { left: left, right: right };
706
+ }
707
+ };
708
+
676
709
  Line.prototype.updatePosition = function(pos) {
677
710
  for (var sourceId in this._sources) {
678
711
  if (Utils.objectHasProperty(this._sources, sourceId)) {
package/src/lines.js CHANGED
@@ -22,12 +22,15 @@ define([
22
22
  this._peaks = peaks;
23
23
  this._view = view;
24
24
  this._layer = layer;
25
- this._linesBySourceId = {};
26
25
  this._linesByPosition = {};
27
26
  this._autoAddToLayer = false;
28
27
  this._areSourceInteractionsAllowed = true;
29
28
  this._areSegmentInteractionsAllowed = true;
30
29
 
30
+ this._automaticallyCreatedLineId = null;
31
+ this._automaticLineCreationPosition = null;
32
+ this._automaticLineCreationTimeout = null;
33
+
31
34
  this._segmentsGroups = {};
32
35
  this._segmentsGroupToLine = {};
33
36
 
@@ -105,10 +108,8 @@ define([
105
108
  };
106
109
 
107
110
  Lines.prototype._onLineRemove = function(position) {
108
- var oldLine = this.removeLine(position);
109
- var lineNewY = oldLine.getY();
110
-
111
- this._updateLinesPosition(position, lineNewY);
111
+ this.removeLine(position);
112
+ this._updateLinesPosition(position);
112
113
  };
113
114
 
114
115
  Lines.prototype.changeLineHeight = function(from, to) {
@@ -129,7 +130,6 @@ define([
129
130
 
130
131
  sourceGroup.getSource().position = position;
131
132
  this._linesByPosition[position].addSourceGroup(sourceGroup);
132
- this._linesBySourceId[sourceGroup.getSource().id] = this._linesByPosition[position];
133
133
  };
134
134
 
135
135
  Lines.prototype.addSegments = function(lineId, position) {
@@ -146,10 +146,13 @@ define([
146
146
  };
147
147
 
148
148
  Lines.prototype.removeSourceGroup = function(source, isPermanent) {
149
+ if (!this._linesByPosition[source.position]) {
150
+ return null;
151
+ }
152
+
149
153
  var sourceGroup = this._linesByPosition[source.position].removeSourceGroup(source, isPermanent);
150
154
 
151
155
  if (isPermanent) {
152
- delete this._linesBySourceId[source.id];
153
156
  this._updateLinesPosition(source.position);
154
157
  }
155
158
 
@@ -158,18 +161,22 @@ define([
158
161
 
159
162
  Lines.prototype.removeLine = function(pos) {
160
163
  var oldLine = this._linesByPosition[pos];
164
+ var lineId = oldLine.getId();
161
165
 
166
+ if (this._automaticallyCreatedLineId === lineId) {
167
+ this._automaticallyCreatedLineId = null;
168
+ }
162
169
  oldLine.destroy();
163
170
 
164
171
  delete this._linesByPosition[pos];
165
172
 
166
- this._lineIndicator.removeIndicator(oldLine.getId(), false);
173
+ this._lineIndicator.removeIndicator(lineId, false);
167
174
 
168
175
  return oldLine;
169
176
  };
170
177
 
171
178
  Lines.prototype.isLineVisible = function(position) {
172
- return this._linesByPosition[position].isVisible();
179
+ return this._linesByPosition[position] ? this._linesByPosition[position].isVisible() : false;
173
180
  };
174
181
 
175
182
  Lines.prototype.getVisibleLines = function() {
@@ -207,16 +214,22 @@ define([
207
214
  this._updateLinesPosition(position);
208
215
  };
209
216
 
210
- Lines.prototype._updateLinesPosition = function(position, forceNewY) {
217
+ Lines.prototype._updateLinesPosition = function(position) {
211
218
  var line = this._linesByPosition[position];
212
219
  var dy = null;
213
220
  var newY;
214
221
 
215
- if (forceNewY) {
216
- newY = forceNewY;
222
+ if (line) {
223
+ newY = line.getY() + line.lineHeight() + this._peaks.options.interline;
217
224
  }
218
225
  else {
219
- newY = line.getY() + line.lineHeight() + this._peaks.options.interline;
226
+ var previousLine;
227
+
228
+ while ((previousLine === undefined || previousLine === null) && position > 0) {
229
+ previousLine = this._linesByPosition[--position];
230
+ }
231
+
232
+ newY = previousLine ? previousLine.getY() + previousLine.lineHeight() + this._peaks.options.interline : 0;
220
233
  }
221
234
 
222
235
  for (var pos in this._linesByPosition) {
@@ -235,8 +248,7 @@ define([
235
248
 
236
249
  this._lineIndicator.updateIndicators();
237
250
  this._lineIndicator.draw();
238
-
239
- this._view.drawSourcesLayer();
251
+ this._view.refresh();
240
252
  };
241
253
 
242
254
  Lines.prototype.setOffsetY = function(frameOffset) {
@@ -282,25 +294,100 @@ define([
282
294
  return length;
283
295
  };
284
296
 
285
- Lines.prototype.manageVerticalPosition = function(source, newY) {
286
- if (newY !== null && newY !== undefined) {
287
- var pos = this.getLineOnPosition(newY);
297
+ Lines.prototype.stopAutomaticLineCreation = function() {
298
+ if (this._automaticLineCreationTimeout) {
299
+ clearTimeout(this._automaticLineCreationTimeout);
300
+ }
301
+ this._automaticLineCreationTimeout = null;
302
+ this._automaticLineCreationPosition = null;
303
+ this._automaticallyCreatedLineId = null;
304
+ };
288
305
 
289
- if (pos[0] === pos[1]
290
- && pos[0] !== source.position
291
- && !this._linesByPosition[pos[0]].isSegmentsLine()) {
292
- this.moveSourceToPosition(source, pos[0]);
306
+ Lines.prototype.manageAutomaticLineCreation = function(pos, source) {
307
+ if (this._automaticallyCreatedLineId !== null) {
308
+ return;
309
+ }
310
+ else if (
311
+ this._automaticLineCreationPosition !== null
312
+ && this._automaticLineCreationPosition !== pos
313
+ ) {
314
+ this.stopAutomaticLineCreation();
315
+ }
316
+ else if (this._automaticLineCreationTimeout) {
317
+ return;
318
+ }
319
+
320
+ this._automaticLineCreationPosition = pos;
321
+ this._automaticLineCreationTimeout = setTimeout(function() {
322
+ this._automaticLineCreationTimeout = null;
323
+ this._automaticallyCreatedLineId = this._createLine(pos);
324
+ this._setInteractions(pos);
325
+ this.moveSourceToPosition(source, pos);
326
+ }.bind(this), this._peaks.options.automaticLineCreationDelay);
327
+ };
328
+
329
+ Lines.prototype.manageVerticalPosition = function(source, mouseX, mouseY) {
330
+ if (mouseY !== null && mouseY !== undefined) {
331
+ var linePos = this.getLinesUnderY(mouseY);
332
+
333
+ if (linePos[0] !== linePos[1]) {
334
+ this.manageAutomaticLineCreation(linePos[0] + 1, source);
335
+ }
336
+ else {
337
+ this.stopAutomaticLineCreation();
338
+
339
+ if (
340
+ mouseX !== null && mouseX !== undefined
341
+ && linePos[0] !== source.position
342
+ && !this._linesByPosition[linePos[0]].isSegmentsLine()
343
+ ) {
344
+ var mouseTime = this._view.pixelsToTime(mouseX + this._view.getFrameOffset());
345
+ var sourceDuration = Utils.roundTime(source.endTime - source.startTime);
346
+
347
+ if (this._hasSpaceForSourceAt(linePos[0], mouseTime, sourceDuration)) {
348
+ this.moveSourceToPosition(source, linePos[0]);
349
+ }
350
+ }
293
351
  }
294
352
  }
295
353
  };
296
354
 
355
+ Lines.prototype._hasSpaceForSourceAt = function(linePosition, mouseTime, sourceDuration) {
356
+ var line = this._linesByPosition[linePosition];
357
+
358
+ if (!line || line.isSegmentsLine()) {
359
+ return false;
360
+ }
361
+
362
+ var sourcesAround = line.getSourcesAround(mouseTime);
363
+
364
+ if (sourcesAround.overlapping) {
365
+ return false;
366
+ }
367
+ else if (!sourcesAround.right) {
368
+ return true;
369
+ }
370
+ else {
371
+ var leftLimit = sourcesAround.left ? sourcesAround.left.endTime : 0;
372
+ var rightLimit = sourcesAround.right.startTime;
373
+
374
+ return sourceDuration <= Utils.roundTime(rightLimit - leftLimit);
375
+ }
376
+ };
377
+
297
378
  Lines.prototype.getLineByPosition = function(pos) {
298
379
  return this._linesByPosition[pos];
299
380
  };
300
381
 
301
- Lines.prototype.getLineOnPosition = function(y) {
382
+ Lines.prototype.getLastPosition = function() {
383
+ var keys = Object.keys(this._linesByPosition);
384
+
385
+ return keys.pop();
386
+ };
387
+
388
+ Lines.prototype.getLinesUnderY = function(y) {
302
389
  var height;
303
- var pos = [-1, Number.MAX_VALUE];
390
+ var pos = [-1, this.getLastPosition() + 1];
304
391
 
305
392
  for (var position in this._linesByPosition) {
306
393
  if (Utils.objectHasProperty(this._linesByPosition, position)) {
@@ -322,8 +409,6 @@ define([
322
409
  Lines.prototype.moveSourceToPosition = function(source, pos) {
323
410
  var sourceGroup = this._linesByPosition[source.position].removeSourceGroup(source, true);
324
411
 
325
- delete this._linesBySourceId[source.id];
326
-
327
412
  sourceGroup.moveTo(this._linesByPosition[pos].getKonvaGroup());
328
413
 
329
414
  this._updateLinesPosition(source.position);
@@ -348,9 +433,17 @@ define([
348
433
  y += this._linesByPosition[pos].lineHeight() + this._peaks.options.interline;
349
434
  }
350
435
  else {
351
- if (this._linesByPosition[position]) {
352
- this._linesByPosition[currentPos].updatePosition(currentPos + 1);
353
- newLinesByPosition[currentPos + 1] = this._linesByPosition[currentPos];
436
+ // This code assumes that lines are ordered in ascending order of position
437
+ // This is the case as the keys are integers
438
+ if (Utils.objectHasProperty(this._linesByPosition, position)) {
439
+ var newPosition = currentPos + 1;
440
+
441
+ this._linesByPosition[currentPos].updatePosition(newPosition);
442
+ newLinesByPosition[newPosition] = this._linesByPosition[currentPos];
443
+
444
+ if (!this._linesByPosition[newPosition]) {
445
+ break;
446
+ }
354
447
  }
355
448
  }
356
449
  }
@@ -366,6 +459,8 @@ define([
366
459
 
367
460
  newLinesByPosition[position] = line;
368
461
  this._linesByPosition = newLinesByPosition;
462
+
463
+ return line.getId();
369
464
  };
370
465
 
371
466
  Lines.prototype.updateSegments = function(frameStartTime, frameEndTime) {
@@ -377,21 +472,13 @@ define([
377
472
  };
378
473
 
379
474
  Lines.prototype.manageCollision = function(source, newTimes) {
380
- return this._linesBySourceId[source.id].manageCollision(source, newTimes);
475
+ return this._linesByPosition[source.position].manageCollision(source, newTimes);
381
476
  };
382
477
 
383
478
  Lines.prototype.manageSourceOrder = function(source, newTimes) {
384
- return this._linesBySourceId[source.id].manageSourceOrder(source, newTimes);
479
+ return this._linesByPosition[source.position].manageSourceOrder(source, newTimes);
385
480
  };
386
481
 
387
- // Lines.prototype.rescale = function() {
388
- // for (var position in this._linesByPosition) {
389
- // if (Utils.objectHasProperty(this._linesByPosition, position)) {
390
- // this._linesByPosition[position].rescale();
391
- // }
392
- // }
393
- // };
394
-
395
482
  Lines.prototype._setInteractions = function(position) {
396
483
  var line = this._linesByPosition[position];
397
484
 
package/src/main.js CHANGED
@@ -409,7 +409,13 @@ define([
409
409
  * Indicates whether or not sources can be dragged
410
410
  * from one line to another
411
411
  */
412
- canMoveSourcesBetweenLines: true
412
+ canMoveSourcesBetweenLines: true,
413
+
414
+ /**
415
+ * Delay in milliseconds before a new line is created
416
+ * when dragging a source between 2 lines.
417
+ */
418
+ automaticLineCreationDelay: 100
413
419
  };
414
420
 
415
421
  /**
@@ -56,7 +56,6 @@ define([
56
56
  this._peaks.on('sources.setSelected', this._onSourcesSetSelected.bind(this));
57
57
  this._peaks.on('source.update', this._onSourceUpdate.bind(this));
58
58
  this._peaks.on('data.retrieved', this._onDataRetrieved.bind(this));
59
- this._peaks.on('sources.refresh', this._onSourcesRefresh.bind(this));
60
59
  this._peaks.on('segments.show', this._onSegmentsShow.bind(this));
61
60
  this._peaks.on('options.set.line_height', this._onOptionsLineHeightChange.bind(this));
62
61
  this._peaks.on('source.setIndicators', this.setIndicators.bind(this));
@@ -120,16 +119,20 @@ define([
120
119
  }
121
120
 
122
121
  if (positions) {
123
- var frameOffset = this._view.getFrameOffset();
124
- var width = this._view.getWidth();
125
-
126
- this.updateSources(
127
- this._view.pixelsToTime(frameOffset),
128
- this._view.pixelsToTime(frameOffset + width)
129
- );
122
+ this.refresh();
130
123
  }
131
124
  };
132
125
 
126
+ SourcesLayer.prototype.refresh = function() {
127
+ var frameOffset = this._view.getFrameOffset();
128
+ var width = this._view.getWidth();
129
+
130
+ this.updateSources(
131
+ this._view.pixelsToTime(frameOffset),
132
+ this._view.pixelsToTime(frameOffset + width)
133
+ );
134
+ };
135
+
133
136
  SourcesLayer.prototype._onSourceUpdate = function(source) {
134
137
  var redraw = false;
135
138
  var sourceGroup = this._sourcesGroup[source.id];
@@ -252,10 +255,6 @@ define([
252
255
  }
253
256
  };
254
257
 
255
- SourcesLayer.prototype._onSourcesRefresh = function() {
256
- this._layer.draw();
257
- };
258
-
259
258
  SourcesLayer.prototype._onSegmentsShow = function(lineId, position) {
260
259
  this._lines.addSegments(lineId, position);
261
260
  this._view.updateTimelineLength();
@@ -321,7 +320,7 @@ define([
321
320
  // Update sources in visible time range.
322
321
  var sources = this.findSources(startTime, endTime);
323
322
 
324
- // Should implement virtualization on Y
323
+ // TODO: Should implement virtualization on Y
325
324
 
326
325
  var count = sources.length;
327
326
 
@@ -391,6 +390,7 @@ define([
391
390
 
392
391
  const diff = this._view.pixelsToTime(mousePos - this._mouseDownX);
393
392
  const timeOffsetDiff = this._view.getTimeOffset() - this._initialTimeOffset;
393
+ const mousePosX = this._view.getPointerPosition().x;
394
394
  const mousePosY = this._view.getPointerPosition().y;
395
395
  var newEnd = 0;
396
396
  var shouldRedraw = false;
@@ -411,6 +411,7 @@ define([
411
411
  source,
412
412
  initialStartTime + diff + timeOffsetDiff,
413
413
  initialEndTime + diff + timeOffsetDiff,
414
+ mousePosX,
414
415
  mousePosY
415
416
  ) || shouldRedraw;
416
417
  }.bind(this));
@@ -435,14 +436,14 @@ define([
435
436
  );
436
437
  };
437
438
 
438
- SourcesLayer.prototype.updateSource = function(source, startTime, endTime, newY) {
439
+ SourcesLayer.prototype.updateSource = function(source, startTime, endTime, mouseX, mouseY) {
439
440
  var newTimes = {
440
441
  start: startTime,
441
442
  end: endTime
442
443
  };
443
444
 
444
445
  if (this._peaks.options.canMoveSourcesBetweenLines) {
445
- this.manageVerticalPosition(source, newY);
446
+ this.manageVerticalPosition(source, mouseX, mouseY);
446
447
  }
447
448
 
448
449
  newTimes = this.manageSourceOrder(source, newTimes);
@@ -463,8 +464,8 @@ define([
463
464
  return false;
464
465
  };
465
466
 
466
- SourcesLayer.prototype.manageVerticalPosition = function(source, newY) {
467
- return this._lines.manageVerticalPosition(source, newY);
467
+ SourcesLayer.prototype.manageVerticalPosition = function(source, mouseX, mouseY) {
468
+ return this._lines.manageVerticalPosition(source, mouseX, mouseY);
468
469
  };
469
470
 
470
471
  SourcesLayer.prototype.manageSourceOrder = function(source, newTimes) {
@@ -635,7 +636,6 @@ define([
635
636
  };
636
637
 
637
638
  SourcesLayer.prototype.rescale = function(debounce) {
638
- // this._lines.rescale();
639
639
  if (debounce) {
640
640
  this._debouncedRescale();
641
641
  }
@@ -686,7 +686,6 @@ define([
686
686
  this._peaks.off('sources.hide', this._onSourcesHide);
687
687
  this._peaks.off('source.update', this._onSourceUpdate);
688
688
  this._peaks.off('data.retrieved', this._onDataRetrieved);
689
- this._peaks.off('sources.refresh', this._onSourcesRefresh);
690
689
  this._peaks.off('segments.show', this._onSegmentsShow);
691
690
  this._peaks.off('options.set.line_height', this._onOptionsLineHeightChange);
692
691
  this._peaks.off('source.setIndicators', this.setIndicators);
@@ -430,6 +430,10 @@ define([
430
430
  this._sourcesLayer.draw();
431
431
  };
432
432
 
433
+ TimelineZoomView.prototype.refresh = function() {
434
+ this._sourcesLayer.refresh();
435
+ };
436
+
433
437
  TimelineZoomView.prototype.getSegmentsGroup = function() {
434
438
  return this._sourcesLayer.getSegmentsGroup();
435
439
  };