@checksub_team/peaks_timeline 1.16.1 → 2.0.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/package.json +1 -1
  2. package/peaks.js +4716 -4409
  3. package/peaks.js.d.ts +5 -5
  4. package/src/{timeline-axis.js → components/axis.js} +244 -244
  5. package/src/{data-retriever.js → components/data-retriever.js} +117 -117
  6. package/src/{default-segment-marker.js → components/default-segment-marker.js} +132 -132
  7. package/src/{invoker.js → components/invoker.js} +81 -81
  8. package/src/components/line-group.js +692 -0
  9. package/src/components/line-groups.js +585 -0
  10. package/src/{line-indicator.js → components/line-indicator.js} +308 -303
  11. package/src/{marker-factories.js → components/marker-factories.js} +1 -1
  12. package/src/{mode-layer.js → components/mode-layer.js} +8 -12
  13. package/src/{playhead-layer.js → components/playhead-layer.js} +3 -3
  14. package/src/{segment-marker.js → components/segment-marker.js} +2 -2
  15. package/src/{segment-shape.js → components/segment-shape.js} +508 -508
  16. package/src/{segments-group.js → components/segments-group.js} +805 -801
  17. package/src/{source-group.js → components/source-group.js} +1661 -1640
  18. package/src/{sources-layer.js → components/sources-layer.js} +716 -730
  19. package/src/{waveform-builder.js → components/waveform-builder.js} +2 -2
  20. package/src/{waveform-shape.js → components/waveform-shape.js} +214 -214
  21. package/src/keyboard-handler.js +9 -9
  22. package/src/line-handler.js +179 -0
  23. package/src/main.js +110 -71
  24. package/src/models/line.js +156 -0
  25. package/src/{segment.js → models/segment.js} +420 -419
  26. package/src/{source.js → models/source.js} +1311 -1315
  27. package/src/player.js +2 -2
  28. package/src/{timeline-segments.js → segment-handler.js} +435 -435
  29. package/src/{timeline-sources.js → source-handler.js} +521 -514
  30. package/src/utils.js +5 -1
  31. package/src/{timeline-zoomview.js → view.js} +136 -137
  32. package/src/line.js +0 -690
  33. package/src/lines.js +0 -427
  34. /package/src/{data.js → components/data.js} +0 -0
  35. /package/src/{loader.js → components/loader.js} +0 -0
  36. /package/src/{mouse-drag-handler.js → components/mouse-drag-handler.js} +0 -0
  37. /package/src/{svgs.js → components/svgs.js} +0 -0
