@checksub_team/peaks_timeline 2.0.0-alpha.9 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -24,6 +24,7 @@ define([
24
24
  var SPACING_BETWEEN_PREVIEWS = 1.5;
25
25
  var CORNER_RADIUS = 8;
26
26
  var INDICATOR_RADIUS = 4; // px
27
+ var PREVIEW_CREATE_CHUNK = 8; // number of preview tiles to add per idle slice
27
28
 
28
29
  /**
29
30
  * Creates a source group for the given source.
@@ -60,6 +61,8 @@ define([
60
61
  this._isDragged = false;
61
62
 
62
63
  this._previewList = [];
64
+ // internal queue state for async preview creation
65
+ this._previewBuildQueue = new Set();
63
66
 
64
67
  this._markersGroup = this._createMarkers();
65
68
 
@@ -79,19 +82,8 @@ define([
79
82
  this._group.on('dragend', this._onDragEnd.bind(this));
80
83
 
81
84
  this._cursor = null;
82
- this._group.on('mouseenter', function() {
83
- self._setHovered(true);
84
- self._view.setHoveredElement(self);
85
- if (!self._source.loading) {
86
- self._showButtons();
87
- }
88
- });
89
-
90
- this._group.on('mouseleave', function() {
91
- self._setHovered(false);
92
- self._view.setHoveredElement(null);
93
- self._hideButtons();
94
- });
85
+ this._group.on('mouseenter', this._onHoverStart.bind(this));
86
+ this._group.on('mouseleave', this._onHoverEnd.bind(this));
95
87
 
96
88
  this._group.on('mouseover', function() {
97
89
  if (self._source.draggable) {
@@ -136,9 +128,21 @@ define([
136
128
  this.setLoadingState(this._source.loading);
137
129
  }
138
130
 
139
- SourceGroup.prototype._setHovered = function(newValue) {
140
- this._hovered = newValue;
141
- this._group.draw();
131
+ SourceGroup.prototype._onHoverStart = function() {
132
+ this._hovered = true;
133
+ this._view.setHoveredElement(this);
134
+ if (!this._source.loading) {
135
+ this._showButtons();
136
+ }
137
+ this._batchDraw();
138
+ };
139
+
140
+ SourceGroup.prototype._onHoverEnd = function() {
141
+ this._hovered = false;
142
+ this._manualHover = false;
143
+ this._view.setHoveredElement(null);
144
+ this._hideButtons();
145
+ this._batchDraw();
142
146
  };
143
147
 
144
148
  SourceGroup.prototype._onDragStart = function(element) {
@@ -148,9 +152,34 @@ define([
148
152
 
149
153
  SourceGroup.prototype._onDragEnd = function(element) {
150
154
  this._isDragged = false;
155
+ this._manageManualHoverStop();
151
156
  this._layer.onSourcesGroupDragEnd(element);
152
157
  };
153
158
 
159
+ SourceGroup.prototype._manageManualHoverStop = function() {
160
+ if (!this._manualHover) {
161
+ return;
162
+ }
163
+
164
+ var pointer = this._view.getPointerPosition();
165
+
166
+ if (pointer) {
167
+ var absPos = this._group.absolutePosition();
168
+ var inside = (
169
+ pointer.x >= absPos.x && pointer.x <= absPos.x + this._width &&
170
+ pointer.y >= absPos.y && pointer.y <= absPos.y + this._height
171
+ );
172
+
173
+ if (!inside) {
174
+ this.stopHover();
175
+ }
176
+ }
177
+ };
178
+
179
+ SourceGroup.prototype.isHovered = function() {
180
+ return this._hovered;
181
+ };
182
+
154
183
  SourceGroup.prototype.isActive = function() {
155
184
  return this._isDragged;
156
185
  };
@@ -185,7 +214,7 @@ define([
185
214
  leftHandle ? start + diff + timeOffsetDiff : null,
186
215
  leftHandle ? null : end + diff + timeOffsetDiff
187
216
  )) {
188
- this._layer.draw();
217
+ this._layer.batchDraw();
189
218
  }
190
219
  }.bind(this)
191
220
  );
@@ -674,6 +703,15 @@ define([
674
703
  return this._source;
675
704
  };
676
705
 
706
+ SourceGroup.prototype.startHover = function() {
707
+ this._manualHover = true;
708
+ this._group.fire('mouseenter', { evt: new MouseEvent('mouseenter') }, true);
709
+ };
710
+
711
+ SourceGroup.prototype.stopHover = function() {
712
+ this._group.fire('mouseleave', { evt: new MouseEvent('mouseleave') }, true);
713
+ };
714
+
677
715
  SourceGroup.prototype.startDrag = function() {
678
716
  return this._group.startDrag();
679
717
  };
@@ -808,80 +846,49 @@ define([
808
846
  throw err;
809
847
  }
810
848
 
811
- originalWaveformData.hasAudio = self._hasAudio(originalWaveformData);
849
+ var newScale = originalWaveformData.sample_rate / self._view.getTimeToPixelsMaxZoom();
812
850
 
813
- if (originalWaveformData.hasAudio) {
814
- var newScale = originalWaveformData.sample_rate / self._view.getTimeToPixelsMaxZoom();
815
-
816
- if (newScale > originalWaveformData.scale) {
817
- self._minScale = newScale;
818
- }
819
- else {
820
- self._minScale = originalWaveformData.scale;
821
- }
822
-
823
- self._view.setTimeToPixelsMaxZoom(originalWaveformData.sample_rate / self._minScale);
851
+ if (newScale > originalWaveformData.scale) {
852
+ self._minScale = newScale;
853
+ }
854
+ else {
855
+ self._minScale = originalWaveformData.scale;
824
856
  }
825
857
 
858
+ self._view.setTimeToPixelsMaxZoom(originalWaveformData.sample_rate / self._minScale);
859
+
826
860
  self._layer.setLoadedData(url, originalWaveformData);
827
861
  self._layer.setLoadedData(
828
862
  url + '-scaled',
829
863
  { data: originalWaveformData, scale: originalWaveformData.sample_rate / self._minScale }
830
864
  );
831
865
  preview.loaded = true;
832
- self._createAudioPreview(preview, originalWaveformData, redraw);
866
+ self._createAudioPreview(preview, redraw);
833
867
  });
834
868
  }
835
869
  else {
836
870
  preview.loaded = true;
837
- this._createAudioPreview(preview, audioData, redraw);
871
+ this._createAudioPreview(preview, redraw);
838
872
  }
839
873
  };
840
874
 
841
- SourceGroup.prototype._hasAudio = function(waveformData) {
842
- var channels = waveformData.channels;
843
- var channel, someIsNotZero = false;
844
-
845
- for (var i = 0; i < channels; i++) {
846
- channel = waveformData.channel(i);
847
-
848
- someIsNotZero = channel.min_array().some(function(item) {
849
- return item !== 0;
850
- });
875
+ SourceGroup.prototype._createAudioPreview = function(preview, redraw) {
876
+ var waveform = new WaveformShape({
877
+ layer: this._layer,
878
+ view: this._view,
879
+ source: this._source,
880
+ height: preview.group.height(),
881
+ url: preview.url
882
+ });
851
883
 
852
- if (!someIsNotZero) {
853
- someIsNotZero = channel.max_array().some(function(item) {
854
- return item !== 0;
855
- });
856
- }
884
+ preview.group.add(waveform);
885
+ this._addToUnwrap(preview.group);
857
886
 
858
- if (someIsNotZero) {
859
- break;
860
- }
887
+ if (redraw) {
888
+ this._layer.rescale(true);
861
889
  }
862
890
 
863
- return someIsNotZero;
864
- };
865
-
866
- SourceGroup.prototype._createAudioPreview = function(preview, waveformData, redraw) {
867
- if (waveformData.hasAudio) {
868
- var waveform = new WaveformShape({
869
- layer: this._layer,
870
- view: this._view,
871
- source: this._source,
872
- height: preview.group.height(),
873
- url: preview.url
874
- });
875
-
876
- preview.group.add(waveform);
877
- this._addToUnwrap(preview.group);
878
-
879
- if (redraw) {
880
- this._layer.rescale(true);
881
- }
882
-
883
- this._previewList.push(preview);
884
- }
891
+ this._previewList.push(preview);
885
892
  };
886
893
 
887
894
  SourceGroup.prototype.getAudioPreview = function() {
@@ -973,37 +980,100 @@ define([
973
980
  imageNumber = 0;
974
981
  }
975
982
 
976
- var imageList = preview.group.getChildren();
977
-
978
- var i = 0;
979
-
980
- for (i = 0; i < imageNumber; i++) {
981
- if (imageList.length > i) {
982
- imageList[i].visible(true);
983
- }
984
- else {
985
- var imagePreview = new Konva.Image({
986
- x: preview.imageData.borderSpacing + i * interImageSpacing,
987
- y: preview.imageData.borderSpacing,
988
- image: preview.imageData.image,
989
- width: preview.imageData.width,
990
- height: preview.imageData.height,
991
- listening: false,
992
- visible: true
993
- });
994
-
995
- preview.group.add(imagePreview);
996
- }
997
- }
998
-
999
- for (i = imageNumber; i < imageList.length; i++) {
1000
- imageList[i].visible(false);
1001
- }
983
+ self._ensureImagePreviewCount(preview, imageNumber, interImageSpacing);
1002
984
  }
1003
985
  }
1004
986
  });
1005
987
  };
1006
988
 
989
+ SourceGroup.prototype._batchDraw = function() {
990
+ var layer = this._group && this._group.getLayer && this._group.getLayer();
991
+
992
+ if (layer && typeof layer.batchDraw === 'function') {
993
+ layer.batchDraw();
994
+ }
995
+ };
996
+
997
+ // Utility to schedule work during idle time or next frame
998
+ SourceGroup.prototype._scheduleIdle = function(fn) {
999
+ if (typeof window !== 'undefined' && window.requestIdleCallback) {
1000
+ return window.requestIdleCallback(fn, { timeout: 50 });
1001
+ }
1002
+
1003
+ if (typeof window !== 'undefined' && window.requestAnimationFrame) {
1004
+ return window.requestAnimationFrame(function() {
1005
+ fn({
1006
+ timeRemaining: function() {
1007
+ return 0;
1008
+ },
1009
+ didTimeout: true
1010
+ });
1011
+ });
1012
+ }
1013
+
1014
+ return setTimeout(function() {
1015
+ fn({
1016
+ timeRemaining: function() {
1017
+ return 0;
1018
+ },
1019
+ didTimeout: true
1020
+ });
1021
+ }, 0);
1022
+ };
1023
+
1024
+ SourceGroup.prototype._ensureImagePreviewCount = function(preview, targetCount, interImageSpacing) {
1025
+ var imageList = preview.group.getChildren();
1026
+ var currentCount = imageList.length;
1027
+
1028
+ for (var i = 0; i < Math.min(currentCount, targetCount); i++) {
1029
+ imageList[i].visible(true);
1030
+ }
1031
+ for (var j = targetCount; j < currentCount; j++) {
1032
+ imageList[j].visible(false);
1033
+ }
1034
+
1035
+ if (currentCount >= targetCount || this._previewBuildQueue.has(preview)) {
1036
+ this._batchDraw();
1037
+ return;
1038
+ }
1039
+
1040
+ this._previewBuildQueue.add(preview);
1041
+
1042
+ var self = this;
1043
+ var nextIndex = currentCount;
1044
+
1045
+ function buildChunk() {
1046
+ var added = 0;
1047
+
1048
+ while (nextIndex < targetCount && added < PREVIEW_CREATE_CHUNK) {
1049
+ var imagePreview = new Konva.Image({
1050
+ x: preview.imageData.borderSpacing + nextIndex * interImageSpacing,
1051
+ y: preview.imageData.borderSpacing,
1052
+ image: preview.imageData.image,
1053
+ width: preview.imageData.width,
1054
+ height: preview.imageData.height,
1055
+ listening: false,
1056
+ visible: true
1057
+ });
1058
+
1059
+ preview.group.add(imagePreview);
1060
+ nextIndex += 1;
1061
+ added += 1;
1062
+ }
1063
+
1064
+ self._batchDraw();
1065
+
1066
+ if (nextIndex < targetCount) {
1067
+ self._scheduleIdle(buildChunk);
1068
+ }
1069
+ else {
1070
+ self._previewBuildQueue.delete(preview);
1071
+ }
1072
+ }
1073
+
1074
+ this._scheduleIdle(buildChunk);
1075
+ };
1076
+
1007
1077
  SourceGroup.prototype._createImagePreview = function(preview, image, redraw) {
1008
1078
  preview.imageData = {
1009
1079
  image: image,
@@ -1024,27 +1094,19 @@ define([
1024
1094
  preview.imageData.width = preview.imageData.height * preview.imageData.dimRatio;
1025
1095
  preview.imageData.imageSpacing = preview.imageData.width * SPACING_BETWEEN_PREVIEWS;
1026
1096
 
1027
- var currentX = preview.imageData.borderSpacing;
1097
+ this._addToUnwrap(preview.group);
1028
1098
 
1029
- while (currentX < this._width) {
1030
- var imagePreview = new Konva.Image({
1031
- x: currentX,
1032
- y: preview.imageData.borderSpacing,
1033
- image: image,
1034
- width: preview.imageData.width,
1035
- height: preview.imageData.height,
1036
- listening: false
1037
- });
1099
+ var interImageSpacing = preview.imageData.width + preview.imageData.imageSpacing;
1038
1100
 
1039
- preview.group.add(imagePreview);
1101
+ var targetCount = 0;
1040
1102
 
1041
- currentX += preview.imageData.width + preview.imageData.imageSpacing;
1103
+ if (this._width > preview.imageData.borderSpacing) {
1104
+ targetCount = Math.trunc((this._width - preview.imageData.borderSpacing) / interImageSpacing) + 1;
1042
1105
  }
1043
-
1044
- this._addToUnwrap(preview.group);
1106
+ this._ensureImagePreviewCount(preview, targetCount, interImageSpacing);
1045
1107
 
1046
1108
  if (redraw) {
1047
- this._group.draw();
1109
+ this._batchDraw();
1048
1110
  }
1049
1111
 
1050
1112
  this._previewList.push(preview);
@@ -1435,6 +1497,14 @@ define([
1435
1497
  this._buttonsAnimation.destroy();
1436
1498
  this._buttonsAnimation = null;
1437
1499
  }
1500
+ if (!this._buttonsGroup.getLayer()) {
1501
+ // If the node is not in a layer, avoid creating a Tween
1502
+ if (!this._buttonsGroup.getLayer()) {
1503
+ this._buttonsGroup.visible(true);
1504
+ this._buttonsGroup.opacity(1);
1505
+ return;
1506
+ }
1507
+ }
1438
1508
 
1439
1509
  var self = this;
1440
1510
 
@@ -1459,6 +1529,12 @@ define([
1459
1529
  this._buttonsAnimation.destroy();
1460
1530
  this._buttonsAnimation = null;
1461
1531
  }
1532
+ if (!this._buttonsGroup.getLayer()) {
1533
+ // If the node is not in a layer, avoid creating a Tween
1534
+ this._buttonsGroup.visible(false);
1535
+ this._buttonsGroup.opacity(0);
1536
+ return;
1537
+ }
1462
1538
 
1463
1539
  var self = this;
1464
1540
 
@@ -1603,7 +1679,7 @@ define([
1603
1679
  self._source.volume = Math.max(self._source.volumeRange[0], Math.min(volume, self._source.volumeRange[1]));
1604
1680
  self._peaks.emit('source.volumeChanged', self._source);
1605
1681
 
1606
- self._group.draw();
1682
+ self._batchDraw();
1607
1683
  });
1608
1684
 
1609
1685
  volumeSliderGroup.on('dragend', function() {
@@ -58,8 +58,17 @@ define([
58
58
  this._peaks.on('data.retrieved', this._onDataRetrieved.bind(this));
59
59
  this._peaks.on('handler.segments.show', this._onSegmentsShow.bind(this));
60
60
  this._peaks.on('model.source.setIndicators', this.setIndicators.bind(this));
61
+ this._peaks.on('handler.view.mouseup', this._stopDrag.bind(this));
61
62
  }
62
63
 
64
+ SourcesLayer.prototype._stopDrag = function() {
65
+ const draggedSourceGroup = this._sourcesGroup[this._draggedElementId];
66
+
67
+ if (draggedSourceGroup) {
68
+ draggedSourceGroup.stopDrag();
69
+ }
70
+ };
71
+
63
72
  SourcesLayer.prototype.fitToView = function() {
64
73
  this._lineGroups.fitToView();
65
74
  };
@@ -109,20 +118,31 @@ define([
109
118
  };
110
119
 
111
120
  SourcesLayer.prototype._onSourceUpdate = function(source) {
121
+ const sourceGroup = this._sourcesGroup[source.id];
122
+ const frameOffset = this._view.getFrameOffset();
123
+ const width = this._view.getWidth();
124
+ const frameStartTime = this._view.pixelsToTime(frameOffset);
125
+ const frameEndTime = this._view.pixelsToTime(frameOffset + width);
112
126
  var redraw = false;
113
- var sourceGroup = this._sourcesGroup[source.id];
114
- var frameOffset = this._view.getFrameOffset();
115
- var width = this._view.getWidth();
116
- var frameStartTime = this._view.pixelsToTime(frameOffset);
117
- var frameEndTime = this._view.pixelsToTime(frameOffset + width);
127
+ var isSourceGroupHovered = false;
128
+ var isSourceGroupActive = false;
118
129
 
119
130
  if (sourceGroup) {
131
+ isSourceGroupHovered = sourceGroup.isHovered();
132
+ isSourceGroupActive = sourceGroup.isActive();
120
133
  this._destroySourceGroup(source);
121
134
  redraw = true;
122
135
  }
123
136
 
124
- if (source.isVisible(frameStartTime, frameEndTime)) {
125
- this._addSourceGroup(source);
137
+ if (source.isVisible(frameStartTime, frameEndTime) || isSourceGroupActive) {
138
+ const newSourceGroup = this._addSourceGroup(source);
139
+
140
+ if (isSourceGroupHovered) {
141
+ newSourceGroup.startHover();
142
+ }
143
+ if (isSourceGroupActive) {
144
+ newSourceGroup.startDrag();
145
+ }
126
146
  redraw = true;
127
147
  }
128
148
 
@@ -140,7 +160,7 @@ define([
140
160
  }
141
161
  }.bind(this));
142
162
 
143
- this.draw();
163
+ this.batchDraw();
144
164
  };
145
165
 
146
166
  SourcesLayer.prototype._onSourcesAdd = function(sources) {
@@ -170,7 +190,7 @@ define([
170
190
 
171
191
  this._view.updateTimelineLength();
172
192
 
173
- this._layer.draw();
193
+ this._layer.batchDraw();
174
194
  };
175
195
 
176
196
  SourcesLayer.prototype._onSourcesShow = function(sources) {
@@ -180,7 +200,7 @@ define([
180
200
  self._sourcesGroup[source.id].setWrapping(false, true);
181
201
  });
182
202
 
183
- this._layer.draw();
203
+ this._layer.batchDraw();
184
204
  };
185
205
 
186
206
  SourcesLayer.prototype._onSourcesHide = function(sources) {
@@ -190,7 +210,7 @@ define([
190
210
  self._sourcesGroup[source.id].setWrapping(true, true);
191
211
  });
192
212
 
193
- this._layer.draw();
213
+ this._layer.batchDraw();
194
214
  };
195
215
 
196
216
  SourcesLayer.prototype._onDataRetrieved = function(data, source, url) {
@@ -223,7 +243,7 @@ define([
223
243
  SourcesLayer.prototype._onSegmentsShow = function(segmentsGroupId, lineId) {
224
244
  this._lineGroups.addSegments(segmentsGroupId, lineId);
225
245
  this._view.updateTimelineLength();
226
- this._layer.draw();
246
+ this._layer.batchDraw();
227
247
  };
228
248
 
229
249
  /**
@@ -265,7 +285,7 @@ define([
265
285
 
266
286
  if (sourceGroup) {
267
287
  sourceGroup.createIndicators();
268
- this._layer.draw();
288
+ this._layer.batchDraw();
269
289
  }
270
290
  };
271
291
 
@@ -292,7 +312,7 @@ define([
292
312
  count += this._removeInvisibleSources(startTime, endTime);
293
313
 
294
314
  if (count > 0) {
295
- this._layer.draw();
315
+ this._layer.batchDraw();
296
316
  }
297
317
  };
298
318
 
@@ -300,18 +320,18 @@ define([
300
320
  this._initialTimeOffset = this._view.getTimeOffset();
301
321
  this._mouseDownX = this._view.getPointerPosition().x;
302
322
 
303
- const draggedElementId = element.currentTarget.attrs.sourceId;
323
+ this._draggedElementId = element.currentTarget.attrs.sourceId;
304
324
 
305
325
  var selectedElements = this._view.getSelectedElements();
306
326
  const shouldDragSelectedElements = Object.keys(selectedElements).includes(
307
- draggedElementId
327
+ this._draggedElementId
308
328
  );
309
329
 
310
330
  if (shouldDragSelectedElements) {
311
331
  this._draggedElements = Object.values(selectedElements).sort((a, b) => a.startTime - b.startTime);
312
332
  }
313
333
  else {
314
- this._draggedElements = [this._sourcesGroup[draggedElementId].getSource()];
334
+ this._draggedElements = [this._sourcesGroup[this._draggedElementId].getSource()];
315
335
  this._view.deselectAll();
316
336
  }
317
337
 
@@ -343,7 +363,9 @@ define([
343
363
  }.bind(this)
344
364
  );
345
365
 
346
- this._view.drawSourcesLayer();
366
+ this._draggedElementId = null;
367
+
368
+ this._view.batchDrawSourcesLayer();
347
369
  this._view.updateTimelineLength();
348
370
 
349
371
  this._peaks.emit('sources.updated', updatedSources);
@@ -387,7 +409,7 @@ define([
387
409
  );
388
410
 
389
411
  if (shouldRedraw) {
390
- this.draw();
412
+ this.batchDraw();
391
413
  }
392
414
  };
393
415
 
@@ -603,8 +625,8 @@ define([
603
625
  this._layer.setVisible(visible);
604
626
  };
605
627
 
606
- SourcesLayer.prototype.draw = function() {
607
- this._layer.draw();
628
+ SourcesLayer.prototype.batchDraw = function() {
629
+ this._layer.batchDraw();
608
630
  };
609
631
 
610
632
  SourcesLayer.prototype.listening = function(bool) {
@@ -660,7 +682,7 @@ define([
660
682
  });
661
683
  }
662
684
  }
663
- this._layer.draw();
685
+ this._layer.batchDraw();
664
686
  };
665
687
 
666
688
  SourcesLayer.prototype._shouldResampleAudio = function(audioUrl, urls) {
@@ -685,6 +707,7 @@ define([
685
707
  this._peaks.off('data.retrieved', this._onDataRetrieved);
686
708
  this._peaks.off('handler.segments.show', this._onSegmentsShow);
687
709
  this._peaks.off('model.source.setIndicators', this.setIndicators);
710
+ this._peaks.off('handler.view.mouseup', this._stopDrag);
688
711
  };
689
712
 
690
713
  SourcesLayer.prototype.getHeight = function() {
@@ -16,6 +16,14 @@ define([
16
16
 
17
17
  var isXhr2 = ('withCredentials' in new XMLHttpRequest());
18
18
 
19
+ // Schedule heavy work during idle time to avoid UI stutter
20
+ function scheduleIdle(fn) {
21
+ if (typeof window !== 'undefined' && window.requestIdleCallback) {
22
+ return window.requestIdleCallback(fn, { timeout: 80 });
23
+ }
24
+ return setTimeout(fn, 0);
25
+ }
26
+
19
27
  /**
20
28
  * Creates and returns a WaveformData object, either by requesting the
21
29
  * waveform data from the server, or by creating the waveform data using the
@@ -197,14 +205,21 @@ define([
197
205
  return;
198
206
  }
199
207
 
200
- var waveformData = WaveformData.create(event.target.response);
208
+ scheduleIdle(function() {
209
+ try {
210
+ var waveformData = WaveformData.create(event.target.response);
201
211
 
202
- if (waveformData.channels !== 1 && waveformData.channels !== 2) {
203
- callback(new Error('Peaks.init(): Only mono or stereo waveforms are currently supported'));
204
- return;
205
- }
212
+ if (waveformData.channels !== 1 && waveformData.channels !== 2) {
213
+ callback(new Error('Peaks.init(): Only mono or stereo waveforms are currently supported'));
214
+ return;
215
+ }
206
216
 
207
- callback(null, waveformData);
217
+ callback(null, waveformData);
218
+ }
219
+ catch (err) {
220
+ callback(err);
221
+ }
222
+ });
208
223
  },
209
224
  function() {
210
225
  callback(new Error('XHR Failed'));
@@ -255,19 +270,21 @@ define([
255
270
  return;
256
271
  }
257
272
 
258
- try {
259
- var createdWaveformData = WaveformData.create(data);
273
+ scheduleIdle(function() {
274
+ try {
275
+ var createdWaveformData = WaveformData.create(data);
276
+
277
+ if (createdWaveformData.channels !== 1 && createdWaveformData.channels !== 2) {
278
+ callback(new Error('Peaks.init(): Only mono or stereo waveforms are currently supported'));
279
+ return;
280
+ }
260
281
 
261
- if (createdWaveformData.channels !== 1 && createdWaveformData.channels !== 2) {
262
- callback(new Error('Peaks.init(): Only mono or stereo waveforms are currently supported'));
263
- return;
282
+ callback(null, createdWaveformData);
264
283
  }
265
-
266
- callback(null, createdWaveformData);
267
- }
268
- catch (err) {
269
- callback(err);
270
- }
284
+ catch (err) {
285
+ callback(err);
286
+ }
287
+ });
271
288
  };
272
289
 
273
290
  /**