@checksub_team/peaks_timeline 1.4.40 → 1.4.41

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.
@@ -1,592 +1,592 @@
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('source.update', this._onSourceUpdate.bind(this));
57
- this._peaks.on('data.retrieved', this._onDataRetrieved.bind(this));
58
- this._peaks.on('sources.refresh', this._onSourcesRefresh.bind(this));
59
- this._peaks.on('segments.show', this._onSegmentsShow.bind(this));
60
- this._peaks.on('options.set.line_height', this._onOptionsLineHeightChange.bind(this));
61
- }
62
-
63
- SourcesLayer.prototype.getLoadedData = function(id) {
64
- return this._loadedData[id];
65
- };
66
-
67
- SourcesLayer.prototype.setLoadedData = function(id, data) {
68
- this._loadedData[id] = data;
69
- };
70
-
71
- SourcesLayer.prototype.getSegmentsGroups = function() {
72
- return this._lines.getSegmentsGroups();
73
- };
74
-
75
- SourcesLayer.prototype.add = function(element) {
76
- this._layer.add(element);
77
- };
78
-
79
- /**
80
- * Adds the layer to the given {Konva.Stage}.
81
- *
82
- * @param {Konva.Stage} stage
83
- */
84
-
85
- SourcesLayer.prototype.addToStage = function(stage) {
86
- stage.add(this._layer);
87
- };
88
-
89
- SourcesLayer.prototype.enableEditing = function(enable) {
90
- this._allowEditing = enable;
91
- };
92
-
93
- SourcesLayer.prototype.isEditingEnabled = function() {
94
- return this._allowEditing;
95
- };
96
-
97
- SourcesLayer.prototype._onOptionsLineHeightChange = function(oldHeight) {
98
- var positions = [];
99
-
100
- for (var sourceId in this._sourcesGroup) {
101
- if (Utils.objectHasProperty(this._sourcesGroup, sourceId)) {
102
- var source = this._sourcesGroup[sourceId].getSource();
103
-
104
- if (!positions.includes(source.position)) {
105
- this._lines.changeLineHeight(
106
- oldHeight,
107
- this._peaks.options.lineHeight
108
- );
109
- positions.push(source.position);
110
- }
111
- this._removeSource(source);
112
- this._addSourceGroup(source);
113
- }
114
- }
115
-
116
- if (positions) {
117
- var frameOffset = this._view.getFrameOffset();
118
- var width = this._view.getWidth();
119
-
120
- this.updateSources(
121
- this._view.pixelsToTime(frameOffset),
122
- this._view.pixelsToTime(frameOffset + width)
123
- );
124
- }
125
- };
126
-
127
- SourcesLayer.prototype._onSourceUpdate = function(source) {
128
- var redraw = false;
129
- var sourceGroup = this._sourcesGroup[source.id];
130
- var frameOffset = this._view.getFrameOffset();
131
- var width = this._view.getWidth();
132
- var frameStartTime = this._view.pixelsToTime(frameOffset);
133
- var frameEndTime = this._view.pixelsToTime(frameOffset + width);
134
-
135
- if (sourceGroup) {
136
- this._removeSource(source);
137
- redraw = true;
138
- }
139
-
140
- if (source.isVisible(frameStartTime, frameEndTime)) {
141
- this._addSourceGroup(source);
142
- redraw = true;
143
- }
144
-
145
- if (redraw) {
146
- this.updateSources(frameStartTime, frameEndTime);
147
- }
148
- };
149
-
150
- SourcesLayer.prototype._onSourcesShow = function(sources) {
151
- var self = this;
152
-
153
- sources.forEach(function(source) {
154
- self._sourcesGroup[source.id].unwrap(true);
155
- });
156
-
157
- this._layer.draw();
158
- };
159
-
160
- SourcesLayer.prototype._onSourcesAdd = function(sources) {
161
- var self = this;
162
-
163
- var frameOffset = self._view.getFrameOffset();
164
- var width = self._view.getWidth();
165
-
166
- var frameStartTime = self._view.pixelsToTime(frameOffset);
167
- var frameEndTime = self._view.pixelsToTime(frameOffset + width);
168
-
169
- sources.forEach(function(source) {
170
- self._addSourceGroup(source);
171
- });
172
-
173
- this._view.updateTimelineLength();
174
-
175
- this.updateSources(frameStartTime, frameEndTime);
176
- };
177
-
178
- SourcesLayer.prototype._onSourcesDestroy = function(sources) {
179
- var self = this;
180
-
181
- sources.forEach(function(source) {
182
- self._removeSource(source, true);
183
- });
184
-
185
- this._view.updateTimelineLength();
186
-
187
- this._layer.draw();
188
- };
189
-
190
- SourcesLayer.prototype._onSourcesShow = function(sources) {
191
- var self = this;
192
-
193
- sources.forEach(function(source) {
194
- self._sourcesGroup[source.id].unwrap(true);
195
- });
196
-
197
- this._layer.draw();
198
- };
199
-
200
- SourcesLayer.prototype._onSourcesHide = function(sources) {
201
- var self = this;
202
-
203
- sources.forEach(function(source) {
204
- self._sourcesGroup[source.id].wrap(true);
205
- });
206
-
207
- this._layer.draw();
208
- };
209
-
210
- SourcesLayer.prototype._onDataRetrieved = function(data, source, url) {
211
- if (data) {
212
- var type = data.type.split('/')[0];
213
- var sourceGroup = this._sourcesGroup[source.id];
214
-
215
- if (sourceGroup) {
216
- switch (type) {
217
- case 'image':
218
- sourceGroup.addImagePreview(data.content, url, true);
219
- break;
220
- case 'video':
221
- sourceGroup.addVideoPreview(data.content, url, true);
222
- break;
223
- case 'binary':
224
- case 'text':
225
- case 'application':
226
- case 'other':
227
- case 'audio':
228
- sourceGroup.addAudioPreview(type, data.content, url, true);
229
- break;
230
- default:
231
- // Type not handled
232
- }
233
- }
234
- }
235
- };
236
-
237
- SourcesLayer.prototype._onSourcesRefresh = function() {
238
- this._layer.draw();
239
- };
240
-
241
- SourcesLayer.prototype._onSegmentsShow = function(lineId, position) {
242
- this._lines.addSegments(lineId, position);
243
- this._view.updateTimelineLength();
244
- this._layer.draw();
245
- };
246
-
247
- /**
248
- * Creates the Konva UI objects for a given source.
249
- *
250
- * @private
251
- * @param {Source} source
252
- * @returns {Kanva.Group}
253
- */
254
-
255
- SourcesLayer.prototype._createSourceGroup = function(source) {
256
- return new SourceGroup(source, this._peaks, this, this._view);
257
- };
258
-
259
- /**
260
- * Adds a Konva UI object to the layer for a given source.
261
- *
262
- * @private
263
- * @param {Source} source
264
- * @returns {Konva.Group}
265
- */
266
-
267
- SourcesLayer.prototype._addSourceGroup = function(source) {
268
- var sourceGroup = this._createSourceGroup(source);
269
-
270
- this._sourcesGroup[source.id] = sourceGroup;
271
- this._lines.addSourceGroup(sourceGroup, source.position);
272
-
273
- // After creating and referencing the new group, we can start data retrieval
274
- this._dataRetriever.retrieveData(source);
275
-
276
- return sourceGroup;
277
- };
278
-
279
- /**
280
- * Updates the positions of all displayed sources in the view.
281
- *
282
- * @param {Number} startTime The start of the visible range in the view,
283
- * in seconds.
284
- * @param {Number} endTime The end of the visible range in the view,
285
- * in seconds.
286
- */
287
-
288
- SourcesLayer.prototype.updateSources = function(startTime, endTime) {
289
- // Update segments
290
- this._lines.updateSegments(startTime, endTime);
291
-
292
- // Update sources in visible time range.
293
- var sources = this.findSources(startTime, endTime);
294
-
295
- // Should implement virtualization on Y
296
-
297
- var count = sources.length;
298
-
299
- sources.forEach(this._updateSource.bind(this));
300
- this._lines.setOffsetY(this._view.getFrameOffsetY());
301
-
302
- count += this._removeInvisibleSources(startTime, endTime);
303
-
304
- if (count > 0) {
305
- this._layer.draw();
306
- }
307
- };
308
-
309
- SourcesLayer.prototype.findSources = function(startTime, endTime) {
310
- var sources = this._peaks.sources.find(startTime, endTime);
311
- var positions = this._lines.getVisibleLines();
312
-
313
- return sources.filter(
314
- function(source) {
315
- return positions[source.position];
316
- }
317
- );
318
- };
319
-
320
- SourcesLayer.prototype.updateSource = function(source, newStartX, newEndX, newY) {
321
- var newXs = {
322
- startX: newStartX,
323
- endX: newEndX,
324
- updateWidth: false
325
- };
326
-
327
- if (this._peaks.options.canMoveSourcesBetweenLines) {
328
- this.manageVerticalPosition(source, newY);
329
- }
330
-
331
- newXs = this.manageSourceOrder(source, newStartX, newEndX);
332
-
333
- newXs = this.manageCollision(source, newXs.startX, newXs.endX);
334
-
335
- source.updateTimes(
336
- newXs.startX !== null ? this._view.pixelsToTime(newXs.startX) : null,
337
- newXs.endX !== null ? this._view.pixelsToTime(newXs.endX) : null
338
- );
339
-
340
- if (newXs) {
341
- this._updateSource(
342
- source,
343
- newXs.updateWidth
344
- );
345
-
346
- this.draw();
347
- }
348
- };
349
-
350
- SourcesLayer.prototype.manageVerticalPosition = function(source, newY) {
351
- return this._lines.manageVerticalPosition(source, newY);
352
- };
353
-
354
- SourcesLayer.prototype.manageSourceOrder = function(source, newStartX, newEndX) {
355
- return this._lines.manageSourceOrder(source, newStartX, newEndX);
356
- };
357
-
358
- SourcesLayer.prototype.manageCollision = function(source, newStartX, newEndX) {
359
- return this._lines.manageCollision(source, newStartX, newEndX);
360
- };
361
-
362
- /**
363
- * @private
364
- */
365
-
366
- SourcesLayer.prototype._updateSource = function(source) {
367
- var sourceGroup = this._findOrAddSourceGroup(source);
368
-
369
- sourceGroup.update();
370
- };
371
-
372
- SourcesLayer.prototype._findOrAddSourceGroup = function(source) {
373
- var sourceGroup = this._sourcesGroup[source.id];
374
-
375
- if (!sourceGroup) {
376
- sourceGroup = this._addSourceGroup(source);
377
- }
378
-
379
- return sourceGroup;
380
- };
381
-
382
- /**
383
- * Removes any sources that are not visible, i.e., are not within and do not
384
- * overlap the given time range.
385
- *
386
- * @private
387
- * @param {Number} startTime The start of the visible time range, in seconds.
388
- * @param {Number} endTime The end of the visible time range, in seconds.
389
- * @returns {Number} The number of sources removed.
390
- */
391
-
392
- SourcesLayer.prototype._removeInvisibleSources = function(startTime, endTime) {
393
- var count = 0;
394
-
395
- for (var sourceId in this._sourcesGroup) {
396
- if (Utils.objectHasProperty(this._sourcesGroup, sourceId)) {
397
- var source = this._sourcesGroup[sourceId].getSource();
398
-
399
- if (!this._isSourceVisible(source, startTime, endTime)
400
- && !this._sourcesGroup[sourceId].isDragged()) {
401
- this._removeSource(source);
402
- count++;
403
- }
404
- }
405
- }
406
-
407
- return count;
408
- };
409
-
410
- SourcesLayer.prototype._isSourceVisible = function(source, startTime, endTime) {
411
- return source.isVisible(startTime, endTime) && this._lines.isLineVisible(source.position);
412
- };
413
-
414
- /**
415
- * Get all visible sources.
416
- *
417
- * @private
418
- * @returns {Array<Source>} The visible sources.
419
- */
420
-
421
- SourcesLayer.prototype._getVisibleSources = function() {
422
- var frameOffset = this._view.getFrameOffset();
423
- var width = this._view.getWidth();
424
- var frameStartTime = this._view.pixelsToTime(frameOffset);
425
- var frameEndTime = this._view.pixelsToTime(frameOffset + width);
426
-
427
- var visibleSources = [];
428
-
429
- for (var sourceId in this._sourcesGroup) {
430
- if (Utils.objectHasProperty(this._sourcesGroup, sourceId)) {
431
- var source = this._sourcesGroup[sourceId].data;
432
-
433
- if (source.isVisible(frameStartTime, frameEndTime)) {
434
- visibleSources.push(source);
435
- }
436
- }
437
- }
438
-
439
- return visibleSources;
440
- };
441
-
442
- SourcesLayer.prototype._getOverlappedSources = function() {
443
- var self = this;
444
- var sources = this._getVisibleSources();
445
-
446
- return sources.reduce(function(result, source) {
447
- sources.forEach(function(source2) {
448
- if (self._sourcesGroupOverlapped(source, source2)) {
449
- if (!result.includes(source2.id)) {
450
- result.push(source2);
451
- }
452
- }
453
- });
454
-
455
- return result;
456
- }, []);
457
- };
458
-
459
- /**
460
- * Removes the given source from the view.
461
- *
462
- * @param {Source} source
463
- */
464
-
465
- SourcesLayer.prototype._removeSource = function(source, isPermanent) {
466
- var sourceGroup = this._sourcesGroup[source.id];
467
-
468
- if (sourceGroup) {
469
- delete this._sourcesGroup[source.id];
470
- this._lines.removeSourceGroup(source, isPermanent);
471
- sourceGroup.destroy();
472
- }
473
-
474
- if (isPermanent) {
475
- this._peaks.emit('source.destroyed', source);
476
- }
477
- };
478
-
479
- /**
480
- * Toggles visibility of the sources layer.
481
- *
482
- * @param {Boolean} visible
483
- */
484
-
485
- SourcesLayer.prototype.setVisible = function(visible) {
486
- this._layer.setVisible(visible);
487
- };
488
-
489
- SourcesLayer.prototype.draw = function() {
490
- this._layer.draw();
491
- };
492
-
493
- SourcesLayer.prototype.listening = function(bool) {
494
- this._layer.listening(bool);
495
- };
496
-
497
- SourcesLayer.prototype.stopDrag = function() {
498
- this._layer.stopDrag();
499
- };
500
-
501
- SourcesLayer.prototype.getSourceGroupById = function(sourceId) {
502
- return this._sourcesGroup[sourceId];
503
- };
504
-
505
- SourcesLayer.prototype._sourcesOverlapped = function(source1, source2) {
506
- var endsLater = (source1.startTime < source2.startTime)
507
- && (source1.endTime > source2.startTime);
508
- var startsEarlier = (source1.startTime > source2.startTime)
509
- && (source1.startTime < source2.endTime);
510
-
511
- return endsLater || startsEarlier;
512
- };
513
-
514
- SourcesLayer.prototype.rescale = function(debounce) {
515
- // this._lines.rescale();
516
- if (debounce) {
517
- this._debouncedRescale();
518
- }
519
- else {
520
- this._rescale();
521
- }
522
- };
523
-
524
- SourcesLayer.prototype._rescale = function() {
525
- var id, audioPreviews, urls = [], self = this;
526
-
527
- for (id in this._sourcesGroup) {
528
- if (Utils.objectHasProperty(this._sourcesGroup, id)) {
529
- audioPreviews = this._sourcesGroup[id].getAudioPreview();
530
-
531
- audioPreviews.forEach(function(audioPreview) {
532
- if (self._shouldResampleAudio(audioPreview.url, urls)) {
533
- self._loadedData[audioPreview.url + '-scaled'] = {
534
- data: self._resampleAudio(audioPreview.url),
535
- scale: self._view.getTimeToPixelsScale()
536
- };
537
-
538
- urls.push(audioPreview.url);
539
- }
540
- });
541
- }
542
- }
543
- this._layer.draw();
544
- };
545
-
546
- SourcesLayer.prototype._shouldResampleAudio = function(audioUrl, urls) {
547
- return this._loadedData[audioUrl + '-scaled']
548
- && !urls.includes(audioUrl)
549
- && this._loadedData[audioUrl + '-scaled'].scale !== this._view.getTimeToPixelsScale();
550
- };
551
-
552
- SourcesLayer.prototype._resampleAudio = function(audioUrl) {
553
- return this._loadedData[audioUrl].resample({
554
- scale: this._loadedData[audioUrl].sample_rate
555
- / this._view.getTimeToPixelsScale()
556
- });
557
- };
558
-
559
- SourcesLayer.prototype.destroy = function() {
560
- this._peaks.off('sources.add', this._onSourcesAdd);
561
- this._peaks.off('sources.destroy', this._onSourcesDestroy);
562
- this._peaks.off('sources.show', this._onSourcesShow);
563
- this._peaks.off('sources.hide', this._onSourcesHide);
564
- this._peaks.off('source.wrappingChanged', this._onSourceWrappingChanged);
565
- this._peaks.off('data.retrieved', this._onDataRetrieved);
566
- this._peaks.off('sources.refresh', this._onSourcesRefresh);
567
- this._peaks.off('segments.show', this._onSegmentsShow);
568
- };
569
-
570
- SourcesLayer.prototype.getHeight = function() {
571
- return this._layer.getHeight();
572
- };
573
-
574
- SourcesLayer.prototype.getLength = function() {
575
- return this._lines.linesLength();
576
- };
577
-
578
- SourcesLayer.prototype.getLineByPosition = function(pos) {
579
- return this._lines.getLineByPosition(pos);
580
- };
581
-
582
- /**
583
- * Object for storing data and UI of a source.
584
- *
585
- * @typedef {Object} CompleteSource
586
- * @global
587
- * @property {Source} data
588
- * @property {Konva.Group} ui
589
- */
590
-
591
- return SourcesLayer;
592
- });
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('source.update', this._onSourceUpdate.bind(this));
57
+ this._peaks.on('data.retrieved', this._onDataRetrieved.bind(this));
58
+ this._peaks.on('sources.refresh', this._onSourcesRefresh.bind(this));
59
+ this._peaks.on('segments.show', this._onSegmentsShow.bind(this));
60
+ this._peaks.on('options.set.line_height', this._onOptionsLineHeightChange.bind(this));
61
+ }
62
+
63
+ SourcesLayer.prototype.getLoadedData = function(id) {
64
+ return this._loadedData[id];
65
+ };
66
+
67
+ SourcesLayer.prototype.setLoadedData = function(id, data) {
68
+ this._loadedData[id] = data;
69
+ };
70
+
71
+ SourcesLayer.prototype.getSegmentsGroups = function() {
72
+ return this._lines.getSegmentsGroups();
73
+ };
74
+
75
+ SourcesLayer.prototype.add = function(element) {
76
+ this._layer.add(element);
77
+ };
78
+
79
+ /**
80
+ * Adds the layer to the given {Konva.Stage}.
81
+ *
82
+ * @param {Konva.Stage} stage
83
+ */
84
+
85
+ SourcesLayer.prototype.addToStage = function(stage) {
86
+ stage.add(this._layer);
87
+ };
88
+
89
+ SourcesLayer.prototype.enableEditing = function(enable) {
90
+ this._allowEditing = enable;
91
+ };
92
+
93
+ SourcesLayer.prototype.isEditingEnabled = function() {
94
+ return this._allowEditing;
95
+ };
96
+
97
+ SourcesLayer.prototype._onOptionsLineHeightChange = function(oldHeight) {
98
+ var positions = [];
99
+
100
+ for (var sourceId in this._sourcesGroup) {
101
+ if (Utils.objectHasProperty(this._sourcesGroup, sourceId)) {
102
+ var source = this._sourcesGroup[sourceId].getSource();
103
+
104
+ if (!positions.includes(source.position)) {
105
+ this._lines.changeLineHeight(
106
+ oldHeight,
107
+ this._peaks.options.lineHeight
108
+ );
109
+ positions.push(source.position);
110
+ }
111
+ this._removeSource(source);
112
+ this._addSourceGroup(source);
113
+ }
114
+ }
115
+
116
+ if (positions) {
117
+ var frameOffset = this._view.getFrameOffset();
118
+ var width = this._view.getWidth();
119
+
120
+ this.updateSources(
121
+ this._view.pixelsToTime(frameOffset),
122
+ this._view.pixelsToTime(frameOffset + width)
123
+ );
124
+ }
125
+ };
126
+
127
+ SourcesLayer.prototype._onSourceUpdate = function(source) {
128
+ var redraw = false;
129
+ var sourceGroup = this._sourcesGroup[source.id];
130
+ var frameOffset = this._view.getFrameOffset();
131
+ var width = this._view.getWidth();
132
+ var frameStartTime = this._view.pixelsToTime(frameOffset);
133
+ var frameEndTime = this._view.pixelsToTime(frameOffset + width);
134
+
135
+ if (sourceGroup) {
136
+ this._removeSource(source);
137
+ redraw = true;
138
+ }
139
+
140
+ if (source.isVisible(frameStartTime, frameEndTime)) {
141
+ this._addSourceGroup(source);
142
+ redraw = true;
143
+ }
144
+
145
+ if (redraw) {
146
+ this.updateSources(frameStartTime, frameEndTime);
147
+ }
148
+ };
149
+
150
+ SourcesLayer.prototype._onSourcesShow = function(sources) {
151
+ var self = this;
152
+
153
+ sources.forEach(function(source) {
154
+ self._sourcesGroup[source.id].unwrap(true);
155
+ });
156
+
157
+ this._layer.draw();
158
+ };
159
+
160
+ SourcesLayer.prototype._onSourcesAdd = function(sources) {
161
+ var self = this;
162
+
163
+ var frameOffset = self._view.getFrameOffset();
164
+ var width = self._view.getWidth();
165
+
166
+ var frameStartTime = self._view.pixelsToTime(frameOffset);
167
+ var frameEndTime = self._view.pixelsToTime(frameOffset + width);
168
+
169
+ sources.forEach(function(source) {
170
+ self._addSourceGroup(source);
171
+ });
172
+
173
+ this._view.updateTimelineLength();
174
+
175
+ this.updateSources(frameStartTime, frameEndTime);
176
+ };
177
+
178
+ SourcesLayer.prototype._onSourcesDestroy = function(sources, shouldBlockEvent) {
179
+ var self = this;
180
+
181
+ sources.forEach(function(source) {
182
+ self._removeSource(source, true, shouldBlockEvent);
183
+ });
184
+
185
+ this._view.updateTimelineLength();
186
+
187
+ this._layer.draw();
188
+ };
189
+
190
+ SourcesLayer.prototype._onSourcesShow = function(sources) {
191
+ var self = this;
192
+
193
+ sources.forEach(function(source) {
194
+ self._sourcesGroup[source.id].unwrap(true);
195
+ });
196
+
197
+ this._layer.draw();
198
+ };
199
+
200
+ SourcesLayer.prototype._onSourcesHide = function(sources) {
201
+ var self = this;
202
+
203
+ sources.forEach(function(source) {
204
+ self._sourcesGroup[source.id].wrap(true);
205
+ });
206
+
207
+ this._layer.draw();
208
+ };
209
+
210
+ SourcesLayer.prototype._onDataRetrieved = function(data, source, url) {
211
+ if (data) {
212
+ var type = data.type.split('/')[0];
213
+ var sourceGroup = this._sourcesGroup[source.id];
214
+
215
+ if (sourceGroup) {
216
+ switch (type) {
217
+ case 'image':
218
+ sourceGroup.addImagePreview(data.content, url, true);
219
+ break;
220
+ case 'video':
221
+ sourceGroup.addVideoPreview(data.content, url, true);
222
+ break;
223
+ case 'binary':
224
+ case 'text':
225
+ case 'application':
226
+ case 'other':
227
+ case 'audio':
228
+ sourceGroup.addAudioPreview(type, data.content, url, true);
229
+ break;
230
+ default:
231
+ // Type not handled
232
+ }
233
+ }
234
+ }
235
+ };
236
+
237
+ SourcesLayer.prototype._onSourcesRefresh = function() {
238
+ this._layer.draw();
239
+ };
240
+
241
+ SourcesLayer.prototype._onSegmentsShow = function(lineId, position) {
242
+ this._lines.addSegments(lineId, position);
243
+ this._view.updateTimelineLength();
244
+ this._layer.draw();
245
+ };
246
+
247
+ /**
248
+ * Creates the Konva UI objects for a given source.
249
+ *
250
+ * @private
251
+ * @param {Source} source
252
+ * @returns {Kanva.Group}
253
+ */
254
+
255
+ SourcesLayer.prototype._createSourceGroup = function(source) {
256
+ return new SourceGroup(source, this._peaks, this, this._view);
257
+ };
258
+
259
+ /**
260
+ * Adds a Konva UI object to the layer for a given source.
261
+ *
262
+ * @private
263
+ * @param {Source} source
264
+ * @returns {Konva.Group}
265
+ */
266
+
267
+ SourcesLayer.prototype._addSourceGroup = function(source) {
268
+ var sourceGroup = this._createSourceGroup(source);
269
+
270
+ this._sourcesGroup[source.id] = sourceGroup;
271
+ this._lines.addSourceGroup(sourceGroup, source.position);
272
+
273
+ // After creating and referencing the new group, we can start data retrieval
274
+ this._dataRetriever.retrieveData(source);
275
+
276
+ return sourceGroup;
277
+ };
278
+
279
+ /**
280
+ * Updates the positions of all displayed sources in the view.
281
+ *
282
+ * @param {Number} startTime The start of the visible range in the view,
283
+ * in seconds.
284
+ * @param {Number} endTime The end of the visible range in the view,
285
+ * in seconds.
286
+ */
287
+
288
+ SourcesLayer.prototype.updateSources = function(startTime, endTime) {
289
+ // Update segments
290
+ this._lines.updateSegments(startTime, endTime);
291
+
292
+ // Update sources in visible time range.
293
+ var sources = this.findSources(startTime, endTime);
294
+
295
+ // Should implement virtualization on Y
296
+
297
+ var count = sources.length;
298
+
299
+ sources.forEach(this._updateSource.bind(this));
300
+ this._lines.setOffsetY(this._view.getFrameOffsetY());
301
+
302
+ count += this._removeInvisibleSources(startTime, endTime);
303
+
304
+ if (count > 0) {
305
+ this._layer.draw();
306
+ }
307
+ };
308
+
309
+ SourcesLayer.prototype.findSources = function(startTime, endTime) {
310
+ var sources = this._peaks.sources.find(startTime, endTime);
311
+ var positions = this._lines.getVisibleLines();
312
+
313
+ return sources.filter(
314
+ function(source) {
315
+ return positions[source.position];
316
+ }
317
+ );
318
+ };
319
+
320
+ SourcesLayer.prototype.updateSource = function(source, newStartX, newEndX, newY) {
321
+ var newXs = {
322
+ startX: newStartX,
323
+ endX: newEndX,
324
+ updateWidth: false
325
+ };
326
+
327
+ if (this._peaks.options.canMoveSourcesBetweenLines) {
328
+ this.manageVerticalPosition(source, newY);
329
+ }
330
+
331
+ newXs = this.manageSourceOrder(source, newStartX, newEndX);
332
+
333
+ newXs = this.manageCollision(source, newXs.startX, newXs.endX);
334
+
335
+ source.updateTimes(
336
+ newXs.startX !== null ? this._view.pixelsToTime(newXs.startX) : null,
337
+ newXs.endX !== null ? this._view.pixelsToTime(newXs.endX) : null
338
+ );
339
+
340
+ if (newXs) {
341
+ this._updateSource(
342
+ source,
343
+ newXs.updateWidth
344
+ );
345
+
346
+ this.draw();
347
+ }
348
+ };
349
+
350
+ SourcesLayer.prototype.manageVerticalPosition = function(source, newY) {
351
+ return this._lines.manageVerticalPosition(source, newY);
352
+ };
353
+
354
+ SourcesLayer.prototype.manageSourceOrder = function(source, newStartX, newEndX) {
355
+ return this._lines.manageSourceOrder(source, newStartX, newEndX);
356
+ };
357
+
358
+ SourcesLayer.prototype.manageCollision = function(source, newStartX, newEndX) {
359
+ return this._lines.manageCollision(source, newStartX, newEndX);
360
+ };
361
+
362
+ /**
363
+ * @private
364
+ */
365
+
366
+ SourcesLayer.prototype._updateSource = function(source) {
367
+ var sourceGroup = this._findOrAddSourceGroup(source);
368
+
369
+ sourceGroup.update();
370
+ };
371
+
372
+ SourcesLayer.prototype._findOrAddSourceGroup = function(source) {
373
+ var sourceGroup = this._sourcesGroup[source.id];
374
+
375
+ if (!sourceGroup) {
376
+ sourceGroup = this._addSourceGroup(source);
377
+ }
378
+
379
+ return sourceGroup;
380
+ };
381
+
382
+ /**
383
+ * Removes any sources that are not visible, i.e., are not within and do not
384
+ * overlap the given time range.
385
+ *
386
+ * @private
387
+ * @param {Number} startTime The start of the visible time range, in seconds.
388
+ * @param {Number} endTime The end of the visible time range, in seconds.
389
+ * @returns {Number} The number of sources removed.
390
+ */
391
+
392
+ SourcesLayer.prototype._removeInvisibleSources = function(startTime, endTime) {
393
+ var count = 0;
394
+
395
+ for (var sourceId in this._sourcesGroup) {
396
+ if (Utils.objectHasProperty(this._sourcesGroup, sourceId)) {
397
+ var source = this._sourcesGroup[sourceId].getSource();
398
+
399
+ if (!this._isSourceVisible(source, startTime, endTime)
400
+ && !this._sourcesGroup[sourceId].isDragged()) {
401
+ this._removeSource(source);
402
+ count++;
403
+ }
404
+ }
405
+ }
406
+
407
+ return count;
408
+ };
409
+
410
+ SourcesLayer.prototype._isSourceVisible = function(source, startTime, endTime) {
411
+ return source.isVisible(startTime, endTime) && this._lines.isLineVisible(source.position);
412
+ };
413
+
414
+ /**
415
+ * Get all visible sources.
416
+ *
417
+ * @private
418
+ * @returns {Array<Source>} The visible sources.
419
+ */
420
+
421
+ SourcesLayer.prototype._getVisibleSources = function() {
422
+ var frameOffset = this._view.getFrameOffset();
423
+ var width = this._view.getWidth();
424
+ var frameStartTime = this._view.pixelsToTime(frameOffset);
425
+ var frameEndTime = this._view.pixelsToTime(frameOffset + width);
426
+
427
+ var visibleSources = [];
428
+
429
+ for (var sourceId in this._sourcesGroup) {
430
+ if (Utils.objectHasProperty(this._sourcesGroup, sourceId)) {
431
+ var source = this._sourcesGroup[sourceId].data;
432
+
433
+ if (source.isVisible(frameStartTime, frameEndTime)) {
434
+ visibleSources.push(source);
435
+ }
436
+ }
437
+ }
438
+
439
+ return visibleSources;
440
+ };
441
+
442
+ SourcesLayer.prototype._getOverlappedSources = function() {
443
+ var self = this;
444
+ var sources = this._getVisibleSources();
445
+
446
+ return sources.reduce(function(result, source) {
447
+ sources.forEach(function(source2) {
448
+ if (self._sourcesGroupOverlapped(source, source2)) {
449
+ if (!result.includes(source2.id)) {
450
+ result.push(source2);
451
+ }
452
+ }
453
+ });
454
+
455
+ return result;
456
+ }, []);
457
+ };
458
+
459
+ /**
460
+ * Removes the given source from the view.
461
+ *
462
+ * @param {Source} source
463
+ */
464
+
465
+ SourcesLayer.prototype._removeSource = function(source, isPermanent, shouldBlockEvent) {
466
+ var sourceGroup = this._sourcesGroup[source.id];
467
+
468
+ if (sourceGroup) {
469
+ delete this._sourcesGroup[source.id];
470
+ this._lines.removeSourceGroup(source, isPermanent);
471
+ sourceGroup.destroy();
472
+ }
473
+
474
+ if (isPermanent && !shouldBlockEvent) {
475
+ this._peaks.emit('source.destroyed', source);
476
+ }
477
+ };
478
+
479
+ /**
480
+ * Toggles visibility of the sources layer.
481
+ *
482
+ * @param {Boolean} visible
483
+ */
484
+
485
+ SourcesLayer.prototype.setVisible = function(visible) {
486
+ this._layer.setVisible(visible);
487
+ };
488
+
489
+ SourcesLayer.prototype.draw = function() {
490
+ this._layer.draw();
491
+ };
492
+
493
+ SourcesLayer.prototype.listening = function(bool) {
494
+ this._layer.listening(bool);
495
+ };
496
+
497
+ SourcesLayer.prototype.stopDrag = function() {
498
+ this._layer.stopDrag();
499
+ };
500
+
501
+ SourcesLayer.prototype.getSourceGroupById = function(sourceId) {
502
+ return this._sourcesGroup[sourceId];
503
+ };
504
+
505
+ SourcesLayer.prototype._sourcesOverlapped = function(source1, source2) {
506
+ var endsLater = (source1.startTime < source2.startTime)
507
+ && (source1.endTime > source2.startTime);
508
+ var startsEarlier = (source1.startTime > source2.startTime)
509
+ && (source1.startTime < source2.endTime);
510
+
511
+ return endsLater || startsEarlier;
512
+ };
513
+
514
+ SourcesLayer.prototype.rescale = function(debounce) {
515
+ // this._lines.rescale();
516
+ if (debounce) {
517
+ this._debouncedRescale();
518
+ }
519
+ else {
520
+ this._rescale();
521
+ }
522
+ };
523
+
524
+ SourcesLayer.prototype._rescale = function() {
525
+ var id, audioPreviews, urls = [], self = this;
526
+
527
+ for (id in this._sourcesGroup) {
528
+ if (Utils.objectHasProperty(this._sourcesGroup, id)) {
529
+ audioPreviews = this._sourcesGroup[id].getAudioPreview();
530
+
531
+ audioPreviews.forEach(function(audioPreview) {
532
+ if (self._shouldResampleAudio(audioPreview.url, urls)) {
533
+ self._loadedData[audioPreview.url + '-scaled'] = {
534
+ data: self._resampleAudio(audioPreview.url),
535
+ scale: self._view.getTimeToPixelsScale()
536
+ };
537
+
538
+ urls.push(audioPreview.url);
539
+ }
540
+ });
541
+ }
542
+ }
543
+ this._layer.draw();
544
+ };
545
+
546
+ SourcesLayer.prototype._shouldResampleAudio = function(audioUrl, urls) {
547
+ return this._loadedData[audioUrl + '-scaled']
548
+ && !urls.includes(audioUrl)
549
+ && this._loadedData[audioUrl + '-scaled'].scale !== this._view.getTimeToPixelsScale();
550
+ };
551
+
552
+ SourcesLayer.prototype._resampleAudio = function(audioUrl) {
553
+ return this._loadedData[audioUrl].resample({
554
+ scale: this._loadedData[audioUrl].sample_rate
555
+ / this._view.getTimeToPixelsScale()
556
+ });
557
+ };
558
+
559
+ SourcesLayer.prototype.destroy = function() {
560
+ this._peaks.off('sources.add', this._onSourcesAdd);
561
+ this._peaks.off('sources.destroy', this._onSourcesDestroy);
562
+ this._peaks.off('sources.show', this._onSourcesShow);
563
+ this._peaks.off('sources.hide', this._onSourcesHide);
564
+ this._peaks.off('source.wrappingChanged', this._onSourceWrappingChanged);
565
+ this._peaks.off('data.retrieved', this._onDataRetrieved);
566
+ this._peaks.off('sources.refresh', this._onSourcesRefresh);
567
+ this._peaks.off('segments.show', this._onSegmentsShow);
568
+ };
569
+
570
+ SourcesLayer.prototype.getHeight = function() {
571
+ return this._layer.getHeight();
572
+ };
573
+
574
+ SourcesLayer.prototype.getLength = function() {
575
+ return this._lines.linesLength();
576
+ };
577
+
578
+ SourcesLayer.prototype.getLineByPosition = function(pos) {
579
+ return this._lines.getLineByPosition(pos);
580
+ };
581
+
582
+ /**
583
+ * Object for storing data and UI of a source.
584
+ *
585
+ * @typedef {Object} CompleteSource
586
+ * @global
587
+ * @property {Source} data
588
+ * @property {Konva.Group} ui
589
+ */
590
+
591
+ return SourcesLayer;
592
+ });