@checksub_team/peaks_timeline 1.16.1 → 2.0.0-alpha.10

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