@checksub_team/peaks_timeline 2.0.0-alpha.14 → 2.0.0-alpha.16

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.
@@ -63,18 +63,18 @@ define([
63
63
  Axis.prototype._onPlayheadMoved = function(playheadX, playheadWidth) {
64
64
  this._maskStart = playheadX + this._view.getFrameOffset();
65
65
  this._maskEnd = playheadX + this._view.getFrameOffset() + playheadWidth;
66
- this._frontLayer.draw();
66
+ this._frontLayer.batchDraw();
67
67
  };
68
68
 
69
69
  Axis.prototype._onPlayheadHidden = function() {
70
70
  this._maskStart = null;
71
71
  this._maskEnd = null;
72
- this._frontLayer.draw();
72
+ this._frontLayer.batchDraw();
73
73
  };
74
74
 
75
- Axis.prototype.draw = function() {
76
- this._backLayer.draw();
77
- this._frontLayer.draw();
75
+ Axis.prototype.batchDraw = function() {
76
+ this._backLayer.batchDraw();
77
+ this._frontLayer.batchDraw();
78
78
  };
79
79
 
80
80
  Axis.prototype.addBackToStage = function(stage) {
@@ -86,12 +86,12 @@ define([
86
86
  if (self._options.draggable) {
87
87
  group.on('dragstart', function() {
88
88
  self._label.show();
89
- self._options.group.draw();
89
+ self._batchDraw();
90
90
  });
91
91
 
92
92
  group.on('dragend', function() {
93
93
  self._label.hide();
94
- self._options.group.draw();
94
+ self._batchDraw();
95
95
  });
96
96
  }
97
97
 
@@ -100,13 +100,13 @@ define([
100
100
  self._options.view.setCursor('ew-resize');
101
101
  self._label.show();
102
102
  self._group.moveToTop();
103
- self._options.view.drawSourcesLayer();
103
+ self._options.view.batchDrawSourcesLayer();
104
104
  });
105
105
 
106
106
  self._handle.on('mouseout touchend', function() {
107
107
  self._options.view.setCursor('default');
108
108
  self._label.hide();
109
- self._options.view.drawSourcesLayer();
109
+ self._options.view.batchDrawSourcesLayer();
110
110
  });
111
111
  }
112
112
  };
@@ -128,5 +128,14 @@ define([
128
128
  this._label.setText(Utils.formatTime(time, false));
129
129
  };
130
130
 
131
+ DefaultSegmentMarker.prototype._batchDraw = function() {
132
+ const group = this._options.group;
133
+ const layer = group && group.getLayer && group.getLayer();
134
+
135
+ if (layer && typeof layer.batchDraw === 'function') {
136
+ layer.batchDraw();
137
+ }
138
+ };
139
+
131
140
  return DefaultSegmentMarker;
132
141
  });
@@ -61,6 +61,8 @@ define([
61
61
  this._peaks.on('line.heightChanged', this._onLineHeightChanged.bind(this));
62
62
 
63
63
  this._peaks.on('segments.dragend', this._onSegmentUpdated.bind(this));
64
+
65
+ this._peaks.on('lineIndicator.drag', this._onIndicatorDrag.bind(this));
64
66
  }
65
67
 
66
68
  LineGroups.prototype.fitToView = function() {
@@ -563,6 +565,40 @@ define([
563
565
  return line.id;
564
566
  };
565
567
 
568
+ LineGroups.prototype._onIndicatorDrag = function(lineId, y) {
569
+ const lineGroup = this._lineGroupsById[lineId];
570
+
571
+ if (!lineGroup) {
572
+ return;
573
+ }
574
+
575
+ const positions = this.getLinesUnderY(y);
576
+
577
+ if (positions[0] !== positions[1] || positions[0] === lineGroup.getPosition()) {
578
+ return;
579
+ }
580
+
581
+ const targetPos = positions[0];
582
+ const targetLineGroup = this._lineGroupsByPosition[targetPos];
583
+ const targetCenterY = targetLineGroup.y() + (targetLineGroup.lineHeight() / 2);
584
+ const movingDown = targetPos > lineGroup.getPosition();
585
+
586
+ if ((movingDown && y < targetCenterY) || (!movingDown && y > targetCenterY)) {
587
+ return;
588
+ }
589
+
590
+ if (targetPos === lineGroup.getPosition() + 1) {
591
+ this._setLinePosition(targetLineGroup.getId(), lineGroup.getPosition());
592
+ }
593
+ else {
594
+ this._setLinePosition(lineId, targetPos);
595
+ }
596
+
597
+ this.refreshLineYs();
598
+
599
+ this._peaks.emit('line.moved', lineGroup.getLine());
600
+ };
601
+
566
602
  LineGroups.prototype.updateSegments = function(frameStartTime, frameEndTime) {
567
603
  for (var lineId in this._segmentsGroups) {
568
604
  if (Utils.objectHasProperty(this._segmentsGroups, lineId)) {
@@ -68,7 +68,14 @@ define([
68
68
 
69
69
  this._layer.add(this._separatingLine);
70
70
 
71
- this._layer.draw();
71
+ this._layer.batchDraw();
72
+
73
+ this._isDragging = false;
74
+ this._dragLineId = null;
75
+ this._dragContainerRect = null;
76
+
77
+ this._onWindowMove = this._onWindowMove.bind(this);
78
+ this._onWindowUp = this._onWindowUp.bind(this);
72
79
  }
73
80
 
74
81
  LineIndicator.prototype.fitToView = function() {
@@ -165,7 +172,7 @@ define([
165
172
  indicator.getChildren().forEach(function(child) {
166
173
  child.fill(child.getAttr('selectedColor'));
167
174
  });
168
- self.draw();
175
+ self.batchDraw();
169
176
  self._stage.container().style.cursor = 'pointer';
170
177
  });
171
178
 
@@ -173,14 +180,27 @@ define([
173
180
  indicator.getChildren().forEach(function(child) {
174
181
  child.fill(child.getAttr('defaultColor'));
175
182
  });
176
- self.draw();
177
- self._stage.container().style.cursor = 'default';
183
+ self.batchDraw();
184
+ if (!self._isDragging) {
185
+ self._stage.container().style.cursor = 'default';
186
+ }
178
187
  });
179
188
 
180
189
  indicator.on('click', function(e) {
181
190
  self._peaks.emit('lineIndicator.click', self._indicators[lineGroup.getId()], e.evt);
182
191
  });
183
192
 
193
+ indicator.on('mousedown touchstart', function() {
194
+ self._dragLineId = lineGroup.getId();
195
+ self._dragContainerRect = self._stage.getContainer().getBoundingClientRect();
196
+
197
+ window.addEventListener('mousemove', self._onWindowMove, false);
198
+ window.addEventListener('touchmove', self._onWindowMove, false);
199
+ window.addEventListener('mouseup', self._onWindowUp, false);
200
+ window.addEventListener('touchend', self._onWindowUp, false);
201
+ window.addEventListener('blur', self._onWindowUp, false);
202
+ });
203
+
184
204
  return indicator;
185
205
  };
186
206
 
@@ -230,7 +250,7 @@ define([
230
250
  indicatorData.type = line.indicatorType;
231
251
  indicatorData.text = line.indicatorText;
232
252
 
233
- this.draw();
253
+ this.batchDraw();
234
254
  };
235
255
 
236
256
  LineIndicator.prototype.removeIndicator = function(lineId, keepInList) {
@@ -300,13 +320,50 @@ define([
300
320
  }
301
321
 
302
322
  if (anyChange) {
303
- this.draw();
323
+ this.batchDraw();
304
324
  }
305
325
  return anyChange;
306
326
  };
307
327
 
308
- LineIndicator.prototype.draw = function() {
309
- this._layer.draw();
328
+ LineIndicator.prototype.batchDraw = function() {
329
+ this._layer.batchDraw();
330
+ };
331
+
332
+ LineIndicator.prototype._onWindowMove = function(event) {
333
+ if (!this._dragContainerRect) {
334
+ return;
335
+ }
336
+
337
+ if (!this._isDragging) {
338
+ this._stage.container().style.cursor = 'grabbing';
339
+ }
340
+
341
+ var clientY;
342
+
343
+ if (event.type === 'touchmove') {
344
+ clientY = Math.floor(event.changedTouches[0].clientY);
345
+ }
346
+ else {
347
+ clientY = event.clientY;
348
+ }
349
+
350
+ const relY = clientY - this._dragContainerRect.top;
351
+
352
+ this._peaks.emit('lineIndicator.drag', this._dragLineId, relY);
353
+ };
354
+
355
+ LineIndicator.prototype._onWindowUp = function() {
356
+ window.removeEventListener('mousemove', this._onWindowMove, false);
357
+ window.removeEventListener('touchmove', this._onWindowMove, false);
358
+ window.removeEventListener('mouseup', this._onWindowUp, false);
359
+ window.removeEventListener('touchend', this._onWindowUp, false);
360
+ window.removeEventListener('blur', this._onWindowUp, false);
361
+
362
+ this._isDragging = false;
363
+ this._dragLineId = null;
364
+ this._dragContainerRect = null;
365
+
366
+ this._stage.container().style.cursor = 'pointer';
310
367
  };
311
368
 
312
369
  return LineIndicator;
@@ -229,7 +229,7 @@ define([
229
229
  }
230
230
  else {
231
231
  this.deselectDifference([], true);
232
- this._view.drawSourcesLayer(); // Redraw sources layer to remove selection
232
+ this._view.batchDrawSourcesLayer(); // Redraw sources layer to remove selection
233
233
  }
234
234
  };
235
235
 
@@ -258,7 +258,7 @@ define([
258
258
  ModeLayer.prototype._onMouseEnterInCutMode = function() {
259
259
  this._cutGroup.visible(true);
260
260
 
261
- this._layer.draw();
261
+ this._layer.batchDraw();
262
262
  };
263
263
 
264
264
  ModeLayer.prototype._updateCursorTime = function(position) {
@@ -359,13 +359,13 @@ define([
359
359
  this._updateCursorTime(cuttingPosition);
360
360
  this._updateCuttingLine(cuttingPosition);
361
361
 
362
- this._layer.draw();
362
+ this._layer.batchDraw();
363
363
  };
364
364
 
365
365
  ModeLayer.prototype._onMouseLeaveInCutMode = function() {
366
366
  this._cutGroup.visible(false);
367
367
 
368
- this._layer.draw();
368
+ this._layer.batchDraw();
369
369
  };
370
370
 
371
371
  ModeLayer.prototype._onMouseClickInCutMode = function() {
@@ -417,7 +417,7 @@ define([
417
417
  this._updateCursorTime(cuttingPosition);
418
418
  this._updateCuttingLine(cuttingPosition);
419
419
 
420
- this._layer.draw();
420
+ this._layer.batchDraw();
421
421
  }
422
422
  }
423
423
  };
@@ -494,8 +494,8 @@ define([
494
494
  }
495
495
 
496
496
  this._mode = mode;
497
- this._layer.draw();
498
- this._view.drawSourcesLayer();
497
+ this._layer.batchDraw();
498
+ this._view.batchDrawSourcesLayer();
499
499
  };
500
500
 
501
501
  ModeLayer.prototype.getCurrentMode = function() {
@@ -269,7 +269,7 @@ define([
269
269
  }
270
270
 
271
271
  this._time = time;
272
- this._playheadLayer.draw();
272
+ this._playheadLayer.batchDraw();
273
273
  };
274
274
 
275
275
  /**
@@ -307,7 +307,7 @@ define([
307
307
  }
308
308
 
309
309
  if (updated) {
310
- this._playheadLayer.draw();
310
+ this._playheadLayer.batchDraw();
311
311
  }
312
312
  };
313
313
 
@@ -380,7 +380,7 @@ define([
380
380
  0.65, this._segment.warningColor
381
381
  ]);
382
382
 
383
- this._view.drawSourcesLayer();
383
+ this._view.batchDrawSourcesLayer();
384
384
 
385
385
  this._peaks.emit('segments.mouseenter', this._segment);
386
386
  };
@@ -400,7 +400,7 @@ define([
400
400
  0.65, this._segment.warningColor
401
401
  ]);
402
402
 
403
- this._view.drawSourcesLayer();
403
+ this._view.batchDrawSourcesLayer();
404
404
 
405
405
  this._peaks.emit('segments.mouseleave', this._segment);
406
406
  };
@@ -377,7 +377,7 @@ define([
377
377
  };
378
378
 
379
379
  SegmentsGroup.prototype._draw = function() {
380
- this._view.drawSourcesLayer();
380
+ this._view.batchDrawSourcesLayer();
381
381
  };
382
382
 
383
383
  /**
@@ -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
 
@@ -131,7 +134,7 @@ define([
131
134
  if (!this._source.loading) {
132
135
  this._showButtons();
133
136
  }
134
- this._group.draw();
137
+ this._batchDraw();
135
138
  };
136
139
 
137
140
  SourceGroup.prototype._onHoverEnd = function() {
@@ -139,7 +142,7 @@ define([
139
142
  this._manualHover = false;
140
143
  this._view.setHoveredElement(null);
141
144
  this._hideButtons();
142
- this._group.draw();
145
+ this._batchDraw();
143
146
  };
144
147
 
145
148
  SourceGroup.prototype._onDragStart = function(element) {
@@ -211,7 +214,7 @@ define([
211
214
  leftHandle ? start + diff + timeOffsetDiff : null,
212
215
  leftHandle ? null : end + diff + timeOffsetDiff
213
216
  )) {
214
- this._layer.draw();
217
+ this._layer.batchDraw();
215
218
  }
216
219
  }.bind(this)
217
220
  );
@@ -843,80 +846,49 @@ define([
843
846
  throw err;
844
847
  }
845
848
 
846
- originalWaveformData.hasAudio = self._hasAudio(originalWaveformData);
849
+ var newScale = originalWaveformData.sample_rate / self._view.getTimeToPixelsMaxZoom();
847
850
 
848
- if (originalWaveformData.hasAudio) {
849
- var newScale = originalWaveformData.sample_rate / self._view.getTimeToPixelsMaxZoom();
850
-
851
- if (newScale > originalWaveformData.scale) {
852
- self._minScale = newScale;
853
- }
854
- else {
855
- self._minScale = originalWaveformData.scale;
856
- }
857
-
858
- 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;
859
856
  }
860
857
 
858
+ self._view.setTimeToPixelsMaxZoom(originalWaveformData.sample_rate / self._minScale);
859
+
861
860
  self._layer.setLoadedData(url, originalWaveformData);
862
861
  self._layer.setLoadedData(
863
862
  url + '-scaled',
864
863
  { data: originalWaveformData, scale: originalWaveformData.sample_rate / self._minScale }
865
864
  );
866
865
  preview.loaded = true;
867
- self._createAudioPreview(preview, originalWaveformData, redraw);
866
+ self._createAudioPreview(preview, redraw);
868
867
  });
869
868
  }
870
869
  else {
871
870
  preview.loaded = true;
872
- this._createAudioPreview(preview, audioData, redraw);
871
+ this._createAudioPreview(preview, redraw);
873
872
  }
874
873
  };
875
874
 
876
- SourceGroup.prototype._hasAudio = function(waveformData) {
877
- var channels = waveformData.channels;
878
- var channel, someIsNotZero = false;
879
-
880
- for (var i = 0; i < channels; i++) {
881
- channel = waveformData.channel(i);
882
-
883
- someIsNotZero = channel.min_array().some(function(item) {
884
- return item !== 0;
885
- });
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
+ });
886
883
 
887
- if (!someIsNotZero) {
888
- someIsNotZero = channel.max_array().some(function(item) {
889
- return item !== 0;
890
- });
891
- }
884
+ preview.group.add(waveform);
885
+ this._addToUnwrap(preview.group);
892
886
 
893
- if (someIsNotZero) {
894
- break;
895
- }
887
+ if (redraw) {
888
+ this._layer.rescale(true);
896
889
  }
897
890
 
898
- return someIsNotZero;
899
- };
900
-
901
- SourceGroup.prototype._createAudioPreview = function(preview, waveformData, redraw) {
902
- if (waveformData.hasAudio) {
903
- var waveform = new WaveformShape({
904
- layer: this._layer,
905
- view: this._view,
906
- source: this._source,
907
- height: preview.group.height(),
908
- url: preview.url
909
- });
910
-
911
- preview.group.add(waveform);
912
- this._addToUnwrap(preview.group);
913
-
914
- if (redraw) {
915
- this._layer.rescale(true);
916
- }
917
-
918
- this._previewList.push(preview);
919
- }
891
+ this._previewList.push(preview);
920
892
  };
921
893
 
922
894
  SourceGroup.prototype.getAudioPreview = function() {
@@ -1008,37 +980,100 @@ define([
1008
980
  imageNumber = 0;
1009
981
  }
1010
982
 
1011
- var imageList = preview.group.getChildren();
1012
-
1013
- var i = 0;
1014
-
1015
- for (i = 0; i < imageNumber; i++) {
1016
- if (imageList.length > i) {
1017
- imageList[i].visible(true);
1018
- }
1019
- else {
1020
- var imagePreview = new Konva.Image({
1021
- x: preview.imageData.borderSpacing + i * interImageSpacing,
1022
- y: preview.imageData.borderSpacing,
1023
- image: preview.imageData.image,
1024
- width: preview.imageData.width,
1025
- height: preview.imageData.height,
1026
- listening: false,
1027
- visible: true
1028
- });
1029
-
1030
- preview.group.add(imagePreview);
1031
- }
1032
- }
1033
-
1034
- for (i = imageNumber; i < imageList.length; i++) {
1035
- imageList[i].visible(false);
1036
- }
983
+ self._ensureImagePreviewCount(preview, imageNumber, interImageSpacing);
1037
984
  }
1038
985
  }
1039
986
  });
1040
987
  };
1041
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
+
1042
1077
  SourceGroup.prototype._createImagePreview = function(preview, image, redraw) {
1043
1078
  preview.imageData = {
1044
1079
  image: image,
@@ -1059,27 +1094,19 @@ define([
1059
1094
  preview.imageData.width = preview.imageData.height * preview.imageData.dimRatio;
1060
1095
  preview.imageData.imageSpacing = preview.imageData.width * SPACING_BETWEEN_PREVIEWS;
1061
1096
 
1062
- var currentX = preview.imageData.borderSpacing;
1097
+ this._addToUnwrap(preview.group);
1063
1098
 
1064
- while (currentX < this._width) {
1065
- var imagePreview = new Konva.Image({
1066
- x: currentX,
1067
- y: preview.imageData.borderSpacing,
1068
- image: image,
1069
- width: preview.imageData.width,
1070
- height: preview.imageData.height,
1071
- listening: false
1072
- });
1099
+ var interImageSpacing = preview.imageData.width + preview.imageData.imageSpacing;
1073
1100
 
1074
- preview.group.add(imagePreview);
1101
+ var targetCount = 0;
1075
1102
 
1076
- 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;
1077
1105
  }
1078
-
1079
- this._addToUnwrap(preview.group);
1106
+ this._ensureImagePreviewCount(preview, targetCount, interImageSpacing);
1080
1107
 
1081
1108
  if (redraw) {
1082
- this._group.draw();
1109
+ this._batchDraw();
1083
1110
  }
1084
1111
 
1085
1112
  this._previewList.push(preview);
@@ -1652,7 +1679,7 @@ define([
1652
1679
  self._source.volume = Math.max(self._source.volumeRange[0], Math.min(volume, self._source.volumeRange[1]));
1653
1680
  self._peaks.emit('source.volumeChanged', self._source);
1654
1681
 
1655
- self._group.draw();
1682
+ self._batchDraw();
1656
1683
  });
1657
1684
 
1658
1685
  volumeSliderGroup.on('dragend', function() {