@checksub_team/peaks_timeline 1.4.17 → 1.4.20

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.4.17",
3
+ "version": "1.4.20",
4
4
  "description": "JavaScript UI component for displaying audio waveforms",
5
5
  "main": "./peaks.js",
6
6
  "types": "./peaks.js.d.ts",
@@ -75,7 +75,7 @@
75
75
  "eventemitter2": "~6.0.0",
76
76
  "konva": "~4.1.3",
77
77
  "uuid": "^8.3.2",
78
- "waveform-data": "~3.1.0"
78
+ "waveform-data": "~4.0.0"
79
79
  },
80
80
  "bugs": {
81
81
  "url": "https://github.com/bbc/peaks.js/issues"
package/peaks.js CHANGED
@@ -14338,7 +14338,56 @@ module.exports = function (Utils, Konva) {
14338
14338
  };
14339
14339
  return DefaultSegmentMarker;
14340
14340
  }(_dereq_('./utils'), _dereq_('konva'));
14341
- },{"./utils":109,"konva":43}],88:[function(_dereq_,module,exports){
14341
+ },{"./utils":110,"konva":43}],88:[function(_dereq_,module,exports){
14342
+ module.exports = function () {
14343
+ 'use strict';
14344
+ function Invoker() {
14345
+ this._throttledFunc = {};
14346
+ }
14347
+ Invoker.prototype.throttle = function (id, func, wait) {
14348
+ var self = this;
14349
+ if (this._throttledFunc[id]) {
14350
+ this._throttledFunc[id].func = func;
14351
+ this._throttledFunc[id].continue = true;
14352
+ } else {
14353
+ this._throttledFunc[id] = {
14354
+ func: func,
14355
+ timer: null,
14356
+ continue: true
14357
+ };
14358
+ this._throttledFunc[id].timer = setInterval(function () {
14359
+ if (self._throttledFunc[id].continue) {
14360
+ func();
14361
+ self._throttledFunc[id].continue = false;
14362
+ } else {
14363
+ clearInterval(self._throttledFunc[id].timer);
14364
+ delete self._throttledFunc[id];
14365
+ }
14366
+ }, wait);
14367
+ }
14368
+ };
14369
+ Invoker.prototype.debounce = function (func, wait, immediate) {
14370
+ var timeout;
14371
+ return function executedFunction() {
14372
+ var _self = this;
14373
+ var args = arguments;
14374
+ function later() {
14375
+ timeout = null;
14376
+ if (!immediate) {
14377
+ func.apply(_self, args);
14378
+ }
14379
+ }
14380
+ var callNow = immediate && !timeout;
14381
+ clearTimeout(timeout);
14382
+ timeout = setTimeout(later, wait);
14383
+ if (callNow) {
14384
+ func.apply(_self, args);
14385
+ }
14386
+ };
14387
+ };
14388
+ return Invoker;
14389
+ }();
14390
+ },{}],89:[function(_dereq_,module,exports){
14342
14391
  module.exports = function () {
14343
14392
  'use strict';
14344
14393
  var nodes = [
@@ -14421,7 +14470,7 @@ module.exports = function () {
14421
14470
  };
14422
14471
  return KeyboardHandler;
14423
14472
  }();
14424
- },{}],89:[function(_dereq_,module,exports){
14473
+ },{}],90:[function(_dereq_,module,exports){
14425
14474
  module.exports = function (Konva, Utils) {
14426
14475
  'use strict';
14427
14476
  function LineIndicator(peaks, view, container) {
@@ -14642,7 +14691,7 @@ module.exports = function (Konva, Utils) {
14642
14691
  };
14643
14692
  return LineIndicator;
14644
14693
  }(_dereq_('konva'), _dereq_('./utils'));
14645
- },{"./utils":109,"konva":43}],90:[function(_dereq_,module,exports){
14694
+ },{"./utils":110,"konva":43}],91:[function(_dereq_,module,exports){
14646
14695
  module.exports = function (Konva, Utils) {
14647
14696
  'use strict';
14648
14697
  function Line(peaks, view, y, id, position) {
@@ -15048,13 +15097,6 @@ module.exports = function (Konva, Utils) {
15048
15097
  }
15049
15098
  return newXs;
15050
15099
  };
15051
- Line.prototype.rescale = function () {
15052
- for (var sourceId in this._sourcesGroup) {
15053
- if (Utils.objectHasProperty(this._sourcesGroup, sourceId)) {
15054
- this._sourcesGroup[sourceId].rescale();
15055
- }
15056
- }
15057
- };
15058
15100
  Line.prototype.updatePosition = function (pos) {
15059
15101
  for (var sourceId in this._sources) {
15060
15102
  if (Utils.objectHasProperty(this._sources, sourceId)) {
@@ -15074,7 +15116,7 @@ module.exports = function (Konva, Utils) {
15074
15116
  };
15075
15117
  return Line;
15076
15118
  }(_dereq_('konva'), _dereq_('./utils'));
15077
- },{"./utils":109,"konva":43}],91:[function(_dereq_,module,exports){
15119
+ },{"./utils":110,"konva":43}],92:[function(_dereq_,module,exports){
15078
15120
  module.exports = function (Line, LineIndicator, Utils) {
15079
15121
  'use strict';
15080
15122
  function Lines(peaks, view, layer) {
@@ -15294,13 +15336,6 @@ module.exports = function (Line, LineIndicator, Utils) {
15294
15336
  Lines.prototype.manageSourceOrder = function (source, newStartX, newEndX) {
15295
15337
  return this._linesBySourceId[source.id].manageSourceOrder(source, newStartX, newEndX);
15296
15338
  };
15297
- Lines.prototype.rescale = function () {
15298
- for (var position in this._linesByPosition) {
15299
- if (Utils.objectHasProperty(this._linesByPosition, position)) {
15300
- this._linesByPosition[position].rescale();
15301
- }
15302
- }
15303
- };
15304
15339
  Lines.prototype._setInteractions = function (position) {
15305
15340
  var line = this._linesByPosition[position];
15306
15341
  if (this._areInteractionsOverridden) {
@@ -15329,7 +15364,7 @@ module.exports = function (Line, LineIndicator, Utils) {
15329
15364
  };
15330
15365
  return Lines;
15331
15366
  }(_dereq_('./line'), _dereq_('./line-indicator'), _dereq_('./utils'));
15332
- },{"./line":90,"./line-indicator":89,"./utils":109}],92:[function(_dereq_,module,exports){
15367
+ },{"./line":91,"./line-indicator":90,"./utils":110}],93:[function(_dereq_,module,exports){
15333
15368
  module.exports = function (Colors, EventEmitter, TimelineSegments, TimelineSources, KeyboardHandler, Player, MarkerFactories, TimelineZoomView, Utils) {
15334
15369
  'use strict';
15335
15370
  function Peaks() {
@@ -15526,6 +15561,9 @@ module.exports = function (Colors, EventEmitter, TimelineSegments, TimelineSourc
15526
15561
  Peaks.prototype.allowInteractions = function (forSources, forSegments) {
15527
15562
  return this.view.allowInteractions(forSources, forSegments);
15528
15563
  };
15564
+ Peaks.prototype.checkOverlapping = function (segment, message) {
15565
+ return this.view.getSegmentsGroup().checkOverlapping(segment, message);
15566
+ };
15529
15567
  Peaks.prototype._addWindowResizeHandler = function () {
15530
15568
  this._onResize = this._onResize.bind(this);
15531
15569
  window.addEventListener('resize', this._onResize);
@@ -15553,7 +15591,7 @@ module.exports = function (Colors, EventEmitter, TimelineSegments, TimelineSourc
15553
15591
  };
15554
15592
  return Peaks;
15555
15593
  }(_dereq_('colors.css'), _dereq_('eventemitter2'), _dereq_('./timeline-segments'), _dereq_('./timeline-sources'), _dereq_('./keyboard-handler'), _dereq_('./player'), _dereq_('./marker-factories'), _dereq_('./timeline-zoomview'), _dereq_('./utils'));
15556
- },{"./keyboard-handler":88,"./marker-factories":93,"./player":96,"./timeline-segments":106,"./timeline-sources":107,"./timeline-zoomview":108,"./utils":109,"colors.css":1,"eventemitter2":2}],93:[function(_dereq_,module,exports){
15594
+ },{"./keyboard-handler":89,"./marker-factories":94,"./player":97,"./timeline-segments":107,"./timeline-sources":108,"./timeline-zoomview":109,"./utils":110,"colors.css":1,"eventemitter2":2}],94:[function(_dereq_,module,exports){
15557
15595
  module.exports = function (DefaultSegmentMarker, Utils, Konva) {
15558
15596
  'use strict';
15559
15597
  function createSegmentMarker(options) {
@@ -15585,7 +15623,7 @@ module.exports = function (DefaultSegmentMarker, Utils, Konva) {
15585
15623
  createSegmentLabel: createSegmentLabel
15586
15624
  };
15587
15625
  }(_dereq_('./default-segment-marker'), _dereq_('./utils'), _dereq_('konva'));
15588
- },{"./default-segment-marker":87,"./utils":109,"konva":43}],94:[function(_dereq_,module,exports){
15626
+ },{"./default-segment-marker":87,"./utils":110,"konva":43}],95:[function(_dereq_,module,exports){
15589
15627
  module.exports = function (Utils, SourceGroup, Konva) {
15590
15628
  'use strict';
15591
15629
  var TIME_X_OFFSET = 20;
@@ -15832,7 +15870,7 @@ module.exports = function (Utils, SourceGroup, Konva) {
15832
15870
  };
15833
15871
  return ModeLayer;
15834
15872
  }(_dereq_('./utils'), _dereq_('./source-group'), _dereq_('konva'));
15835
- },{"./source-group":102,"./utils":109,"konva":43}],95:[function(_dereq_,module,exports){
15873
+ },{"./source-group":103,"./utils":110,"konva":43}],96:[function(_dereq_,module,exports){
15836
15874
  module.exports = function (Konva) {
15837
15875
  'use strict';
15838
15876
  function getMarkerObject(obj) {
@@ -15928,7 +15966,7 @@ module.exports = function (Konva) {
15928
15966
  };
15929
15967
  return MouseDragHandler;
15930
15968
  }(_dereq_('konva'));
15931
- },{"konva":43}],96:[function(_dereq_,module,exports){
15969
+ },{"konva":43}],97:[function(_dereq_,module,exports){
15932
15970
  module.exports = function (Utils) {
15933
15971
  'use strict';
15934
15972
  function Player(peaks) {
@@ -16012,7 +16050,7 @@ module.exports = function (Utils) {
16012
16050
  };
16013
16051
  return Player;
16014
16052
  }(_dereq_('./utils'));
16015
- },{"./utils":109}],97:[function(_dereq_,module,exports){
16053
+ },{"./utils":110}],98:[function(_dereq_,module,exports){
16016
16054
  module.exports = function (Utils, Konva) {
16017
16055
  'use strict';
16018
16056
  var HANDLE_RADIUS = 10;
@@ -16252,7 +16290,7 @@ module.exports = function (Utils, Konva) {
16252
16290
  };
16253
16291
  return PlayheadLayer;
16254
16292
  }(_dereq_('./utils'), _dereq_('konva'));
16255
- },{"./utils":109,"konva":43}],98:[function(_dereq_,module,exports){
16293
+ },{"./utils":110,"konva":43}],99:[function(_dereq_,module,exports){
16256
16294
  module.exports = function (Konva) {
16257
16295
  'use strict';
16258
16296
  function SegmentMarker(options) {
@@ -16338,7 +16376,7 @@ module.exports = function (Konva) {
16338
16376
  };
16339
16377
  return SegmentMarker;
16340
16378
  }(_dereq_('konva'));
16341
- },{"konva":43}],99:[function(_dereq_,module,exports){
16379
+ },{"konva":43}],100:[function(_dereq_,module,exports){
16342
16380
  module.exports = function (Konva, SegmentMarker) {
16343
16381
  'use strict';
16344
16382
  var SEGMENT_WIDTH = 10;
@@ -16569,7 +16607,7 @@ module.exports = function (Konva, SegmentMarker) {
16569
16607
  };
16570
16608
  return SegmentShape;
16571
16609
  }(_dereq_('konva'), _dereq_('./segment-marker'));
16572
- },{"./segment-marker":98,"konva":43}],100:[function(_dereq_,module,exports){
16610
+ },{"./segment-marker":99,"konva":43}],101:[function(_dereq_,module,exports){
16573
16611
  module.exports = function (Utils) {
16574
16612
  'use strict';
16575
16613
  function validateSegment(peaks, options, context) {
@@ -16712,6 +16750,7 @@ module.exports = function (Utils) {
16712
16750
  };
16713
16751
  Utils.extend(opts, options);
16714
16752
  validateSegment(this._peaks, opts, 'update()');
16753
+ this._peaks.checkOverlapping(this, 'overlapping before manual update');
16715
16754
  this._startTime = opts.startTime;
16716
16755
  this._endTime = opts.endTime;
16717
16756
  this._labelText = opts.labelText;
@@ -16720,6 +16759,7 @@ module.exports = function (Utils) {
16720
16759
  this._handleTextColor = opts.handleTextColor;
16721
16760
  this._opacity = opts.opacity;
16722
16761
  this._editable = opts.editable;
16762
+ this._peaks.checkOverlapping(this, 'overlapping after manual update');
16723
16763
  this._peaks.emit('segment.updated', this);
16724
16764
  };
16725
16765
  Segment.prototype.isVisible = function (startTime, endTime) {
@@ -16727,7 +16767,7 @@ module.exports = function (Utils) {
16727
16767
  };
16728
16768
  return Segment;
16729
16769
  }(_dereq_('./utils'));
16730
- },{"./utils":109}],101:[function(_dereq_,module,exports){
16770
+ },{"./utils":110}],102:[function(_dereq_,module,exports){
16731
16771
  module.exports = function (SegmentShape, Utils, Konva) {
16732
16772
  'use strict';
16733
16773
  function SegmentsGroup(peaks, view, allowEditing) {
@@ -16740,6 +16780,7 @@ module.exports = function (SegmentShape, Utils, Konva) {
16740
16780
  this._segmentShapes = {};
16741
16781
  this._group = new Konva.Group();
16742
16782
  this._updatedSegments = [];
16783
+ this._overlappingSegments = [];
16743
16784
  this._isMagnetized = false;
16744
16785
  this._peaks.on('segment.updated', this._onSegmentsUpdate.bind(this));
16745
16786
  this._peaks.on('segments.add', this._onSegmentsAdd.bind(this));
@@ -16789,6 +16830,7 @@ module.exports = function (SegmentShape, Utils, Konva) {
16789
16830
  return activeSegment;
16790
16831
  };
16791
16832
  SegmentsGroup.prototype._onSegmentsUpdate = function (segment) {
16833
+ this._overlappingSegments = [];
16792
16834
  if (this._segments[segment.id]) {
16793
16835
  var redraw = false;
16794
16836
  var segmentShape = this._segmentShapes[segment.id];
@@ -16814,6 +16856,7 @@ module.exports = function (SegmentShape, Utils, Konva) {
16814
16856
  SegmentsGroup.prototype._onSegmentUpdated = function () {
16815
16857
  this._peaks.emit('segments.updated', this._updatedSegments);
16816
16858
  this._updatedSegments = [];
16859
+ this._overlappingSegments = [];
16817
16860
  };
16818
16861
  SegmentsGroup.prototype._onSegmentsAdd = function (segments) {
16819
16862
  var self = this;
@@ -16998,6 +17041,7 @@ module.exports = function (SegmentShape, Utils, Konva) {
16998
17041
  }
16999
17042
  };
17000
17043
  SegmentsGroup.prototype.updateSegment = function (segment, newStartX, newEndX) {
17044
+ this.checkOverlapping(segment, 'overlapping before dragging');
17001
17045
  var newXs = this.manageCollision(segment, newStartX, newEndX);
17002
17046
  if (newXs.startX !== null) {
17003
17047
  segment.startTime = this._view.pixelsToTime(newXs.startX);
@@ -17006,17 +17050,31 @@ module.exports = function (SegmentShape, Utils, Konva) {
17006
17050
  segment.endTime = this._view.pixelsToTime(newXs.endX);
17007
17051
  }
17008
17052
  if (newXs) {
17053
+ this.checkOverlapping(segment, 'overlapping after dragging');
17009
17054
  this._updateSegment(segment);
17010
17055
  this.addToUpdatedSegments(segment);
17011
17056
  this._draw();
17012
17057
  }
17013
17058
  };
17059
+ SegmentsGroup.prototype.checkOverlapping = function (segment, message) {
17060
+ if (this._segments[segment.id].prevSegmentId && this._segments[this._segments[segment.id].prevSegmentId].segment.endTime > segment.startTime || this._segments[segment.id].nextSegmentId && this._segments[this._segments[segment.id].nextSegmentId].segment.startTime < segment.endTime) {
17061
+ if (!this._overlappingSegments.includes(segment.id)) {
17062
+ this._peaks.emit('segments.overlap', {
17063
+ message: message,
17064
+ segment: segment,
17065
+ prevSegment: this._segments[segment.id].prevSegmentId ? this._segments[this._segments[segment.id].prevSegmentId].segment : null,
17066
+ nextSegment: this._segments[segment.id].nextSegmentId ? this._segments[this._segments[segment.id].nextSegmentId].segment : null
17067
+ });
17068
+ this._overlappingSegments.push(segment.id);
17069
+ }
17070
+ }
17071
+ };
17014
17072
  SegmentsGroup.prototype.manageCollision = function (segment, newStartX, newEndX) {
17015
17073
  var newStartTime = null;
17016
17074
  var newEndTime = null;
17017
17075
  var startLimited = false;
17018
17076
  var endLimited = false;
17019
- var segmentMagnetThreshold, width;
17077
+ var segmentMagnetThreshold, width, previousSegment, nextSegment, newXs;
17020
17078
  if (this._isMagnetized) {
17021
17079
  segmentMagnetThreshold = this._view.pixelsToTime(this._peaks.options.segmentMagnetThreshold);
17022
17080
  if (newStartX !== null && newEndX !== null) {
@@ -17026,7 +17084,7 @@ module.exports = function (SegmentShape, Utils, Konva) {
17026
17084
  if (newStartX !== null) {
17027
17085
  newStartTime = this._view.pixelsToTime(newStartX);
17028
17086
  if (this._segments[segment.id].prevSegmentId) {
17029
- var previousSegment = this._segments[this._segments[segment.id].prevSegmentId].segment;
17087
+ previousSegment = this._segments[this._segments[segment.id].prevSegmentId].segment;
17030
17088
  if (this._isMagnetized) {
17031
17089
  if (newStartTime < previousSegment.endTime + segmentMagnetThreshold) {
17032
17090
  newStartX = this._view.timeToPixels(previousSegment.endTime);
@@ -17038,14 +17096,20 @@ module.exports = function (SegmentShape, Utils, Konva) {
17038
17096
  endX: newEndX
17039
17097
  };
17040
17098
  }
17041
- } else if (segment.startTime > newStartTime) {
17099
+ } else if (segment.startTime >= newStartTime) {
17042
17100
  if (newStartTime < previousSegment.endTime) {
17043
17101
  if (previousSegment.startTime + previousSegment.minSize > newStartTime) {
17044
17102
  newStartTime = previousSegment.startTime + previousSegment.minSize;
17045
17103
  startLimited = true;
17046
17104
  }
17047
17105
  if (previousSegment.endTime !== newStartTime) {
17048
- previousSegment.endTime = newStartTime;
17106
+ newXs = this.manageCollision(previousSegment, this._view.timeToPixels(previousSegment.startTime), this._view.timeToPixels(newStartTime));
17107
+ if (newXs.startX !== null) {
17108
+ previousSegment.startTime = this._view.pixelsToTime(newXs.startX);
17109
+ }
17110
+ if (newXs.endX !== null) {
17111
+ previousSegment.endTime = this._view.pixelsToTime(newXs.endX);
17112
+ }
17049
17113
  this._updateSegment(previousSegment);
17050
17114
  this.addToUpdatedSegments(previousSegment);
17051
17115
  }
@@ -17061,7 +17125,7 @@ module.exports = function (SegmentShape, Utils, Konva) {
17061
17125
  if (newEndX !== null) {
17062
17126
  newEndTime = this._view.pixelsToTime(newEndX);
17063
17127
  if (this._segments[segment.id].nextSegmentId) {
17064
- var nextSegment = this._segments[this._segments[segment.id].nextSegmentId].segment;
17128
+ nextSegment = this._segments[this._segments[segment.id].nextSegmentId].segment;
17065
17129
  if (this._isMagnetized) {
17066
17130
  if (newEndTime > nextSegment.startTime - segmentMagnetThreshold) {
17067
17131
  newEndX = this._view.timeToPixels(nextSegment.startTime);
@@ -17073,14 +17137,20 @@ module.exports = function (SegmentShape, Utils, Konva) {
17073
17137
  endX: newEndX
17074
17138
  };
17075
17139
  }
17076
- } else if (segment.endTime < newEndTime) {
17140
+ } else if (segment.endTime <= newEndTime) {
17077
17141
  if (newEndTime > nextSegment.startTime) {
17078
17142
  if (nextSegment.endTime - nextSegment.minSize < newEndTime) {
17079
17143
  newEndTime = nextSegment.endTime - nextSegment.minSize;
17080
17144
  endLimited = true;
17081
17145
  }
17082
17146
  if (nextSegment.startTime !== newEndTime) {
17083
- nextSegment.startTime = newEndTime;
17147
+ newXs = this.manageCollision(nextSegment, this._view.timeToPixels(newEndTime), this._view.timeToPixels(nextSegment.endTime));
17148
+ if (newXs.startX !== null) {
17149
+ nextSegment.startTime = this._view.pixelsToTime(newXs.startX);
17150
+ }
17151
+ if (newXs.endX !== null) {
17152
+ nextSegment.endTime = this._view.pixelsToTime(newXs.endX);
17153
+ }
17084
17154
  this._updateSegment(nextSegment);
17085
17155
  this.addToUpdatedSegments(nextSegment);
17086
17156
  }
@@ -17090,7 +17160,15 @@ module.exports = function (SegmentShape, Utils, Konva) {
17090
17160
  }
17091
17161
  }
17092
17162
  if (newStartTime !== null && newEndTime !== null) {
17093
- if (newEndTime - newStartTime < segment.minSize) {
17163
+ if (Utils.roundTime(newEndTime - newStartTime) < segment.minSize) {
17164
+ if (previousSegment && nextSegment) {
17165
+ if (Utils.roundTime(nextSegment.startTime - previousSegment.endTime) < segment.minSize) {
17166
+ return {
17167
+ startX: null,
17168
+ endX: null
17169
+ };
17170
+ }
17171
+ }
17094
17172
  if (startLimited) {
17095
17173
  newEndTime = newStartTime + segment.minSize;
17096
17174
  } else if (endLimited) {
@@ -17098,11 +17176,11 @@ module.exports = function (SegmentShape, Utils, Konva) {
17098
17176
  }
17099
17177
  }
17100
17178
  } else if (newStartTime !== null) {
17101
- if (segment.endTime - newStartTime < segment.minSize) {
17179
+ if (Utils.roundTime(segment.endTime - newStartTime) < segment.minSize) {
17102
17180
  newStartTime = segment.endTime - segment.minSize;
17103
17181
  }
17104
17182
  } else if (newEndTime !== null) {
17105
- if (newEndTime - segment.startTime < segment.minSize) {
17183
+ if (Utils.roundTime(newEndTime - segment.startTime) < segment.minSize) {
17106
17184
  newEndTime = segment.startTime + segment.minSize;
17107
17185
  }
17108
17186
  }
@@ -17180,7 +17258,7 @@ module.exports = function (SegmentShape, Utils, Konva) {
17180
17258
  };
17181
17259
  return SegmentsGroup;
17182
17260
  }(_dereq_('./segment-shape'), _dereq_('./utils'), _dereq_('konva'));
17183
- },{"./segment-shape":99,"./utils":109,"konva":43}],102:[function(_dereq_,module,exports){
17261
+ },{"./segment-shape":100,"./utils":110,"konva":43}],103:[function(_dereq_,module,exports){
17184
17262
  module.exports = function (WaveformBuilder, WaveformShape, Utils, Konva) {
17185
17263
  'use strict';
17186
17264
  var SPACING_BETWEEN_PREVIEW_AND_BORDER_RATIO = 0.15;
@@ -17233,21 +17311,6 @@ module.exports = function (WaveformBuilder, WaveformShape, Utils, Konva) {
17233
17311
  this._addHandles(true);
17234
17312
  this.setWrapping(source.wrapped);
17235
17313
  }
17236
- SourceGroup.prototype.rescale = function () {
17237
- this.update();
17238
- this._previewList.forEach(function (preview) {
17239
- if (preview.loaded) {
17240
- switch (preview.type) {
17241
- case 'audio':
17242
- preview.group.getChildren()[0].rescale();
17243
- break;
17244
- case 'video':
17245
- case 'image':
17246
- default:
17247
- }
17248
- }
17249
- });
17250
- };
17251
17314
  SourceGroup.prototype._onSourceGroupDragStart = function () {
17252
17315
  this._dragged = true;
17253
17316
  this._mouseDownX = this._view.getPointerPosition().x;
@@ -17659,7 +17722,8 @@ module.exports = function (WaveformBuilder, WaveformShape, Utils, Konva) {
17659
17722
  group: new Konva.Group({
17660
17723
  height: this._source.binaryUrl && this._source.previewUrl ? this._source.binaryHeight : this._unwrappedHeight,
17661
17724
  listening: false
17662
- })
17725
+ }),
17726
+ url: url
17663
17727
  };
17664
17728
  var self = this;
17665
17729
  var audioData = this._layer.getLoadedData(url);
@@ -17686,6 +17750,10 @@ module.exports = function (WaveformBuilder, WaveformShape, Utils, Konva) {
17686
17750
  self._view.setTimeToPixelsMaxZoom(originalWaveformData.sample_rate / self._minScale);
17687
17751
  }
17688
17752
  self._layer.setLoadedData(url, originalWaveformData);
17753
+ self._layer.setLoadedData(url + '-scaled', {
17754
+ data: originalWaveformData,
17755
+ scale: originalWaveformData.sample_rate / self._minScale
17756
+ });
17689
17757
  preview.loaded = true;
17690
17758
  self._createAudioPreview(preview, originalWaveformData, redraw);
17691
17759
  });
@@ -17716,20 +17784,26 @@ module.exports = function (WaveformBuilder, WaveformShape, Utils, Konva) {
17716
17784
  SourceGroup.prototype._createAudioPreview = function (preview, waveformData, redraw) {
17717
17785
  if (waveformData.hasAudio) {
17718
17786
  var waveform = new WaveformShape({
17787
+ layer: this._layer,
17719
17788
  view: this._view,
17720
17789
  color: this._peaks.options.zoomWaveformColor,
17721
- waveformData: waveformData,
17722
17790
  source: this._source,
17723
- height: preview.group.height()
17791
+ height: preview.group.height(),
17792
+ url: preview.url
17724
17793
  });
17725
17794
  preview.group.add(waveform);
17726
17795
  this._unwrap.add(preview.group);
17727
17796
  if (redraw) {
17728
- this._group.draw();
17797
+ this._layer.rescale(true);
17729
17798
  }
17730
17799
  this._previewList.push(preview);
17731
17800
  }
17732
17801
  };
17802
+ SourceGroup.prototype.getAudioPreview = function () {
17803
+ return this._previewList.filter(function (preview) {
17804
+ return preview.type === 'audio';
17805
+ });
17806
+ };
17733
17807
  SourceGroup.prototype.setSelected = function (isSelected) {
17734
17808
  var background = this._unwrap.getChildren(function (node) {
17735
17809
  return node.getClassName() === 'Shape';
@@ -17889,7 +17963,7 @@ module.exports = function (WaveformBuilder, WaveformShape, Utils, Konva) {
17889
17963
  };
17890
17964
  return SourceGroup;
17891
17965
  }(_dereq_('./waveform-builder'), _dereq_('./waveform-shape'), _dereq_('./utils'), _dereq_('konva'));
17892
- },{"./utils":109,"./waveform-builder":110,"./waveform-shape":111,"konva":43}],103:[function(_dereq_,module,exports){
17966
+ },{"./utils":110,"./waveform-builder":111,"./waveform-shape":112,"konva":43}],104:[function(_dereq_,module,exports){
17893
17967
  module.exports = function (Utils) {
17894
17968
  'use strict';
17895
17969
  function validateSource(peaks, options, context) {
@@ -18426,8 +18500,8 @@ module.exports = function (Utils) {
18426
18500
  };
18427
18501
  return Source;
18428
18502
  }(_dereq_('./utils'));
18429
- },{"./utils":109}],104:[function(_dereq_,module,exports){
18430
- module.exports = function (SourceGroup, SegmentsGroup, Lines, DataRetriever, Utils, Konva) {
18503
+ },{"./utils":110}],105:[function(_dereq_,module,exports){
18504
+ module.exports = function (SourceGroup, SegmentsGroup, Lines, DataRetriever, Utils, Invoker, Konva) {
18431
18505
  'use strict';
18432
18506
  function SourcesLayer(peaks, view, allowEditing) {
18433
18507
  this._peaks = peaks;
@@ -18440,6 +18514,7 @@ module.exports = function (SourceGroup, SegmentsGroup, Lines, DataRetriever, Uti
18440
18514
  this._lines.addToLayer(this);
18441
18515
  this._segmentsGroup = new SegmentsGroup(peaks, view, true);
18442
18516
  this._loadedData = {};
18517
+ this._debouncedRescale = new Invoker().debounce(this._rescale, 150);
18443
18518
  this._peaks.on('sources.add', this._onSourcesAdd.bind(this));
18444
18519
  this._peaks.on('sources.destroy', this._onSourcesDestroy.bind(this));
18445
18520
  this._peaks.on('sources.show', this._onSourcesShow.bind(this));
@@ -18699,10 +18774,37 @@ module.exports = function (SourceGroup, SegmentsGroup, Lines, DataRetriever, Uti
18699
18774
  var startsEarlier = source1.startTime > source2.startTime && source1.startTime < source2.endTime;
18700
18775
  return endsLater || startsEarlier;
18701
18776
  };
18702
- SourcesLayer.prototype.rescale = function () {
18703
- this._lines.rescale();
18777
+ SourcesLayer.prototype.rescale = function (debounce) {
18778
+ if (debounce) {
18779
+ this._debouncedRescale();
18780
+ } else {
18781
+ this._rescale();
18782
+ }
18783
+ };
18784
+ SourcesLayer.prototype._rescale = function () {
18785
+ var id, audioPreviews, urls = [], self = this;
18786
+ for (id in this._sourcesGroup) {
18787
+ if (Utils.objectHasProperty(this._sourcesGroup, id)) {
18788
+ audioPreviews = this._sourcesGroup[id].getAudioPreview();
18789
+ audioPreviews.forEach(function (audioPreview) {
18790
+ if (self._shouldResampleAudio(audioPreview.url, urls)) {
18791
+ self._loadedData[audioPreview.url + '-scaled'] = {
18792
+ data: self._resampleAudio(audioPreview.url),
18793
+ scale: self._view.getTimeToPixelsScale()
18794
+ };
18795
+ urls.push(audioPreview.url);
18796
+ }
18797
+ });
18798
+ }
18799
+ }
18704
18800
  this._layer.draw();
18705
18801
  };
18802
+ SourcesLayer.prototype._shouldResampleAudio = function (audioUrl, urls) {
18803
+ return this._loadedData[audioUrl + '-scaled'] && !urls.includes(audioUrl) && this._loadedData[audioUrl + '-scaled'].scale !== this._view.getTimeToPixelsScale();
18804
+ };
18805
+ SourcesLayer.prototype._resampleAudio = function (audioUrl) {
18806
+ return this._loadedData[audioUrl].resample({ scale: this._loadedData[audioUrl].sample_rate / this._view.getTimeToPixelsScale() });
18807
+ };
18706
18808
  SourcesLayer.prototype.destroy = function () {
18707
18809
  this._peaks.off('sources.add', this._onSourcesAdd);
18708
18810
  this._peaks.off('sources.destroy', this._onSourcesDestroy);
@@ -18720,8 +18822,8 @@ module.exports = function (SourceGroup, SegmentsGroup, Lines, DataRetriever, Uti
18720
18822
  return this._lines.linesLength();
18721
18823
  };
18722
18824
  return SourcesLayer;
18723
- }(_dereq_('./source-group'), _dereq_('./segments-group'), _dereq_('./lines'), _dereq_('./data-retriever'), _dereq_('./utils'), _dereq_('konva'));
18724
- },{"./data-retriever":85,"./lines":91,"./segments-group":101,"./source-group":102,"./utils":109,"konva":43}],105:[function(_dereq_,module,exports){
18825
+ }(_dereq_('./source-group'), _dereq_('./segments-group'), _dereq_('./lines'), _dereq_('./data-retriever'), _dereq_('./utils'), _dereq_('./invoker'), _dereq_('konva'));
18826
+ },{"./data-retriever":85,"./invoker":88,"./lines":92,"./segments-group":102,"./source-group":103,"./utils":110,"konva":43}],106:[function(_dereq_,module,exports){
18725
18827
  module.exports = function (Utils, Konva) {
18726
18828
  'use strict';
18727
18829
  var LEFT_PADDING = 4;
@@ -18862,7 +18964,7 @@ module.exports = function (Utils, Konva) {
18862
18964
  };
18863
18965
  return TimelineAxis;
18864
18966
  }(_dereq_('./utils'), _dereq_('konva'));
18865
- },{"./utils":109,"konva":43}],106:[function(_dereq_,module,exports){
18967
+ },{"./utils":110,"konva":43}],107:[function(_dereq_,module,exports){
18866
18968
  module.exports = function (Colors, Segment, Utils) {
18867
18969
  'use strict';
18868
18970
  function TimelineSegments(peaks) {
@@ -19010,7 +19112,7 @@ module.exports = function (Colors, Segment, Utils) {
19010
19112
  };
19011
19113
  return TimelineSegments;
19012
19114
  }(_dereq_('colors.css'), _dereq_('./segment'), _dereq_('./utils'));
19013
- },{"./segment":100,"./utils":109,"colors.css":1}],107:[function(_dereq_,module,exports){
19115
+ },{"./segment":101,"./utils":110,"colors.css":1}],108:[function(_dereq_,module,exports){
19014
19116
  module.exports = function (Source, Utils) {
19015
19117
  'use strict';
19016
19118
  function TimelineSources(peaks) {
@@ -19177,7 +19279,7 @@ module.exports = function (Source, Utils) {
19177
19279
  };
19178
19280
  return TimelineSources;
19179
19281
  }(_dereq_('./source'), _dereq_('./utils'));
19180
- },{"./source":103,"./utils":109}],108:[function(_dereq_,module,exports){
19282
+ },{"./source":104,"./utils":110}],109:[function(_dereq_,module,exports){
19181
19283
  module.exports = function (MouseDragHandler, PlayheadLayer, SourcesLayer, ModeLayer, TimelineAxis, Utils, Konva) {
19182
19284
  'use strict';
19183
19285
  function TimelineZoomView(container, peaks) {
@@ -19554,10 +19656,10 @@ module.exports = function (MouseDragHandler, PlayheadLayer, SourcesLayer, ModeLa
19554
19656
  this._timeToPixelsScale = newScale;
19555
19657
  var apexPixel = this.timeToPixels(apexTime);
19556
19658
  this.setFrameOffset(apexPixel - playheadOffsetPixels);
19557
- this.updateTimeline(this._frameOffset);
19659
+ this.updateTimeline(this._frameOffset, undefined, undefined, true);
19660
+ this._sourcesLayer.rescale(true);
19558
19661
  this._playheadLayer.zoomLevelChanged();
19559
19662
  this._playheadLayer.updatePlayheadTime(currentTime);
19560
- this._sourcesLayer.rescale();
19561
19663
  this._peaks.emit('zoom.update', newScale, prevScale);
19562
19664
  return true;
19563
19665
  };
@@ -19630,7 +19732,7 @@ module.exports = function (MouseDragHandler, PlayheadLayer, SourcesLayer, ModeLa
19630
19732
  TimelineZoomView.prototype.getAmplitudeScale = function () {
19631
19733
  return this._amplitudeScale;
19632
19734
  };
19633
- TimelineZoomView.prototype.updateTimeline = function (frameOffset, frameOffsetY, fixPlayhead) {
19735
+ TimelineZoomView.prototype.updateTimeline = function (frameOffset, frameOffsetY, fixPlayhead, ignoreRescale) {
19634
19736
  var frameStartTime = null;
19635
19737
  var frameEndTime = null;
19636
19738
  if (frameOffset !== undefined && frameOffset !== null) {
@@ -19656,6 +19758,9 @@ module.exports = function (MouseDragHandler, PlayheadLayer, SourcesLayer, ModeLa
19656
19758
  if (frameEndTime === null) {
19657
19759
  frameEndTime = this.pixelsToTime(this._frameOffset + this._width);
19658
19760
  }
19761
+ if (!ignoreRescale) {
19762
+ this._sourcesLayer.rescale();
19763
+ }
19659
19764
  this._sourcesLayer.updateSources(frameStartTime, frameEndTime);
19660
19765
  };
19661
19766
  TimelineZoomView.prototype.toggleMainCursor = function (on, type) {
@@ -19717,7 +19822,7 @@ module.exports = function (MouseDragHandler, PlayheadLayer, SourcesLayer, ModeLa
19717
19822
  };
19718
19823
  return TimelineZoomView;
19719
19824
  }(_dereq_('./mouse-drag-handler'), _dereq_('./playhead-layer'), _dereq_('./sources-layer'), _dereq_('./mode-layer'), _dereq_('./timeline-axis'), _dereq_('./utils'), _dereq_('konva'));
19720
- },{"./mode-layer":94,"./mouse-drag-handler":95,"./playhead-layer":97,"./sources-layer":104,"./timeline-axis":105,"./utils":109,"konva":43}],109:[function(_dereq_,module,exports){
19825
+ },{"./mode-layer":95,"./mouse-drag-handler":96,"./playhead-layer":98,"./sources-layer":105,"./timeline-axis":106,"./utils":110,"konva":43}],110:[function(_dereq_,module,exports){
19721
19826
  module.exports = function (UUID) {
19722
19827
  'use strict';
19723
19828
  if (typeof Number.isFinite !== 'function') {
@@ -19881,7 +19986,7 @@ module.exports = function (UUID) {
19881
19986
  }
19882
19987
  };
19883
19988
  }(_dereq_('uuid'));
19884
- },{"uuid":62}],110:[function(_dereq_,module,exports){
19989
+ },{"uuid":62}],111:[function(_dereq_,module,exports){
19885
19990
  module.exports = function (WaveformData, Utils) {
19886
19991
  'use strict';
19887
19992
  var isXhr2 = 'withCredentials' in new XMLHttpRequest();
@@ -20073,7 +20178,7 @@ module.exports = function (WaveformData, Utils) {
20073
20178
  };
20074
20179
  return WaveformBuilder;
20075
20180
  }(_dereq_('waveform-data'), _dereq_('./utils'));
20076
- },{"./utils":109,"waveform-data":84}],111:[function(_dereq_,module,exports){
20181
+ },{"./utils":110,"waveform-data":84}],112:[function(_dereq_,module,exports){
20077
20182
  module.exports = function (Utils, Konva) {
20078
20183
  'use strict';
20079
20184
  function scaleY(amplitude, height, scale) {
@@ -20084,24 +20189,21 @@ module.exports = function (Utils, Konva) {
20084
20189
  }
20085
20190
  function WaveformShape(options) {
20086
20191
  Konva.Shape.call(this, { fill: options.color });
20192
+ this._layer = options.layer;
20087
20193
  this._view = options.view;
20088
20194
  this._source = options.source;
20089
- this._originalWaveformData = options.waveformData;
20090
- this._waveformData = options.waveformData;
20091
20195
  this._height = options.height;
20092
- this.rescale();
20196
+ this._url = options.url + '-scaled';
20093
20197
  this.sceneFunc(this._sceneFunc);
20094
20198
  this.hitFunc(this._waveformShapeHitFunc);
20095
20199
  }
20096
20200
  WaveformShape.prototype = Object.create(Konva.Shape.prototype);
20097
- WaveformShape.prototype.rescale = function () {
20098
- this._waveformData = this._originalWaveformData.resample({ scale: this._waveformData.sample_rate / this._view.getTimeToPixelsScale() });
20099
- };
20100
20201
  WaveformShape.prototype.setWaveformColor = function (color) {
20101
20202
  this.fill(color);
20102
20203
  };
20103
20204
  WaveformShape.prototype._sceneFunc = function (context) {
20104
20205
  var width = this._view.getWidth();
20206
+ var waveformData = this._layer.getLoadedData(this._url).data;
20105
20207
  var startPixels = 0, startOffset = 0;
20106
20208
  if (this._source) {
20107
20209
  startPixels = this._view.timeToPixels(this._source.mediaStartTime) + Math.max(this._view.getFrameOffset() - this._view.timeToPixels(this._source.startTime), 0);
@@ -20109,9 +20211,9 @@ module.exports = function (Utils, Konva) {
20109
20211
  }
20110
20212
  var endPixels = width;
20111
20213
  if (this._source) {
20112
- endPixels = Math.min(this._view.timeToPixels(this._source.mediaEndTime) - Math.max(this._view.timeToPixels(this._source.endTime) - this._view.getFrameOffset() - this._view.getWidth(), 0), this._waveformData.length);
20214
+ endPixels = Math.min(this._view.timeToPixels(this._source.mediaEndTime) - Math.max(this._view.timeToPixels(this._source.endTime) - this._view.getFrameOffset() - this._view.getWidth(), 0), waveformData.length);
20113
20215
  }
20114
- this._drawWaveform(context, this._waveformData, startPixels, startOffset, endPixels, this._height);
20216
+ this._drawWaveform(context, waveformData, startPixels, startOffset, endPixels, this._height);
20115
20217
  };
20116
20218
  WaveformShape.prototype._drawWaveform = function (context, waveformData, startPixels, startOffset, endPixels, height) {
20117
20219
  var channels = waveformData.channels;
@@ -20169,6 +20271,6 @@ module.exports = function (Utils, Konva) {
20169
20271
  };
20170
20272
  return WaveformShape;
20171
20273
  }(_dereq_('./utils'), _dereq_('konva'));
20172
- },{"./utils":109,"konva":43}]},{},[92])(92)
20274
+ },{"./utils":110,"konva":43}]},{},[93])(93)
20173
20275
  });
20174
20276
  //# sourceMappingURL=peaks.js.map
package/src/invoker.js ADDED
@@ -0,0 +1,81 @@
1
+ /**
2
+ * @file
3
+ *
4
+ * Defines the {@link invoker} class.
5
+ *
6
+ * @module invoker
7
+ */
8
+
9
+ define([
10
+ ], function() {
11
+ 'use strict';
12
+
13
+ /**
14
+ * An invoker class for throttling.
15
+ *
16
+ * @class
17
+ * @alias Invoker
18
+ */
19
+
20
+ function Invoker() {
21
+ this._throttledFunc = {};
22
+ }
23
+
24
+ Invoker.prototype.throttle = function(id, func, wait) {
25
+ var self = this;
26
+
27
+ if (this._throttledFunc[id]) {
28
+ // Already limiting
29
+ this._throttledFunc[id].func = func;
30
+ this._throttledFunc[id].continue = true;
31
+ }
32
+ else {
33
+ // Create a limit
34
+ this._throttledFunc[id] = {
35
+ func: func,
36
+ timer: null,
37
+ continue: true
38
+ };
39
+
40
+ this._throttledFunc[id].timer = setInterval(function() {
41
+ if (self._throttledFunc[id].continue) {
42
+ func();
43
+ self._throttledFunc[id].continue = false;
44
+ }
45
+ else {
46
+ clearInterval(self._throttledFunc[id].timer);
47
+ delete self._throttledFunc[id];
48
+ }
49
+ }, wait);
50
+ }
51
+ };
52
+
53
+ Invoker.prototype.debounce = function(func, wait, immediate) {
54
+ var timeout;
55
+
56
+ return function executedFunction() {
57
+ // eslint-disable-next-line consistent-this
58
+ var _self = this;
59
+ var args = arguments;
60
+
61
+ function later() {
62
+ timeout = null;
63
+ if (!immediate) {
64
+ func.apply(_self, args);
65
+ }
66
+ }
67
+
68
+ var callNow = immediate && !timeout;
69
+
70
+ clearTimeout(timeout);
71
+
72
+ timeout = setTimeout(later, wait);
73
+
74
+ if (callNow) {
75
+ func.apply(_self, args);
76
+ }
77
+ };
78
+ };
79
+
80
+ return Invoker;
81
+ });
package/src/line.js CHANGED
@@ -596,13 +596,13 @@ define([
596
596
  return newXs;
597
597
  };
598
598
 
599
- Line.prototype.rescale = function() {
600
- for (var sourceId in this._sourcesGroup) {
601
- if (Utils.objectHasProperty(this._sourcesGroup, sourceId)) {
602
- this._sourcesGroup[sourceId].rescale();
603
- }
604
- }
605
- };
599
+ // Line.prototype.rescale = function() {
600
+ // for (var sourceId in this._sourcesGroup) {
601
+ // if (Utils.objectHasProperty(this._sourcesGroup, sourceId)) {
602
+ // this._sourcesGroup[sourceId].rescale();
603
+ // }
604
+ // }
605
+ // };
606
606
 
607
607
  Line.prototype.updatePosition = function(pos) {
608
608
  for (var sourceId in this._sources) {
package/src/lines.js CHANGED
@@ -305,13 +305,13 @@ define([
305
305
  return this._linesBySourceId[source.id].manageSourceOrder(source, newStartX, newEndX);
306
306
  };
307
307
 
308
- Lines.prototype.rescale = function() {
309
- for (var position in this._linesByPosition) {
310
- if (Utils.objectHasProperty(this._linesByPosition, position)) {
311
- this._linesByPosition[position].rescale();
312
- }
313
- }
314
- };
308
+ // Lines.prototype.rescale = function() {
309
+ // for (var position in this._linesByPosition) {
310
+ // if (Utils.objectHasProperty(this._linesByPosition, position)) {
311
+ // this._linesByPosition[position].rescale();
312
+ // }
313
+ // }
314
+ // };
315
315
 
316
316
  Lines.prototype._setInteractions = function(position) {
317
317
  var line = this._linesByPosition[position];
package/src/main.js CHANGED
@@ -622,6 +622,12 @@ define([
622
622
  .allowInteractions(forSources, forSegments);
623
623
  };
624
624
 
625
+ Peaks.prototype.checkOverlapping = function(segment, message) {
626
+ return this.view
627
+ .getSegmentsGroup()
628
+ .checkOverlapping(segment, message);
629
+ };
630
+
625
631
  Peaks.prototype._addWindowResizeHandler = function() {
626
632
  this._onResize = this._onResize.bind(this);
627
633
  window.addEventListener('resize', this._onResize);
package/src/segment.js CHANGED
@@ -199,6 +199,8 @@ define([
199
199
 
200
200
  validateSegment(this._peaks, opts, 'update()');
201
201
 
202
+ this._peaks.checkOverlapping(this, 'overlapping before manual update');
203
+
202
204
  this._startTime = opts.startTime;
203
205
  this._endTime = opts.endTime;
204
206
  this._labelText = opts.labelText;
@@ -208,6 +210,8 @@ define([
208
210
  this._opacity = opts.opacity;
209
211
  this._editable = opts.editable;
210
212
 
213
+ this._peaks.checkOverlapping(this, 'overlapping after manual update');
214
+
211
215
  this._peaks.emit('segment.updated', this);
212
216
  };
213
217
 
@@ -41,6 +41,7 @@ define([
41
41
  this._group = new Konva.Group();
42
42
 
43
43
  this._updatedSegments = [];
44
+ this._overlappingSegments = [];
44
45
 
45
46
  this._isMagnetized = false;
46
47
 
@@ -113,6 +114,8 @@ define([
113
114
  };
114
115
 
115
116
  SegmentsGroup.prototype._onSegmentsUpdate = function(segment) {
117
+ this._overlappingSegments = [];
118
+
116
119
  if (this._segments[segment.id]) {
117
120
  var redraw = false;
118
121
  var segmentShape = this._segmentShapes[segment.id];
@@ -143,6 +146,7 @@ define([
143
146
  SegmentsGroup.prototype._onSegmentUpdated = function() {
144
147
  this._peaks.emit('segments.updated', this._updatedSegments);
145
148
  this._updatedSegments = [];
149
+ this._overlappingSegments = [];
146
150
  };
147
151
 
148
152
  SegmentsGroup.prototype._onSegmentsAdd = function(segments) {
@@ -441,6 +445,8 @@ define([
441
445
  };
442
446
 
443
447
  SegmentsGroup.prototype.updateSegment = function(segment, newStartX, newEndX) {
448
+ this.checkOverlapping(segment, 'overlapping before dragging');
449
+
444
450
  var newXs = this.manageCollision(segment, newStartX, newEndX);
445
451
 
446
452
  if (newXs.startX !== null) {
@@ -452,6 +458,8 @@ define([
452
458
  }
453
459
 
454
460
  if (newXs) {
461
+ this.checkOverlapping(segment, 'overlapping after dragging');
462
+
455
463
  this._updateSegment(segment);
456
464
 
457
465
  this.addToUpdatedSegments(segment);
@@ -460,12 +468,33 @@ define([
460
468
  }
461
469
  };
462
470
 
471
+ SegmentsGroup.prototype.checkOverlapping = function(segment, message) {
472
+ /* eslint-disable max-len */
473
+ if ((this._segments[segment.id].prevSegmentId
474
+ && this._segments[this._segments[segment.id].prevSegmentId].segment.endTime > segment.startTime)
475
+ || (this._segments[segment.id].nextSegmentId
476
+ && this._segments[this._segments[segment.id].nextSegmentId].segment.startTime < segment.endTime)) {
477
+
478
+ if (!this._overlappingSegments.includes(segment.id)) {
479
+ this._peaks.emit('segments.overlap', {
480
+ message: message,
481
+ segment: segment,
482
+ prevSegment: this._segments[segment.id].prevSegmentId ? this._segments[this._segments[segment.id].prevSegmentId].segment : null,
483
+ nextSegment: this._segments[segment.id].nextSegmentId ? this._segments[this._segments[segment.id].nextSegmentId].segment : null
484
+ });
485
+ this._overlappingSegments.push(segment.id);
486
+ }
487
+
488
+ }
489
+ /* eslint-enable max-len */
490
+ };
491
+
463
492
  SegmentsGroup.prototype.manageCollision = function(segment, newStartX, newEndX) {
464
493
  var newStartTime = null;
465
494
  var newEndTime = null;
466
495
  var startLimited = false;
467
496
  var endLimited = false;
468
- var segmentMagnetThreshold, width;
497
+ var segmentMagnetThreshold, width, previousSegment, nextSegment, newXs;
469
498
 
470
499
  if (this._isMagnetized) {
471
500
  segmentMagnetThreshold = this._view.pixelsToTime(
@@ -483,7 +512,7 @@ define([
483
512
 
484
513
  if (this._segments[segment.id].prevSegmentId) {
485
514
  // there is another segment to the left
486
- var previousSegment = this._segments[this._segments[segment.id].prevSegmentId].segment;
515
+ previousSegment = this._segments[this._segments[segment.id].prevSegmentId].segment;
487
516
 
488
517
  if (this._isMagnetized) {
489
518
  if (newStartTime < previousSegment.endTime + segmentMagnetThreshold) {
@@ -498,7 +527,7 @@ define([
498
527
  };
499
528
  }
500
529
  }
501
- else if (segment.startTime > newStartTime) {
530
+ else if (segment.startTime >= newStartTime) {
502
531
  // startMarker moved to the left
503
532
  if (newStartTime < previousSegment.endTime) {
504
533
  // there is collision
@@ -508,7 +537,15 @@ define([
508
537
  }
509
538
 
510
539
  if (previousSegment.endTime !== newStartTime) {
511
- previousSegment.endTime = newStartTime;
540
+ newXs = this.manageCollision(previousSegment, this._view.timeToPixels(previousSegment.startTime), this._view.timeToPixels(newStartTime));
541
+
542
+ if (newXs.startX !== null) {
543
+ previousSegment.startTime = this._view.pixelsToTime(newXs.startX);
544
+ }
545
+
546
+ if (newXs.endX !== null) {
547
+ previousSegment.endTime = this._view.pixelsToTime(newXs.endX);
548
+ }
512
549
  this._updateSegment(previousSegment);
513
550
  this.addToUpdatedSegments(previousSegment);
514
551
  }
@@ -529,7 +566,7 @@ define([
529
566
 
530
567
  if (this._segments[segment.id].nextSegmentId) {
531
568
  // there is another segment to the right
532
- var nextSegment = this._segments[this._segments[segment.id].nextSegmentId].segment;
569
+ nextSegment = this._segments[this._segments[segment.id].nextSegmentId].segment;
533
570
 
534
571
  if (this._isMagnetized) {
535
572
  if (newEndTime > nextSegment.startTime - segmentMagnetThreshold) {
@@ -544,7 +581,7 @@ define([
544
581
  };
545
582
  }
546
583
  }
547
- else if (segment.endTime < newEndTime) {
584
+ else if (segment.endTime <= newEndTime) {
548
585
  // endMarker moved to the right
549
586
  if (newEndTime > nextSegment.startTime) {
550
587
  // there is collision
@@ -554,7 +591,15 @@ define([
554
591
  }
555
592
 
556
593
  if (nextSegment.startTime !== newEndTime) {
557
- nextSegment.startTime = newEndTime;
594
+ newXs = this.manageCollision(nextSegment, this._view.timeToPixels(newEndTime), this._view.timeToPixels(nextSegment.endTime));
595
+
596
+ if (newXs.startX !== null) {
597
+ nextSegment.startTime = this._view.pixelsToTime(newXs.startX);
598
+ }
599
+
600
+ if (newXs.endX !== null) {
601
+ nextSegment.endTime = this._view.pixelsToTime(newXs.endX);
602
+ }
558
603
  this._updateSegment(nextSegment);
559
604
  this.addToUpdatedSegments(nextSegment);
560
605
  }
@@ -568,7 +613,16 @@ define([
568
613
 
569
614
  // Check for minimal size of segment
570
615
  if (newStartTime !== null && newEndTime !== null) {
571
- if (newEndTime - newStartTime < segment.minSize) {
616
+ if (Utils.roundTime(newEndTime - newStartTime) < segment.minSize) {
617
+ if (previousSegment && nextSegment) {
618
+ if (Utils.roundTime(nextSegment.startTime - previousSegment.endTime) < segment.minSize) {
619
+ return {
620
+ startX: null,
621
+ endX: null
622
+ };
623
+ }
624
+ }
625
+
572
626
  if (startLimited) {
573
627
  newEndTime = newStartTime + segment.minSize;
574
628
  }
@@ -578,12 +632,12 @@ define([
578
632
  }
579
633
  }
580
634
  else if (newStartTime !== null) {
581
- if (segment.endTime - newStartTime < segment.minSize) {
635
+ if (Utils.roundTime(segment.endTime - newStartTime) < segment.minSize) {
582
636
  newStartTime = segment.endTime - segment.minSize;
583
637
  }
584
638
  }
585
639
  else if (newEndTime !== null) {
586
- if (newEndTime - segment.startTime < segment.minSize) {
640
+ if (Utils.roundTime(newEndTime - segment.startTime) < segment.minSize) {
587
641
  newEndTime = segment.startTime + segment.minSize;
588
642
  }
589
643
  }
@@ -91,23 +91,23 @@ define([
91
91
  this.setWrapping(source.wrapped);
92
92
  }
93
93
 
94
- SourceGroup.prototype.rescale = function() {
95
- this.update();
96
-
97
- this._previewList.forEach(function(preview) {
98
- if (preview.loaded) {
99
- switch (preview.type) {
100
- case 'audio':
101
- preview.group.getChildren()[0].rescale();
102
- break;
103
- case 'video':
104
- case 'image':
105
- default:
106
- // No resampling
107
- }
108
- }
109
- });
110
- };
94
+ // SourceGroup.prototype.rescale = function() {
95
+ // this.update();
96
+
97
+ // this._previewList.forEach(function(preview) {
98
+ // if (preview.loaded) {
99
+ // switch (preview.type) {
100
+ // case 'audio':
101
+ // preview.group.getChildren()[0].rescale(true);
102
+ // break;
103
+ // case 'video':
104
+ // case 'image':
105
+ // default:
106
+ // // No resampling
107
+ // }
108
+ // }
109
+ // });
110
+ // };
111
111
 
112
112
  SourceGroup.prototype._onSourceGroupDragStart = function() {
113
113
  this._dragged = true;
@@ -667,7 +667,8 @@ define([
667
667
  height: this._source.binaryUrl && this._source.previewUrl ?
668
668
  this._source.binaryHeight : this._unwrappedHeight,
669
669
  listening: false
670
- })
670
+ }),
671
+ url: url
671
672
  };
672
673
 
673
674
  var self = this;
@@ -706,6 +707,10 @@ define([
706
707
  }
707
708
 
708
709
  self._layer.setLoadedData(url, originalWaveformData);
710
+ self._layer.setLoadedData(
711
+ url + '-scaled',
712
+ { data: originalWaveformData, scale: originalWaveformData.sample_rate / self._minScale }
713
+ );
709
714
  preview.loaded = true;
710
715
  self._createAudioPreview(preview, originalWaveformData, redraw);
711
716
  });
@@ -744,24 +749,31 @@ define([
744
749
  SourceGroup.prototype._createAudioPreview = function(preview, waveformData, redraw) {
745
750
  if (waveformData.hasAudio) {
746
751
  var waveform = new WaveformShape({
752
+ layer: this._layer,
747
753
  view: this._view,
748
754
  color: this._peaks.options.zoomWaveformColor,
749
- waveformData: waveformData,
750
755
  source: this._source,
751
- height: preview.group.height()
756
+ height: preview.group.height(),
757
+ url: preview.url
752
758
  });
753
759
 
754
760
  preview.group.add(waveform);
755
761
  this._unwrap.add(preview.group);
756
762
 
757
763
  if (redraw) {
758
- this._group.draw();
764
+ this._layer.rescale(true);
759
765
  }
760
766
 
761
767
  this._previewList.push(preview);
762
768
  }
763
769
  };
764
770
 
771
+ SourceGroup.prototype.getAudioPreview = function() {
772
+ return this._previewList.filter(function(preview) {
773
+ return preview.type === 'audio';
774
+ });
775
+ };
776
+
765
777
  SourceGroup.prototype.setSelected = function(isSelected) {
766
778
  // update unwrap
767
779
  var background = this._unwrap.getChildren(function(node) {
@@ -12,6 +12,7 @@ define([
12
12
  './lines',
13
13
  './data-retriever',
14
14
  './utils',
15
+ './invoker',
15
16
  'konva'
16
17
  ], function(
17
18
  SourceGroup,
@@ -19,6 +20,7 @@ define([
19
20
  Lines,
20
21
  DataRetriever,
21
22
  Utils,
23
+ Invoker,
22
24
  Konva) {
23
25
  'use strict';
24
26
 
@@ -47,6 +49,10 @@ define([
47
49
 
48
50
  this._loadedData = {};
49
51
 
52
+ this._debouncedRescale = new Invoker().debounce(
53
+ this._rescale, 150
54
+ );
55
+
50
56
  this._peaks.on('sources.add', this._onSourcesAdd.bind(this));
51
57
  this._peaks.on('sources.destroy', this._onSourcesDestroy.bind(this));
52
58
  this._peaks.on('sources.show', this._onSourcesShow.bind(this));
@@ -472,11 +478,51 @@ define([
472
478
  return endsLater || startsEarlier;
473
479
  };
474
480
 
475
- SourcesLayer.prototype.rescale = function() {
476
- this._lines.rescale();
481
+ SourcesLayer.prototype.rescale = function(debounce) {
482
+ // this._lines.rescale();
483
+ if (debounce) {
484
+ this._debouncedRescale();
485
+ }
486
+ else {
487
+ this._rescale();
488
+ }
489
+ };
490
+
491
+ SourcesLayer.prototype._rescale = function() {
492
+ var id, audioPreviews, urls = [], self = this;
493
+
494
+ for (id in this._sourcesGroup) {
495
+ if (Utils.objectHasProperty(this._sourcesGroup, id)) {
496
+ audioPreviews = this._sourcesGroup[id].getAudioPreview();
497
+
498
+ audioPreviews.forEach(function(audioPreview) {
499
+ if (self._shouldResampleAudio(audioPreview.url, urls)) {
500
+ self._loadedData[audioPreview.url + '-scaled'] = {
501
+ data: self._resampleAudio(audioPreview.url),
502
+ scale: self._view.getTimeToPixelsScale()
503
+ };
504
+
505
+ urls.push(audioPreview.url);
506
+ }
507
+ });
508
+ }
509
+ }
477
510
  this._layer.draw();
478
511
  };
479
512
 
513
+ SourcesLayer.prototype._shouldResampleAudio = function(audioUrl, urls) {
514
+ return this._loadedData[audioUrl + '-scaled']
515
+ && !urls.includes(audioUrl)
516
+ && this._loadedData[audioUrl + '-scaled'].scale !== this._view.getTimeToPixelsScale();
517
+ };
518
+
519
+ SourcesLayer.prototype._resampleAudio = function(audioUrl) {
520
+ return this._loadedData[audioUrl].resample({
521
+ scale: this._loadedData[audioUrl].sample_rate
522
+ / this._view.getTimeToPixelsScale()
523
+ });
524
+ };
525
+
480
526
  SourcesLayer.prototype.destroy = function() {
481
527
  this._peaks.off('sources.add', this._onSourcesAdd);
482
528
  this._peaks.off('sources.destroy', this._onSourcesDestroy);
@@ -588,15 +588,15 @@ define([
588
588
 
589
589
  this.setFrameOffset(apexPixel - playheadOffsetPixels);
590
590
 
591
- this.updateTimeline(this._frameOffset);
591
+ this.updateTimeline(this._frameOffset, undefined, undefined, true);
592
+
593
+ this._sourcesLayer.rescale(true);
592
594
 
593
595
  this._playheadLayer.zoomLevelChanged();
594
596
 
595
597
  // Update the playhead position after zooming.
596
598
  this._playheadLayer.updatePlayheadTime(currentTime);
597
599
 
598
- this._sourcesLayer.rescale();
599
-
600
600
  this._peaks.emit('zoom.update', newScale, prevScale);
601
601
 
602
602
  return true;
@@ -742,7 +742,8 @@ define([
742
742
  * @param {Number} frameOffset The new frame offset, in pixels.
743
743
  */
744
744
 
745
- TimelineZoomView.prototype.updateTimeline = function(frameOffset, frameOffsetY, fixPlayhead) {
745
+ TimelineZoomView.prototype.updateTimeline = function(frameOffset, frameOffsetY, fixPlayhead,
746
+ ignoreRescale) {
746
747
  var frameStartTime = null;
747
748
  var frameEndTime = null;
748
749
 
@@ -783,6 +784,10 @@ define([
783
784
  frameEndTime = this.pixelsToTime(this._frameOffset + this._width);
784
785
  }
785
786
 
787
+ if (!ignoreRescale) {
788
+ this._sourcesLayer.rescale();
789
+ }
790
+
786
791
  this._sourcesLayer.updateSources(frameStartTime, frameEndTime);
787
792
  };
788
793
 
@@ -54,13 +54,11 @@ define(['./utils', 'konva'], function(Utils, Konva) {
54
54
  fill: options.color
55
55
  });
56
56
 
57
+ this._layer = options.layer;
57
58
  this._view = options.view;
58
59
  this._source = options.source;
59
- this._originalWaveformData = options.waveformData;
60
- this._waveformData = options.waveformData;
61
60
  this._height = options.height;
62
-
63
- this.rescale();
61
+ this._url = options.url + '-scaled';
64
62
 
65
63
  this.sceneFunc(this._sceneFunc);
66
64
 
@@ -69,18 +67,13 @@ define(['./utils', 'konva'], function(Utils, Konva) {
69
67
 
70
68
  WaveformShape.prototype = Object.create(Konva.Shape.prototype);
71
69
 
72
- WaveformShape.prototype.rescale = function() {
73
- this._waveformData = this._originalWaveformData.resample({
74
- scale: this._waveformData.sample_rate / this._view.getTimeToPixelsScale()
75
- });
76
- };
77
-
78
70
  WaveformShape.prototype.setWaveformColor = function(color) {
79
71
  this.fill(color);
80
72
  };
81
73
 
82
74
  WaveformShape.prototype._sceneFunc = function(context) {
83
75
  var width = this._view.getWidth();
76
+ var waveformData = this._layer.getLoadedData(this._url).data;
84
77
 
85
78
  var startPixels = 0, startOffset = 0;
86
79
 
@@ -103,13 +96,13 @@ define(['./utils', 'konva'], function(Utils, Konva) {
103
96
  - this._view.getWidth(),
104
97
  0
105
98
  ),
106
- this._waveformData.length
99
+ waveformData.length
107
100
  );
108
101
  }
109
102
 
110
103
  this._drawWaveform(
111
104
  context,
112
- this._waveformData,
105
+ waveformData,
113
106
  startPixels,
114
107
  startOffset,
115
108
  endPixels,