@@ -1,730 +1,716 @@
1
- /**
2
- * @file
3
- *
4
- * Defines the {@link SourcesLayer} class.
5
- *
6
- * @module sources-layer
7
- */
8
-
9
- define([
10
- './source-group',
11
- './lines',
12
- './data-retriever',
13
- './utils',
14
- './invoker',
15
- 'konva'
16
- ], function(
17
- SourceGroup,
18
- Lines,
19
- DataRetriever,
20
- Utils,
21
- Invoker,
22
- Konva) {
23
- 'use strict';
24
-
25
- /**
26
- * Creates a Konva.Layer that displays sources on the timeline.
27
- *
28
- * @class
29
- * @alias SourcesLayer
30
- *
31
- * @param {Peaks} peaks
32
- * @param {WaveformOverview|WaveformZoomView} view
33
- * @param {Boolean} allowEditing
34
- */
35
-
36
- function SourcesLayer(peaks, view, allowEditing) {
37
- this._peaks = peaks;
38
- this._view = view;
39
- this._allowEditing = allowEditing;
40
- this._sourcesGroup = {};
41
- this._layer = new Konva.Layer();
42
- this._dataRetriever = new DataRetriever(peaks);
43
- this._lines = new Lines(peaks, view, this);
44
- this._lines.addToLayer(this);
45
-
46
- this._loadedData = {};
47
-
48
- this._debouncedRescale = new Invoker().debounce(
49
- this._rescale, 150
50
- );
51
-
52
- this._peaks.on('sources.add', this._onSourcesAdd.bind(this));
53
- this._peaks.on('sources.destroy', this._onSourcesDestroy.bind(this));
54
- this._peaks.on('sources.show', this._onSourcesShow.bind(this));
55
- this._peaks.on('sources.hide', this._onSourcesHide.bind(this));
56
- this._peaks.on('sources.setSelected', this._onSourcesSetSelected.bind(this));
57
- this._peaks.on('source.update', this._onSourceUpdate.bind(this));
58
- this._peaks.on('data.retrieved', this._onDataRetrieved.bind(this));
59
- this._peaks.on('sources.refresh', this._onSourcesRefresh.bind(this));
60
- this._peaks.on('segments.show', this._onSegmentsShow.bind(this));
61
- this._peaks.on('options.set.line_height', this._onOptionsLineHeightChange.bind(this));
62
- this._peaks.on('source.setIndicators', this.setIndicators.bind(this));
63
- }
64
-
65
- SourcesLayer.prototype.fitToView = function() {
66
- this._lines.fitToView();
67
- };
68
-
69
- SourcesLayer.prototype.getLoadedData = function(id) {
70
- return this._loadedData[id];
71
- };
72
-
73
- SourcesLayer.prototype.setLoadedData = function(id, data) {
74
- this._loadedData[id] = data;
75
- };
76
-
77
- SourcesLayer.prototype.getSegmentsGroups = function() {
78
- return this._lines.getSegmentsGroups();
79
- };
80
-
81
- SourcesLayer.prototype.add = function(element) {
82
- this._layer.add(element);
83
- };
84
-
85
- /**
86
- * Adds the layer to the given {Konva.Stage}.
87
- *
88
- * @param {Konva.Stage} stage
89
- */
90
-
91
- SourcesLayer.prototype.addToStage = function(stage) {
92
- stage.add(this._layer);
93
- };
94
-
95
- SourcesLayer.prototype.enableEditing = function(enable) {
96
- this._allowEditing = enable;
97
- };
98
-
99
- SourcesLayer.prototype.isEditingEnabled = function() {
100
- return this._allowEditing;
101
- };
102
-
103
- SourcesLayer.prototype._onOptionsLineHeightChange = function(oldHeight) {
104
- var positions = [];
105
-
106
- for (var sourceId in this._sourcesGroup) {
107
- if (Utils.objectHasProperty(this._sourcesGroup, sourceId)) {
108
- var source = this._sourcesGroup[sourceId].getSource();
109
-
110
- if (!positions.includes(source.position)) {
111
- this._lines.changeLineHeight(
112
- oldHeight,
113
- this._peaks.options.lineHeight
114
- );
115
- positions.push(source.position);
116
- }
117
- this._removeSource(source);
118
- this._addSourceGroup(source);
119
- }
120
- }
121
-
122
- if (positions) {
123
- var frameOffset = this._view.getFrameOffset();
124
- var width = this._view.getWidth();
125
-
126
- this.updateSources(
127
- this._view.pixelsToTime(frameOffset),
128
- this._view.pixelsToTime(frameOffset + width)
129
- );
130
- }
131
- };
132
-
133
- SourcesLayer.prototype._onSourceUpdate = function(source) {
134
- var redraw = false;
135
- var sourceGroup = this._sourcesGroup[source.id];
136
- var frameOffset = this._view.getFrameOffset();
137
- var width = this._view.getWidth();
138
- var frameStartTime = this._view.pixelsToTime(frameOffset);
139
- var frameEndTime = this._view.pixelsToTime(frameOffset + width);
140
-
141
- if (sourceGroup) {
142
- this._removeSource(source);
143
- redraw = true;
144
- }
145
-
146
- if (source.isVisible(frameStartTime, frameEndTime)) {
147
- this._addSourceGroup(source);
148
- redraw = true;
149
- }
150
-
151
- if (redraw) {
152
- this.updateSources(frameStartTime, frameEndTime);
153
- }
154
- };
155
-
156
- SourcesLayer.prototype._onSourcesSetSelected = function(sources) {
157
- sources.forEach(function(source) {
158
- const sourceGroup = this._sourcesGroup[source.id];
159
-
160
- if (sourceGroup) {
161
- sourceGroup.setSelected();
162
- }
163
- }.bind(this));
164
-
165
- this.draw();
166
- };
167
-
168
- SourcesLayer.prototype._onSourcesShow = function(sources) {
169
- var self = this;
170
-
171
- sources.forEach(function(source) {
172
- self._sourcesGroup[source.id].setWrapping(false, true);
173
- });
174
-
175
- this._layer.draw();
176
- };
177
-
178
- SourcesLayer.prototype._onSourcesAdd = function(sources) {
179
- var self = this;
180
-
181
- var frameOffset = self._view.getFrameOffset();
182
- var width = self._view.getWidth();
183
-
184
- var frameStartTime = self._view.pixelsToTime(frameOffset);
185
- var frameEndTime = self._view.pixelsToTime(frameOffset + width);
186
-
187
- sources.forEach(function(source) {
188
- self._addSourceGroup(source, source.isVisible(frameStartTime, frameEndTime));
189
- });
190
-
191
- this._view.updateTimelineLength();
192
-
193
- this.updateSources(frameStartTime, frameEndTime);
194
- };
195
-
196
- SourcesLayer.prototype._onSourcesDestroy = function(sources, shouldBlockEvent) {
197
- var self = this;
198
-
199
- sources.forEach(function(source) {
200
- self._removeSource(source, true, shouldBlockEvent);
201
- });
202
-
203
- this._view.updateTimelineLength();
204
-
205
- this._layer.draw();
206
- };
207
-
208
- SourcesLayer.prototype._onSourcesShow = function(sources) {
209
- var self = this;
210
-
211
- sources.forEach(function(source) {
212
- self._sourcesGroup[source.id].setWrapping(false, true);
213
- });
214
-
215
- this._layer.draw();
216
- };
217
-
218
- SourcesLayer.prototype._onSourcesHide = function(sources) {
219
- var self = this;
220
-
221
- sources.forEach(function(source) {
222
- self._sourcesGroup[source.id].setWrapping(true, true);
223
- });
224
-
225
- this._layer.draw();
226
- };
227
-
228
- SourcesLayer.prototype._onDataRetrieved = function(data, source, url) {
229
- if (data) {
230
- var type = data.type.split('/')[0];
231
- var sourceGroup = this._sourcesGroup[source.id];
232
-
233
- if (sourceGroup) {
234
- switch (type) {
235
- case 'image':
236
- sourceGroup.addImagePreview(data.content, url, true);
237
- break;
238
- case 'video':
239
- sourceGroup.addVideoPreview(data.content, url, true);
240
- break;
241
- case 'binary':
242
- case 'text':
243
- case 'application':
244
- case 'other':
245
- case 'audio':
246
- sourceGroup.addAudioPreview(type, data.content, url, true);
247
- break;
248
- default:
249
- // Type not handled
250
- }
251
- }
252
- }
253
- };
254
-
255
- SourcesLayer.prototype._onSourcesRefresh = function() {
256
- this._layer.draw();
257
- };
258
-
259
- SourcesLayer.prototype._onSegmentsShow = function(lineId, position) {
260
- this._lines.addSegments(lineId, position);
261
- this._view.updateTimelineLength();
262
- this._layer.draw();
263
- };
264
-
265
- /**
266
- * Creates the Konva UI objects for a given source.
267
- *
268
- * @private
269
- * @param {Source} source
270
- * @returns {Kanva.Group}
271
- */
272
-
273
- SourcesLayer.prototype._createSourceGroup = function(source) {
274
- return new SourceGroup(source, this._peaks, this, this._view);
275
- };
276
-
277
- /**
278
- * Adds a Konva UI object to the layer for a given source.
279
- *
280
- * @private
281
- * @param {Source} source
282
- * @returns {Konva.Group}
283
- */
284
-
285
- SourcesLayer.prototype._addSourceGroup = function(source, startDataRetrieval = true) {
286
- var sourceGroup = this._createSourceGroup(source);
287
-
288
- this._sourcesGroup[source.id] = sourceGroup;
289
- this._lines.addSourceGroup(sourceGroup, source.position);
290
-
291
- // After creating and referencing the new group, we can start data retrieval
292
- if (startDataRetrieval) {
293
- this._dataRetriever.retrieveData(source);
294
- }
295
-
296
- return sourceGroup;
297
- };
298
-
299
- SourcesLayer.prototype.setIndicators = function(source) {
300
- var sourceGroup = this._sourcesGroup[source.id];
301
-
302
- if (sourceGroup) {
303
- sourceGroup.createIndicators();
304
- this._layer.draw();
305
- }
306
- };
307
-
308
- /**
309
- * Updates the positions of all displayed sources in the view.
310
- *
311
- * @param {Number} startTime The start of the visible range in the view,
312
- * in seconds.
313
- * @param {Number} endTime The end of the visible range in the view,
314
- * in seconds.
315
- */
316
-
317
- SourcesLayer.prototype.updateSources = function(startTime, endTime) {
318
- // Update segments
319
- this._lines.updateSegments(startTime, endTime);
320
-
321
- // Update sources in visible time range.
322
- var sources = this.findSources(startTime, endTime);
323
-
324
- // Should implement virtualization on Y
325
-
326
- var count = sources.length;
327
-
328
- sources.forEach(this._updateSource.bind(this));
329
- this._lines.setOffsetY(this._view.getFrameOffsetY());
330
-
331
- count += this._removeInvisibleSources(startTime, endTime);
332
-
333
- if (count > 0) {
334
- this._layer.draw();
335
- }
336
- };
337
-
338
- SourcesLayer.prototype.onSourcesGroupDragStart = function(element) {
339
- this._initialTimeOffset = this._view.getTimeOffset();
340
- this._mouseDownX = this._view.getPointerPosition().x;
341
- this._activeElements = {};
342
-
343
- const draggedElementId = element.currentTarget.attrs.sourceId;
344
- const shouldDragSelectedElements = Object.keys(this._view.getSelectedElements()).includes(
345
- draggedElementId
346
- );
347
-
348
- this._nonSelectedElement = shouldDragSelectedElements ?
349
- null :
350
- [this._sourcesGroup[draggedElementId].getSource()];
351
-
352
- this._isDraggable = true;
353
- (this._nonSelectedElement || Object.values(this._view.getSelectedElements())).forEach(function(source) {
354
- if (!source.draggable) {
355
- this._isDraggable = false;
356
- return;
357
- }
358
- }.bind(this));
359
- };
360
-
361
- SourcesLayer.prototype.onSourcesGroupDragEnd = function() {
362
- const updatedSources = (this._nonSelectedElement || Object.values(this._view.getSelectedElements())).map(
363
- function(source) {
364
- const sourceGroup = this._sourcesGroup[source.id];
365
-
366
- if (sourceGroup) {
367
- sourceGroup.prepareDragEnd();
368
- }
369
-
370
- return source;
371
- }.bind(this)
372
- );
373
-
374
- this._view.drawSourcesLayer();
375
- this._view.updateTimelineLength();
376
-
377
- this._activeElements = {};
378
-
379
- this._peaks.emit('sources.updated', updatedSources);
380
- };
381
-
382
- SourcesLayer.prototype.onSourcesGroupDrag = function(draggedElement) {
383
- this._view.updateWithAutoScroll(this._dragSourcesGroup.bind(this));
384
-
385
- return {
386
- x: draggedElement.absolutePosition().x,
387
- y: draggedElement.absolutePosition().y
388
- };
389
- };
390
-
391
- SourcesLayer.prototype._dragSourcesGroup = function() {
392
- var mousePos = Math.min(
393
- this._view.getWidth() - this._peaks.options.autoScrollThreshold * this._view.getWidth(),
394
- Math.max(
395
- 0,
396
- this._view.getPointerPosition().x
397
- )
398
- );
399
-
400
- const diff = this._view.pixelsToTime(mousePos - this._mouseDownX);
401
- const timeOffsetDiff = this._view.getTimeOffset() - this._initialTimeOffset;
402
- const mousePosY = this._view.getPointerPosition().y;
403
- var newEnd = 0;
404
- var shouldRedraw = false;
405
-
406
- (this._nonSelectedElement || Object.values(this._view.getSelectedElements())).forEach(function(source) {
407
- if (!this._activeElements[source.id]) {
408
- this._activeElements[source.id] = {
409
- initialStartTime: source.startTime,
410
- initialEndTime: source.endTime
411
- };
412
- }
413
-
414
- const { initialStartTime, initialEndTime } = this._activeElements[source.id];
415
-
416
- newEnd = Math.max(newEnd, source.endTime);
417
-
418
- if (this._isDraggable) {
419
- shouldRedraw = this.updateSource(
420
- source,
421
- initialStartTime + diff + timeOffsetDiff,
422
- initialEndTime + diff + timeOffsetDiff,
423
- mousePosY
424
- ) || shouldRedraw;
425
- }
426
- }.bind(this));
427
-
428
- if (shouldRedraw) {
429
- this.draw();
430
- }
431
-
432
- this._view.setTimelineLength(
433
- this._view.timeToPixels(newEnd) + this._view.getWidth()
434
- );
435
- };
436
-
437
- SourcesLayer.prototype.findSources = function(startTime, endTime) {
438
- var sources = this._peaks.sources.find(startTime, endTime);
439
- var positions = this._lines.getVisibleLines();
440
-
441
- return sources.filter(
442
- function(source) {
443
- return positions[source.position];
444
- }
445
- );
446
- };
447
-
448
- SourcesLayer.prototype.updateSource = function(source, startTime, endTime, newY) {
449
- var newTimes = {
450
- start: startTime,
451
- end: endTime
452
- };
453
-
454
- if (this._peaks.options.canMoveSourcesBetweenLines) {
455
- this.manageVerticalPosition(source, newY);
456
- }
457
-
458
- newTimes = this.manageSourceOrder(source, newTimes);
459
- newTimes = this.manageCollision(source, newTimes);
460
-
461
- source.updateTimes(
462
- newTimes.start,
463
- newTimes.end
464
- );
465
-
466
- if (newTimes) {
467
- this._updateSource(
468
- source
469
- );
470
-
471
- return true;
472
- }
473
- return false;
474
- };
475
-
476
- SourcesLayer.prototype.manageVerticalPosition = function(source, newY) {
477
- return this._lines.manageVerticalPosition(source, newY);
478
- };
479
-
480
- SourcesLayer.prototype.manageSourceOrder = function(source, newTimes) {
481
- return this._lines.manageSourceOrder(source, newTimes);
482
- };
483
-
484
- SourcesLayer.prototype.manageCollision = function(source, newTimes) {
485
- return this._lines.manageCollision(source, newTimes);
486
- };
487
-
488
- /**
489
- * @private
490
- */
491
-
492
- SourcesLayer.prototype._updateSource = function(source) {
493
- var sourceGroup = this._findOrAddSourceGroup(source);
494
-
495
- sourceGroup.update();
496
- };
497
-
498
- SourcesLayer.prototype._findOrAddSourceGroup = function(source) {
499
- var sourceGroup = this._sourcesGroup[source.id];
500
-
501
- if (!sourceGroup) {
502
- sourceGroup = this._addSourceGroup(source);
503
- }
504
-
505
- return sourceGroup;
506
- };
507
-
508
- /**
509
- * Removes any sources that are not visible, i.e., are not within and do not
510
- * overlap the given time range.
511
- *
512
- * @private
513
- * @param {Number} startTime The start of the visible time range, in seconds.
514
- * @param {Number} endTime The end of the visible time range, in seconds.
515
- * @returns {Number} The number of sources removed.
516
- */
517
-
518
- SourcesLayer.prototype._removeInvisibleSources = function(startTime, endTime) {
519
- var count = 0;
520
-
521
- for (var sourceId in this._sourcesGroup) {
522
- if (Utils.objectHasProperty(this._sourcesGroup, sourceId)) {
523
- var sourceGroup = this._sourcesGroup[sourceId];
524
-
525
- if (!sourceGroup.isActive()) {
526
- var source = this._sourcesGroup[sourceId].getSource();
527
-
528
- if (!this._isSourceVisible(source, startTime, endTime)) {
529
- this._removeSource(source);
530
- count++;
531
- }
532
- }
533
- }
534
- }
535
-
536
- return count;
537
- };
538
-
539
- SourcesLayer.prototype._isSourceVisible = function(source, startTime, endTime) {
540
- return source.isVisible(startTime, endTime) && this._lines.isLineVisible(source.position);
541
- };
542
-
543
- /**
544
- * Get all visible sources.
545
- *
546
- * @private
547
- * @returns {Array<Source>} The visible sources.
548
- */
549
-
550
- SourcesLayer.prototype._getVisibleSources = function() {
551
- var frameOffset = this._view.getFrameOffset();
552
- var width = this._view.getWidth();
553
- var frameStartTime = this._view.pixelsToTime(frameOffset);
554
- var frameEndTime = this._view.pixelsToTime(frameOffset + width);
555
-
556
- var visibleSources = [];
557
-
558
- for (var sourceId in this._sourcesGroup) {
559
- if (Utils.objectHasProperty(this._sourcesGroup, sourceId)) {
560
- var source = this._sourcesGroup[sourceId].data;
561
-
562
- if (source.isVisible(frameStartTime, frameEndTime)) {
563
- visibleSources.push(source);
564
- }
565
- }
566
- }
567
-
568
- return visibleSources;
569
- };
570
-
571
- SourcesLayer.prototype._getOverlappedSources = function() {
572
- var self = this;
573
- var sources = this._getVisibleSources();
574
-
575
- return sources.reduce(function(result, source) {
576
- sources.forEach(function(source2) {
577
- if (self._sourcesGroupOverlapped(source, source2)) {
578
- if (!result.includes(source2.id)) {
579
- result.push(source2);
580
- }
581
- }
582
- });
583
-
584
- return result;
585
- }, []);
586
- };
587
-
588
- /**
589
- * Removes the given source from the view.
590
- *
591
- * @param {Source} source
592
- */
593
-
594
- SourcesLayer.prototype._removeSource = function(source, isPermanent, shouldBlockEvent) {
595
- var sourceGroup = this._sourcesGroup[source.id];
596
-
597
- if (sourceGroup) {
598
- delete this._sourcesGroup[source.id];
599
- this._lines.removeSourceGroup(source, isPermanent);
600
- sourceGroup.destroy();
601
- }
602
-
603
- if (isPermanent && !shouldBlockEvent) {
604
- this._peaks.emit('source.destroyed', source);
605
- }
606
- };
607
-
608
- /**
609
- * Toggles visibility of the sources layer.
610
- *
611
- * @param {Boolean} visible
612
- */
613
-
614
- SourcesLayer.prototype.setVisible = function(visible) {
615
- this._layer.setVisible(visible);
616
- };
617
-
618
- SourcesLayer.prototype.draw = function() {
619
- this._layer.draw();
620
- };
621
-
622
- SourcesLayer.prototype.listening = function(bool) {
623
- this._layer.listening(bool);
624
- };
625
-
626
- SourcesLayer.prototype.stopDrag = function() {
627
- this._layer.stopDrag();
628
- };
629
-
630
- SourcesLayer.prototype.getSourceGroupById = function(sourceId) {
631
- return this._sourcesGroup[sourceId];
632
- };
633
-
634
- SourcesLayer.prototype.getSourcesOnLineAfter = function(lineId, time) {
635
- return this._lines.getSourcesOnLineAfter(lineId, time);
636
- };
637
-
638
- SourcesLayer.prototype._sourcesOverlapped = function(source1, source2) {
639
- var endsLater = (source1.startTime < source2.startTime)
640
- && (source1.endTime > source2.startTime);
641
- var startsEarlier = (source1.startTime > source2.startTime)
642
- && (source1.startTime < source2.endTime);
643
-
644
- return endsLater || startsEarlier;
645
- };
646
-
647
- SourcesLayer.prototype.rescale = function(debounce) {
648
- if (debounce) {
649
- this._debouncedRescale();
650
- }
651
- else {
652
- this._rescale();
653
- }
654
- };
655
-
656
- SourcesLayer.prototype._rescale = function() {
657
- var id, audioPreviews, urls = [], self = this;
658
-
659
- for (id in this._sourcesGroup) {
660
- if (Utils.objectHasProperty(this._sourcesGroup, id)) {
661
- audioPreviews = this._sourcesGroup[id].getAudioPreview();
662
-
663
- audioPreviews.forEach(function(audioPreview) {
664
- if (self._shouldResampleAudio(audioPreview.url, urls)) {
665
- self._loadedData[audioPreview.url + '-scaled'] = {
666
- data: self._resampleAudio(audioPreview.url),
667
- scale: self._view.getTimeToPixelsScale()
668
- };
669
-
670
- urls.push(audioPreview.url);
671
- }
672
- });
673
- }
674
- }
675
- this._layer.draw();
676
- };
677
-
678
- SourcesLayer.prototype._shouldResampleAudio = function(audioUrl, urls) {
679
- return this._loadedData[audioUrl + '-scaled']
680
- && !urls.includes(audioUrl)
681
- && this._loadedData[audioUrl + '-scaled'].scale !== this._view.getTimeToPixelsScale();
682
- };
683
-
684
- SourcesLayer.prototype._resampleAudio = function(audioUrl) {
685
- return this._loadedData[audioUrl].resample({
686
- scale: this._loadedData[audioUrl].sample_rate
687
- / this._view.getTimeToPixelsScale()
688
- });
689
- };
690
-
691
- SourcesLayer.prototype.destroy = function() {
692
- this._peaks.off('sources.add', this._onSourcesAdd);
693
- this._peaks.off('sources.destroy', this._onSourcesDestroy);
694
- this._peaks.off('sources.show', this._onSourcesShow);
695
- this._peaks.off('sources.hide', this._onSourcesHide);
696
- this._peaks.off('source.update', this._onSourceUpdate);
697
- this._peaks.off('data.retrieved', this._onDataRetrieved);
698
- this._peaks.off('sources.refresh', this._onSourcesRefresh);
699
- this._peaks.off('segments.show', this._onSegmentsShow);
700
- this._peaks.off('options.set.line_height', this._onOptionsLineHeightChange);
701
- this._peaks.off('source.setIndicators', this.setIndicators);
702
- };
703
-
704
- SourcesLayer.prototype.getHeight = function() {
705
- return this._layer.getHeight();
706
- };
707
-
708
- SourcesLayer.prototype.getFullHeight = function() {
709
- return this._lines.height();
710
- };
711
-
712
- SourcesLayer.prototype.getLength = function() {
713
- return this._lines.linesLength();
714
- };
715
-
716
- SourcesLayer.prototype.getLineByPosition = function(pos) {
717
- return this._lines.getLineByPosition(pos);
718
- };
719
-
720
- /**
721
- * Object for storing data and UI of a source.
722
- *
723
- * @typedef {Object} CompleteSource
724
- * @global
725
- * @property {Source} data
726
- * @property {Konva.Group} ui
727
- */
728
-
729
- return SourcesLayer;
730
- });
1
+ /**
2
+ * @file
3
+ *
4
+ * Defines the {@link SourcesLayer} class.
5
+ *
6
+ * @module sources-layer
7
+ */
8
+
9
+ define([
10
+ './source-group',
11
+ './line-groups',
12
+ './data-retriever',
13
+ './invoker',
14
+ '../utils',
15
+ 'konva'
16
+ ], function(
17
+ SourceGroup,
18
+ LineGroups,
19
+ DataRetriever,
20
+ Invoker,
21
+ Utils,
22
+ Konva) {
23
+ 'use strict';
24
+
25
+ /**
26
+ * Creates a Konva.Layer that displays sources on the timeline.
27
+ *
28
+ * @class
29
+ * @alias SourcesLayer
30
+ *
31
+ * @param {Peaks} peaks
32
+ * @param {WaveformOverview|WaveformZoomView} view
33
+ * @param {Boolean} allowEditing
34
+ */
35
+
36
+ function SourcesLayer(peaks, view, allowEditing) {
37
+ this._peaks = peaks;
38
+ this._view = view;
39
+ this._allowEditing = allowEditing;
40
+ this._sourcesGroup = {};
41
+ this._layer = new Konva.Layer();
42
+ this._dataRetriever = new DataRetriever(peaks);
43
+ this._lineGroups = new LineGroups(peaks, view, this);
44
+ this._lineGroups.addToLayer(this);
45
+
46
+ this._loadedData = {};
47
+
48
+ this._debouncedRescale = new Invoker().debounce(
49
+ this._rescale, 150
50
+ );
51
+
52
+ this._peaks.on('handler.sources.add', this._onSourcesAdd.bind(this));
53
+ this._peaks.on('handler.sources.destroy', this._onSourcesDestroy.bind(this));
54
+ this._peaks.on('handler.sources.show', this._onSourcesShow.bind(this));
55
+ this._peaks.on('handler.sources.hide', this._onSourcesHide.bind(this));
56
+ this._peaks.on('sources.setSelected', this._onSourcesSetSelected.bind(this));
57
+ this._peaks.on('model.source.update', this._onSourceUpdate.bind(this));
58
+ this._peaks.on('data.retrieved', this._onDataRetrieved.bind(this));
59
+ this._peaks.on('handler.segments.show', this._onSegmentsShow.bind(this));
60
+ this._peaks.on('model.source.setIndicators', this.setIndicators.bind(this));
61
+ }
62
+
63
+ SourcesLayer.prototype.fitToView = function() {
64
+ this._lineGroups.fitToView();
65
+ };
66
+
67
+ SourcesLayer.prototype.getLoadedData = function(id) {
68
+ return this._loadedData[id];
69
+ };
70
+
71
+ SourcesLayer.prototype.setLoadedData = function(id, data) {
72
+ this._loadedData[id] = data;
73
+ };
74
+
75
+ SourcesLayer.prototype.getSegmentsGroups = function() {
76
+ return this._lineGroups.getSegmentsGroups();
77
+ };
78
+
79
+ SourcesLayer.prototype.add = function(element) {
80
+ this._layer.add(element);
81
+ };
82
+
83
+ /**
84
+ * Adds the layer to the given {Konva.Stage}.
85
+ *
86
+ * @param {Konva.Stage} stage
87
+ */
88
+
89
+ SourcesLayer.prototype.addToStage = function(stage) {
90
+ stage.add(this._layer);
91
+ };
92
+
93
+ SourcesLayer.prototype.enableEditing = function(enable) {
94
+ this._allowEditing = enable;
95
+ };
96
+
97
+ SourcesLayer.prototype.isEditingEnabled = function() {
98
+ return this._allowEditing;
99
+ };
100
+
101
+ SourcesLayer.prototype.refresh = function() {
102
+ var frameOffset = this._view.getFrameOffset();
103
+ var width = this._view.getWidth();
104
+
105
+ this.updateSources(
106
+ this._view.pixelsToTime(frameOffset),
107
+ this._view.pixelsToTime(frameOffset + width)
108
+ );
109
+ };
110
+
111
+ SourcesLayer.prototype._onSourceUpdate = function(source) {
112
+ 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);
118
+
119
+ if (sourceGroup) {
120
+ this._destroySourceGroup(source);
121
+ redraw = true;
122
+ }
123
+
124
+ if (source.isVisible(frameStartTime, frameEndTime)) {
125
+ this._addSourceGroup(source);
126
+ redraw = true;
127
+ }
128
+
129
+ if (redraw) {
130
+ this.updateSources(frameStartTime, frameEndTime);
131
+ }
132
+ };
133
+
134
+ SourcesLayer.prototype._onSourcesSetSelected = function(sources) {
135
+ sources.forEach(function(source) {
136
+ const sourceGroup = this._sourcesGroup[source.id];
137
+
138
+ if (sourceGroup) {
139
+ sourceGroup.setSelected();
140
+ }
141
+ }.bind(this));
142
+
143
+ this.draw();
144
+ };
145
+
146
+ SourcesLayer.prototype._onSourcesAdd = function(sources) {
147
+ var self = this;
148
+
149
+ var frameOffset = self._view.getFrameOffset();
150
+ var width = self._view.getWidth();
151
+
152
+ var frameStartTime = self._view.pixelsToTime(frameOffset);
153
+ var frameEndTime = self._view.pixelsToTime(frameOffset + width);
154
+
155
+ sources.forEach(function(source) {
156
+ self._addSourceGroup(source, source.isVisible(frameStartTime, frameEndTime));
157
+ });
158
+
159
+ this._view.updateTimelineLength();
160
+
161
+ this.updateSources(frameStartTime, frameEndTime);
162
+ };
163
+
164
+ SourcesLayer.prototype._onSourcesDestroy = function(sources) {
165
+ var self = this;
166
+
167
+ sources.forEach(function(source) {
168
+ self._removeSource(source);
169
+ });
170
+
171
+ this._view.updateTimelineLength();
172
+
173
+ this._layer.draw();
174
+ };
175
+
176
+ SourcesLayer.prototype._onSourcesShow = function(sources) {
177
+ var self = this;
178
+
179
+ sources.forEach(function(source) {
180
+ self._sourcesGroup[source.id].setWrapping(false, true);
181
+ });
182
+
183
+ this._layer.draw();
184
+ };
185
+
186
+ SourcesLayer.prototype._onSourcesHide = function(sources) {
187
+ var self = this;
188
+
189
+ sources.forEach(function(source) {
190
+ self._sourcesGroup[source.id].setWrapping(true, true);
191
+ });
192
+
193
+ this._layer.draw();
194
+ };
195
+
196
+ SourcesLayer.prototype._onDataRetrieved = function(data, source, url) {
197
+ if (data) {
198
+ var type = data.type.split('/')[0];
199
+ var sourceGroup = this._sourcesGroup[source.id];
200
+
201
+ if (sourceGroup) {
202
+ switch (type) {
203
+ case 'image':
204
+ sourceGroup.addImagePreview(data.content, url, true);
205
+ break;
206
+ case 'video':
207
+ sourceGroup.addVideoPreview(data.content, url, true);
208
+ break;
209
+ case 'binary':
210
+ case 'text':
211
+ case 'application':
212
+ case 'other':
213
+ case 'audio':
214
+ sourceGroup.addAudioPreview(type, data.content, url, true);
215
+ break;
216
+ default:
217
+ // Type not handled
218
+ }
219
+ }
220
+ }
221
+ };
222
+
223
+ SourcesLayer.prototype._onSegmentsShow = function(segmentsGroupId, lineId) {
224
+ this._lineGroups.addSegments(segmentsGroupId, lineId);
225
+ this._view.updateTimelineLength();
226
+ this._layer.draw();
227
+ };
228
+
229
+ /**
230
+ * Creates the Konva UI objects for a given source.
231
+ *
232
+ * @private
233
+ * @param {Source} source
234
+ * @returns {Kanva.Group}
235
+ */
236
+
237
+ SourcesLayer.prototype._createSourceGroup = function(source) {
238
+ return new SourceGroup(source, this._peaks, this, this._view);
239
+ };
240
+
241
+ /**
242
+ * Adds a Konva UI object to the layer for a given source.
243
+ *
244
+ * @private
245
+ * @param {Source} source
246
+ * @returns {Konva.Group}
247
+ */
248
+
249
+ SourcesLayer.prototype._addSourceGroup = function(source, startDataRetrieval = true) {
250
+ var sourceGroup = this._createSourceGroup(source);
251
+
252
+ this._sourcesGroup[source.id] = sourceGroup;
253
+ this._lineGroups.addSource(source, sourceGroup);
254
+
255
+ // After creating and referencing the new group, we can start data retrieval
256
+ if (startDataRetrieval) {
257
+ this._dataRetriever.retrieveData(source);
258
+ }
259
+
260
+ return sourceGroup;
261
+ };
262
+
263
+ SourcesLayer.prototype.setIndicators = function(source) {
264
+ var sourceGroup = this._sourcesGroup[source.id];
265
+
266
+ if (sourceGroup) {
267
+ sourceGroup.createIndicators();
268
+ this._layer.draw();
269
+ }
270
+ };
271
+
272
+ /**
273
+ * Updates the positions of all displayed sources in the view.
274
+ *
275
+ * @param {Number} startTime The start of the visible range in the view,
276
+ * in seconds.
277
+ * @param {Number} endTime The end of the visible range in the view,
278
+ * in seconds.
279
+ */
280
+
281
+ SourcesLayer.prototype.updateSources = function(startTime, endTime) {
282
+ // Update segments
283
+ this._lineGroups.updateSegments(startTime, endTime);
284
+
285
+ // Update sources in visible time range.
286
+ var sources = this.findSources(startTime, endTime);
287
+
288
+ var count = sources.length;
289
+
290
+ sources.forEach(this._updateSource.bind(this));
291
+
292
+ count += this._removeInvisibleSources(startTime, endTime);
293
+
294
+ if (count > 0) {
295
+ this._layer.draw();
296
+ }
297
+ };
298
+
299
+ SourcesLayer.prototype.onSourcesGroupDragStart = function(element) {
300
+ this._initialTimeOffset = this._view.getTimeOffset();
301
+ this._mouseDownX = this._view.getPointerPosition().x;
302
+
303
+ const draggedElementId = element.currentTarget.attrs.sourceId;
304
+
305
+ var selectedElements = this._view.getSelectedElements();
306
+ const shouldDragSelectedElements = Object.keys(selectedElements).includes(
307
+ draggedElementId
308
+ );
309
+
310
+ if (shouldDragSelectedElements) {
311
+ this._draggedElements = Object.values(selectedElements).sort((a, b) => a.startTime - b.startTime);
312
+ }
313
+ else {
314
+ this._draggedElements = [this._sourcesGroup[draggedElementId].getSource()];
315
+ this._view.deselectAll();
316
+ }
317
+
318
+ this._draggedElementsData = this._draggedElements.reduce(function(bounds, source) {
319
+ bounds.initialStartTime = Math.min(source.startTime, bounds.initialStartTime);
320
+ bounds.initialEndTime = Math.max(source.endTime, bounds.initialEndTime);
321
+ bounds.orderable = source.orderable && bounds.orderable;
322
+ bounds.draggable = source.draggable && bounds.draggable;
323
+
324
+ return bounds;
325
+ }, {
326
+ initialStartTime: Infinity,
327
+ initialEndTime: -Infinity,
328
+ orderable: true,
329
+ draggable: true
330
+ });
331
+ };
332
+
333
+ SourcesLayer.prototype.onSourcesGroupDragEnd = function() {
334
+ const updatedSources = this._draggedElements.map(
335
+ function(source) {
336
+ const sourceGroup = this._sourcesGroup[source.id];
337
+
338
+ if (sourceGroup) {
339
+ sourceGroup.prepareDragEnd();
340
+ }
341
+
342
+ return source;
343
+ }.bind(this)
344
+ );
345
+
346
+ this._view.drawSourcesLayer();
347
+ this._view.updateTimelineLength();
348
+
349
+ this._peaks.emit('sources.updated', updatedSources);
350
+ };
351
+
352
+ SourcesLayer.prototype.onSourcesGroupDrag = function(draggedElement) {
353
+ this._view.updateWithAutoScroll(this._dragSourcesGroup.bind(this));
354
+
355
+ return {
356
+ x: draggedElement.absolutePosition().x,
357
+ y: draggedElement.absolutePosition().y
358
+ };
359
+ };
360
+
361
+ SourcesLayer.prototype._dragSourcesGroup = function() {
362
+ var mousePos = Math.min(
363
+ this._view.getWidth() - this._peaks.options.autoScrollThreshold * this._view.getWidth(),
364
+ Math.max(
365
+ 0,
366
+ this._view.getPointerPosition().x
367
+ )
368
+ );
369
+
370
+ const timeDiff = this._view.pixelsToTime(mousePos - this._mouseDownX);
371
+ const timeOffsetDiff = this._view.getTimeOffset() - this._initialTimeOffset;
372
+ const mousePosX = this._view.getPointerPosition().x;
373
+ const mousePosY = this._view.getPointerPosition().y;
374
+ const { initialStartTime, initialEndTime, orderable, draggable } = this._draggedElementsData;
375
+
376
+ if (!draggable) {
377
+ return;
378
+ }
379
+
380
+ const shouldRedraw = this.manageSourceMovements(
381
+ this._draggedElements,
382
+ initialStartTime + timeOffsetDiff + timeDiff,
383
+ initialEndTime + timeOffsetDiff + timeDiff,
384
+ orderable,
385
+ mousePosX,
386
+ mousePosY
387
+ );
388
+
389
+ if (shouldRedraw) {
390
+ this.draw();
391
+ }
392
+ };
393
+
394
+ SourcesLayer.prototype.findSources = function(startTime, endTime) {
395
+ var sources = this._peaks.sourceHandler.find(startTime, endTime);
396
+ var lineIds = this._lineGroups.getVisibleLines();
397
+
398
+ return sources.filter(
399
+ function(source) {
400
+ return lineIds[source.lineId];
401
+ }
402
+ );
403
+ };
404
+
405
+ SourcesLayer.prototype._applyTimeChangesToSources = function(sources, initialStartTime, newStartTime,
406
+ newEndTime
407
+ ) {
408
+ if (sources.length === 1) {
409
+ sources[0].updateTimes(
410
+ newStartTime,
411
+ newEndTime
412
+ );
413
+ }
414
+ else {
415
+ // We cannot have more than 1 source being resized at a time
416
+ // Reaching this point implies that that we are only dragging, not resizing
417
+ // So, we can safely assume that the difference between the initial times and the new times is the same
418
+ const timeDiff = Utils.roundTime(newStartTime - initialStartTime);
419
+
420
+ if (timeDiff !== 0) {
421
+ sources.forEach(function(source) {
422
+ source.updateTimes(
423
+ Utils.roundTime(source.startTime + timeDiff),
424
+ Utils.roundTime(source.endTime + timeDiff)
425
+ );
426
+ });
427
+ }
428
+ }
429
+
430
+ this.refresh();
431
+ };
432
+
433
+ // TODO: This assumes that no sources between the start and the end are unselected
434
+ SourcesLayer.prototype.manageSourceMovements = function(sources, newStartTime, newEndTime, orderable, mouseX,
435
+ mouseY
436
+ ) {
437
+ newStartTime = typeof newStartTime === 'number' ? Utils.roundTime(newStartTime) : newStartTime;
438
+ newEndTime = typeof newEndTime === 'number' ? Utils.roundTime(newEndTime) : newEndTime;
439
+
440
+ if (this._peaks.options.canMoveSourcesBetweenLines && typeof mouseY === 'number') {
441
+ this.manageVerticalPosition(sources, newStartTime, newEndTime, mouseX, mouseY);
442
+ }
443
+
444
+ if (orderable) {
445
+ ({ newStartTime, newEndTime } = this.manageOrder(sources, newStartTime, newEndTime));
446
+ }
447
+ ({ newStartTime, newEndTime } = this.manageCollision(sources, newStartTime, newEndTime));
448
+
449
+ this._applyTimeChangesToSources(sources, sources[0].startTime, newStartTime, newEndTime);
450
+
451
+ this._view.setTimelineLength(
452
+ this._view.timeToPixels(sources[sources.length - 1].endTime) + this._view.getWidth()
453
+ );
454
+
455
+ return true;
456
+ };
457
+
458
+ SourcesLayer.prototype.manageVerticalPosition = function(sources, startTime, endTime, mouseX, mouseY) {
459
+ return this._lineGroups.manageVerticalPosition(sources, startTime, endTime, mouseX, mouseY);
460
+ };
461
+
462
+ SourcesLayer.prototype.manageOrder = function(sources, startTime, endTime) {
463
+ return this._lineGroups.manageOrder(sources, startTime, endTime);
464
+ };
465
+
466
+ SourcesLayer.prototype.manageCollision = function(sources, newStartTime, newEndTime) {
467
+ return this._lineGroups.manageCollision(sources, newStartTime, newEndTime);
468
+ };
469
+
470
+ /**
471
+ * @private
472
+ */
473
+
474
+ SourcesLayer.prototype._updateSource = function(source) {
475
+ var sourceGroup = this._findOrAddSourceGroup(source);
476
+
477
+ sourceGroup.update();
478
+ };
479
+
480
+ SourcesLayer.prototype._findOrAddSourceGroup = function(source) {
481
+ var sourceGroup = this._sourcesGroup[source.id];
482
+
483
+ if (!sourceGroup) {
484
+ sourceGroup = this._addSourceGroup(source);
485
+ }
486
+
487
+ return sourceGroup;
488
+ };
489
+
490
+ /**
491
+ * Removes any sources that are not visible, i.e., are not within and do not
492
+ * overlap the given time range.
493
+ *
494
+ * @private
495
+ * @param {Number} startTime The start of the visible time range, in seconds.
496
+ * @param {Number} endTime The end of the visible time range, in seconds.
497
+ * @returns {Number} The number of sources removed.
498
+ */
499
+
500
+ SourcesLayer.prototype._removeInvisibleSources = function(startTime, endTime) {
501
+ var count = 0;
502
+
503
+ for (var sourceId in this._sourcesGroup) {
504
+ if (Utils.objectHasProperty(this._sourcesGroup, sourceId)) {
505
+ var sourceGroup = this._sourcesGroup[sourceId];
506
+
507
+ if (!sourceGroup.isActive()) {
508
+ var source = this._sourcesGroup[sourceId].getSource();
509
+
510
+ if (!this._isSourceVisible(source, startTime, endTime)) {
511
+ this._destroySourceGroup(source);
512
+ count++;
513
+ }
514
+ }
515
+ }
516
+ }
517
+
518
+ return count;
519
+ };
520
+
521
+ SourcesLayer.prototype._isSourceVisible = function(source, startTime, endTime) {
522
+ return source.isVisible(startTime, endTime) && this._lineGroups.isLineVisible(source.lineId);
523
+ };
524
+
525
+ /**
526
+ * Get all visible sources.
527
+ *
528
+ * @private
529
+ * @returns {Array<Source>} The visible sources.
530
+ */
531
+
532
+ SourcesLayer.prototype._getVisibleSources = function() {
533
+ var frameOffset = this._view.getFrameOffset();
534
+ var width = this._view.getWidth();
535
+ var frameStartTime = this._view.pixelsToTime(frameOffset);
536
+ var frameEndTime = this._view.pixelsToTime(frameOffset + width);
537
+
538
+ var visibleSources = [];
539
+
540
+ for (var sourceId in this._sourcesGroup) {
541
+ if (Utils.objectHasProperty(this._sourcesGroup, sourceId)) {
542
+ var source = this._sourcesGroup[sourceId].data;
543
+
544
+ if (source.isVisible(frameStartTime, frameEndTime)) {
545
+ visibleSources.push(source);
546
+ }
547
+ }
548
+ }
549
+
550
+ return visibleSources;
551
+ };
552
+
553
+ SourcesLayer.prototype._getOverlappedSources = function() {
554
+ var self = this;
555
+ var sources = this._getVisibleSources();
556
+
557
+ return sources.reduce(function(result, source) {
558
+ sources.forEach(function(source2) {
559
+ if (self._sourcesGroupOverlapped(source, source2)) {
560
+ if (!result.includes(source2.id)) {
561
+ result.push(source2);
562
+ }
563
+ }
564
+ });
565
+
566
+ return result;
567
+ }, []);
568
+ };
569
+
570
+ /**
571
+ * Removes the given source from the view.
572
+ *
573
+ * @param {Source} source
574
+ */
575
+
576
+ SourcesLayer.prototype._removeSource = function(source) {
577
+ const sourceGroup = this._sourcesGroup[source.id];
578
+
579
+ if (sourceGroup) {
580
+ delete this._sourcesGroup[source.id];
581
+ this._lineGroups.removeSource(source);
582
+ sourceGroup.destroy();
583
+ }
584
+ };
585
+
586
+ SourcesLayer.prototype._destroySourceGroup = function(source) {
587
+ const sourceGroup = this._sourcesGroup[source.id];
588
+
589
+ if (sourceGroup) {
590
+ delete this._sourcesGroup[source.id];
591
+ this._lineGroups.removeSourceGroup(source);
592
+ sourceGroup.destroy();
593
+ }
594
+ };
595
+
596
+ /**
597
+ * Toggles visibility of the sources layer.
598
+ *
599
+ * @param {Boolean} visible
600
+ */
601
+
602
+ SourcesLayer.prototype.setVisible = function(visible) {
603
+ this._layer.setVisible(visible);
604
+ };
605
+
606
+ SourcesLayer.prototype.draw = function() {
607
+ this._layer.draw();
608
+ };
609
+
610
+ SourcesLayer.prototype.listening = function(bool) {
611
+ this._layer.listening(bool);
612
+ };
613
+
614
+ SourcesLayer.prototype.stopDrag = function() {
615
+ this._layer.stopDrag();
616
+ };
617
+
618
+ SourcesLayer.prototype.getSourceGroupById = function(sourceId) {
619
+ return this._sourcesGroup[sourceId];
620
+ };
621
+
622
+ SourcesLayer.prototype.getSourcesOnLineAfter = function(lineId, time) {
623
+ return this._lineGroups.getSourcesOnLineAfter(lineId, time);
624
+ };
625
+
626
+ SourcesLayer.prototype._sourcesOverlapped = function(source1, source2) {
627
+ var endsLater = (source1.startTime < source2.startTime)
628
+ && (source1.endTime > source2.startTime);
629
+ var startsEarlier = (source1.startTime > source2.startTime)
630
+ && (source1.startTime < source2.endTime);
631
+
632
+ return endsLater || startsEarlier;
633
+ };
634
+
635
+ SourcesLayer.prototype.rescale = function(debounce) {
636
+ if (debounce) {
637
+ this._debouncedRescale();
638
+ }
639
+ else {
640
+ this._rescale();
641
+ }
642
+ };
643
+
644
+ SourcesLayer.prototype._rescale = function() {
645
+ var id, audioPreviews, urls = [], self = this;
646
+
647
+ for (id in this._sourcesGroup) {
648
+ if (Utils.objectHasProperty(this._sourcesGroup, id)) {
649
+ audioPreviews = this._sourcesGroup[id].getAudioPreview();
650
+
651
+ audioPreviews.forEach(function(audioPreview) {
652
+ if (self._shouldResampleAudio(audioPreview.url, urls)) {
653
+ self._loadedData[audioPreview.url + '-scaled'] = {
654
+ data: self._resampleAudio(audioPreview.url),
655
+ scale: self._view.getTimeToPixelsScale()
656
+ };
657
+
658
+ urls.push(audioPreview.url);
659
+ }
660
+ });
661
+ }
662
+ }
663
+ this._layer.draw();
664
+ };
665
+
666
+ SourcesLayer.prototype._shouldResampleAudio = function(audioUrl, urls) {
667
+ return this._loadedData[audioUrl + '-scaled']
668
+ && !urls.includes(audioUrl)
669
+ && this._loadedData[audioUrl + '-scaled'].scale !== this._view.getTimeToPixelsScale();
670
+ };
671
+
672
+ SourcesLayer.prototype._resampleAudio = function(audioUrl) {
673
+ return this._loadedData[audioUrl].resample({
674
+ scale: this._loadedData[audioUrl].sample_rate
675
+ / this._view.getTimeToPixelsScale()
676
+ });
677
+ };
678
+
679
+ SourcesLayer.prototype.destroy = function() {
680
+ this._peaks.off('handler.sources.add', this._onSourcesAdd);
681
+ this._peaks.off('handler.sources.destroy', this._onSourcesDestroy);
682
+ this._peaks.off('handler.sources.show', this._onSourcesShow);
683
+ this._peaks.off('handler.sources.hide', this._onSourcesHide);
684
+ this._peaks.off('model.source.update', this._onSourceUpdate);
685
+ this._peaks.off('data.retrieved', this._onDataRetrieved);
686
+ this._peaks.off('handler.segments.show', this._onSegmentsShow);
687
+ this._peaks.off('model.source.setIndicators', this.setIndicators);
688
+ };
689
+
690
+ SourcesLayer.prototype.getHeight = function() {
691
+ return this._layer.getHeight();
692
+ };
693
+
694
+ SourcesLayer.prototype.getFullHeight = function() {
695
+ return this._lineGroups.height();
696
+ };
697
+
698
+ SourcesLayer.prototype.getLength = function() {
699
+ return this._lineGroups.linesLength();
700
+ };
701
+
702
+ SourcesLayer.prototype.getLineByPosition = function(pos) {
703
+ return this._lineGroups.getLineByPosition(pos);
704
+ };
705
+
706
+ /**
707
+ * Object for storing data and UI of a source.
708
+ *
709
+ * @typedef {Object} CompleteSource
710
+ * @global
711
+ * @property {Source} data
712
+ * @property {Konva.Group} ui
713
+ */
714
+
715
+ return SourcesLayer;
716
+ });