@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,801 +1,805 @@
1
- /**
2
- * @file
3
- *
4
- * Defines the {@link SegmentsGroup} class.
5
- *
6
- * @module segments-group
7
- */
8
-
9
- define([
10
- './segment-shape',
11
- './utils',
12
- 'konva'
13
- ], function(
14
- SegmentShape,
15
- Utils,
16
- Konva) {
17
- 'use strict';
18
-
19
- /**
20
- * Creates a Konva.Group that displays segment markers against the audio
21
- * waveform.
22
- *
23
- * @class
24
- * @alias SegmentsGroup
25
- *
26
- * @param {Peaks} peaks
27
- * @param {WaveformOverview|WaveformZoomView} view
28
- * @param {Boolean} allowEditing
29
- */
30
-
31
- function SegmentsGroup(peaks, view, allowEditing) {
32
- this._peaks = peaks;
33
- this._view = view;
34
- this._allowEditing = allowEditing;
35
-
36
- this._firstSegmentId = null;
37
- this._segments = {};
38
- this._lastSegmentId = null;
39
-
40
- this._segmentShapes = {};
41
- this._group = new Konva.Group();
42
-
43
- this._updatedSegments = [];
44
-
45
- this._isMagnetized = false;
46
-
47
- this._peaks.on('segments.setMagnetizing', this.setMagnetizing.bind(this));
48
- this._peaks.on('segment.setIndicators', this.setIndicators.bind(this));
49
- this._peaks.on('segments.relative_ids_refreshed', this._onRelativeIdsRefreshed.bind(this));
50
- }
51
-
52
- SegmentsGroup.prototype._onRelativeIdsRefreshed = function() {
53
- for (var id in this._segmentShapes) {
54
- if (Utils.objectHasProperty(this._segmentShapes, id)) {
55
- var segmentShape = this._segmentShapes[id];
56
-
57
- var newText = '#'
58
- + segmentShape._segment.relativeId
59
- + ' '
60
- + Utils.removeLineBreaks(segmentShape._segment.labelText);
61
-
62
- if (newText === segmentShape._label.text) {
63
- return;
64
- }
65
-
66
- segmentShape._label.setText(newText);
67
- }
68
- }
69
- };
70
-
71
- SegmentsGroup.prototype.isEmpty = function() {
72
- return Object.keys(this._segments).length === 0;
73
- };
74
-
75
- /**
76
- * Adds the group to the given {Konva.Group}.
77
- *
78
- * @param {Konva.Group} group
79
- */
80
-
81
- SegmentsGroup.prototype.addToGroup = function(group) {
82
- group.add(this._group);
83
- };
84
-
85
- SegmentsGroup.prototype.moveToTop = function() {
86
- this._group.moveToTop();
87
- };
88
-
89
- SegmentsGroup.prototype.enableEditing = function(enable) {
90
- this._allowEditing = enable;
91
- };
92
-
93
- SegmentsGroup.prototype.isEditingEnabled = function() {
94
- return this._allowEditing;
95
- };
96
-
97
- SegmentsGroup.prototype.y = function(value) {
98
- return this._group.y(value);
99
- };
100
-
101
- SegmentsGroup.prototype.getActiveSegment = function(time) {
102
- var activeSegment = null;
103
- var currentSegment = null;
104
- var nextSegmentId = null;
105
-
106
- do {
107
- if (!currentSegment) {
108
- currentSegment = this._segments[this._firstSegmentId];
109
- }
110
- else {
111
- currentSegment = this._segments[currentSegment.nextSegmentId];
112
- }
113
-
114
- if (currentSegment) {
115
- if (currentSegment.segment.startTime > time) {
116
- // We didn't find an active segment and will not in the remainings segments
117
- break;
118
- }
119
-
120
- if (currentSegment.segment.startTime <= time && currentSegment.segment.endTime > time) {
121
- activeSegment = currentSegment.segment;
122
- break;
123
- }
124
- }
125
- else {
126
- break;
127
- }
128
-
129
- nextSegmentId = currentSegment.nextSegmentId;
130
- } while (nextSegmentId);
131
-
132
- return activeSegment;
133
- };
134
-
135
- SegmentsGroup.prototype.onSegmentsUpdate = function(segment) {
136
- if (this._segments[segment.id]) {
137
- var redraw = false;
138
- var segmentShape = this._segmentShapes[segment.id];
139
- var frameOffset = this._view.getFrameOffset();
140
- var width = this._view.getWidth();
141
- var frameStartTime = this._view.pixelsToTime(frameOffset);
142
- var frameEndTime = this._view.pixelsToTime(frameOffset + width);
143
-
144
- this._deleteSegment(segment);
145
- this._addSegment(segment);
146
-
147
- if (segmentShape) {
148
- this._removeSegment(segment);
149
- redraw = true;
150
- }
151
-
152
- if (segment.isVisible(frameStartTime, frameEndTime)) {
153
- this._addSegmentShape(segment);
154
- redraw = true;
155
- }
156
-
157
- if (redraw) {
158
- this.updateSegments(frameStartTime, frameEndTime);
159
- }
160
- }
161
- };
162
-
163
- SegmentsGroup.prototype.onSegmentUpdated = function() {
164
- this._peaks.emit('segments.updated', this._updatedSegments);
165
- this._updatedSegments = [];
166
- };
167
-
168
- SegmentsGroup.prototype.onSegmentsAdd = function(segments) {
169
- var self = this;
170
-
171
- var frameOffset = self._view.getFrameOffset();
172
- var width = self._view.getWidth();
173
-
174
- var frameStartTime = self._view.pixelsToTime(frameOffset);
175
- var frameEndTime = self._view.pixelsToTime(frameOffset + width);
176
-
177
- segments.forEach(function(segment) {
178
- self._addSegment(segment);
179
- });
180
-
181
- self.updateSegments(frameStartTime, frameEndTime);
182
- };
183
-
184
- SegmentsGroup.prototype.onSegmentsRemove = function(segments) {
185
- var self = this;
186
-
187
- segments.forEach(function(segment) {
188
- var index = self._updatedSegments.indexOf(segment);
189
-
190
- if (index > -1) {
191
- self._updatedSegments.splice(index, 1);
192
- }
193
-
194
- self._removeSegment(segment);
195
- self._deleteSegment(segment);
196
- });
197
-
198
- this._draw();
199
- };
200
-
201
- SegmentsGroup.prototype.onSegmentsRemoveAll = function() {
202
- this._group.removeChildren();
203
- this._firstSegmentId = null;
204
- this._segments = {};
205
- this._lastSegmentId = null;
206
-
207
- this._segmentShapes = {};
208
-
209
- this._draw();
210
- };
211
-
212
- SegmentsGroup.prototype._addSegment = function(segment) {
213
- var newSegment = {
214
- segment: segment,
215
- prevSegmentId: null,
216
- nextSegmentId: null
217
- };
218
-
219
- if (this._firstSegmentId) {
220
- var currentSegment = null;
221
-
222
- do {
223
- if (!currentSegment) {
224
- currentSegment = this._segments[this._firstSegmentId];
225
- }
226
- else {
227
- currentSegment = this._segments[currentSegment.nextSegmentId];
228
- }
229
-
230
- if (segment.startTime <= currentSegment.segment.startTime) {
231
- if (currentSegment.prevSegmentId) {
232
- this._segments[currentSegment.prevSegmentId].nextSegmentId = segment.id;
233
- newSegment.prevSegmentId = currentSegment.prevSegmentId;
234
- }
235
- else {
236
- this._firstSegmentId = segment.id;
237
- }
238
-
239
- currentSegment.prevSegmentId = segment.id;
240
- newSegment.nextSegmentId = currentSegment.segment.id;
241
-
242
- this._segments[segment.id] = newSegment;
243
- break;
244
- }
245
- } while (currentSegment.nextSegmentId);
246
-
247
- if (!newSegment.prevSegmentId && !newSegment.nextSegmentId) {
248
- currentSegment.nextSegmentId = segment.id;
249
- newSegment.prevSegmentId = currentSegment.segment.id;
250
- this._segments[segment.id] = newSegment;
251
- this._lastSegmentId = segment.id;
252
- }
253
- }
254
- else {
255
- this._firstSegmentId = segment.id;
256
- this._segments[segment.id] = newSegment;
257
- this._lastSegmentId = segment.id;
258
- }
259
- };
260
-
261
- SegmentsGroup.prototype._deleteSegment = function(segment) {
262
- if (this._segments[segment.id].prevSegmentId) {
263
- this._segments[this._segments[segment.id].prevSegmentId].nextSegmentId
264
- = this._segments[segment.id].nextSegmentId;
265
- }
266
-
267
- if (this._segments[segment.id].nextSegmentId) {
268
- this._segments[this._segments[segment.id].nextSegmentId].prevSegmentId
269
- = this._segments[segment.id].prevSegmentId;
270
- }
271
-
272
- if (this._firstSegmentId === segment.id) {
273
- this._firstSegmentId = this._segments[segment.id].nextSegmentId;
274
- }
275
-
276
- if (this._lastSegmentId === segment.id) {
277
- this._lastSegmentId = this._segments[segment.id].prevSegmentId;
278
- }
279
-
280
- delete this._segments[segment.id];
281
- };
282
-
283
- SegmentsGroup.prototype.getSegmentsGroupLength = function() {
284
- if (this._segments[this._lastSegmentId]) {
285
- return this._view.timeToPixels(this._segments[this._lastSegmentId].segment.endTime);
286
- }
287
-
288
- return 0;
289
- };
290
-
291
- /**
292
- * Creates the Konva UI objects for a given segment.
293
- *
294
- * @private
295
- * @param {Segment} segment
296
- * @returns {SegmentShape}
297
- */
298
-
299
- SegmentsGroup.prototype._createSegmentShape = function(segment) {
300
- return new SegmentShape(segment, this._peaks, this, this._view);
301
- };
302
-
303
- /**
304
- * Adds a Konva UI object to the group for a given segment.
305
- *
306
- * @private
307
- * @param {Segment} segment
308
- * @returns {SegmentShape}
309
- */
310
-
311
- SegmentsGroup.prototype._addSegmentShape = function(segment) {
312
- var segmentShape = this._createSegmentShape(segment);
313
-
314
- segmentShape.addToGroup(this._group, this);
315
-
316
- this._segmentShapes[segment.id] = segmentShape;
317
-
318
- return segmentShape;
319
- };
320
-
321
- SegmentsGroup.prototype.updateSegmentsOnMove = function(segment, marker) {
322
- this._updateSegments(segment, marker);
323
- };
324
-
325
- /**
326
- * Updates the positions of all displayed segments in the view.
327
- *
328
- * @param {Number} startTime The start of the visible range in the view,
329
- * in seconds.
330
- * @param {Number} endTime The end of the visible range in the view,
331
- * in seconds.
332
- */
333
-
334
- SegmentsGroup.prototype.updateSegments = function(startTime, endTime) {
335
- // Update segments in visible time range.
336
- var segments = this.find(startTime, endTime);
337
-
338
- var count = segments.length;
339
-
340
- segments.forEach(this._updateSegment.bind(this));
341
-
342
- // TODO: in the overview all segments are visible, so no need to check
343
- count += this._removeInvisibleSegments(startTime, endTime);
344
-
345
- if (count > 0) {
346
- this._draw();
347
- }
348
- };
349
-
350
- SegmentsGroup.prototype.find = function(startTime, endTime) {
351
- var currentSegment = null;
352
- var visibleSegments = [];
353
-
354
- if (this._firstSegmentId) {
355
- do {
356
- if (!currentSegment) {
357
- currentSegment = this._segments[this._firstSegmentId];
358
- }
359
- else {
360
- currentSegment = this._segments[currentSegment.nextSegmentId];
361
- }
362
-
363
- if (currentSegment.segment.isVisible(startTime, endTime)) {
364
- visibleSegments.push(currentSegment.segment);
365
- }
366
- else if (visibleSegments.length) {
367
- break;
368
- }
369
- } while (currentSegment.nextSegmentId);
370
- }
371
-
372
- return visibleSegments;
373
- };
374
-
375
- SegmentsGroup.prototype._draw = function() {
376
- this._view.drawSourcesLayer();
377
- };
378
-
379
- /**
380
- * @private
381
- * @param {Segment} segment
382
- */
383
-
384
- SegmentsGroup.prototype._updateSegment = function(segment) {
385
- var segmentShape = this._findOrAddSegmentShape(segment);
386
-
387
- segmentShape.update();
388
- };
389
-
390
- SegmentsGroup.prototype.getCurrentHeight = function() {
391
- var currentHeight = 0;
392
-
393
- for (var id in this._segmentShapes) {
394
- if (Utils.objectHasProperty(this._segmentShapes, id)) {
395
- currentHeight = this._segmentShapes[id].getSegmentHeight();
396
- break;
397
- }
398
- }
399
-
400
- if (!currentHeight) {
401
- if (this.isEmpty()) {
402
- currentHeight = this._peaks.options.emptyLineHeight;
403
- }
404
- else {
405
- currentHeight = this._peaks.options.segmentHeight;
406
- }
407
- }
408
-
409
- return currentHeight;
410
- };
411
-
412
- /**
413
- * @private
414
- * @param {Segment} segment
415
- */
416
-
417
- SegmentsGroup.prototype._findOrAddSegmentShape = function(segment) {
418
- var segmentShape = this._segmentShapes[segment.id];
419
-
420
- if (!segmentShape) {
421
- segmentShape = this._addSegmentShape(segment);
422
- }
423
-
424
- return segmentShape;
425
- };
426
-
427
- /**
428
- * Removes any segments that are not visible, i.e., are not within and do not
429
- * overlap the given time range.
430
- *
431
- * @private
432
- * @param {Number} startTime The start of the visible time range, in seconds.
433
- * @param {Number} endTime The end of the visible time range, in seconds.
434
- * @returns {Number} The number of segments removed.
435
- */
436
-
437
- SegmentsGroup.prototype._removeInvisibleSegments = function(startTime, endTime) {
438
- var count = 0;
439
-
440
- for (var segmentId in this._segmentShapes) {
441
- if (Utils.objectHasProperty(this._segmentShapes, segmentId)) {
442
- var segment = this._segmentShapes[segmentId].getSegment();
443
-
444
- if (!segment.isVisible(startTime, endTime)) {
445
- this._removeSegment(segment);
446
- count++;
447
- }
448
- }
449
- }
450
-
451
- return count;
452
- };
453
-
454
- SegmentsGroup.prototype.getVisibleSegments = function() {
455
- return this._getVisibleSegments();
456
- };
457
-
458
- SegmentsGroup.prototype._getVisibleSegments = function() {
459
- var frameOffset = this._view.getFrameOffset();
460
- var width = this._view.getWidth();
461
- var frameStartTime = this._view.pixelsToTime(frameOffset);
462
- var frameEndTime = this._view.pixelsToTime(frameOffset + width);
463
-
464
- var visibleSegments = [];
465
-
466
- for (var segmentId in this._segmentShapes) {
467
- if (Utils.objectHasProperty(this._segmentShapes, segmentId)) {
468
- var segment = this._segmentShapes[segmentId]._segment;
469
-
470
- if (segment.isVisible(frameStartTime, frameEndTime)) {
471
- visibleSegments.push(segment);
472
- }
473
- }
474
- }
475
-
476
- return visibleSegments;
477
- };
478
-
479
- SegmentsGroup.prototype.setMagnetizing = function(bool) {
480
- this._isMagnetized = bool;
481
- };
482
-
483
- SegmentsGroup.prototype.isMagnetized = function() {
484
- return this._isMagnetized;
485
- };
486
-
487
- SegmentsGroup.prototype.setIndicators = function(segment) {
488
- var segmentShape = this._segmentShapes[segment.id];
489
-
490
- if (segmentShape) {
491
- segmentShape.createIndicators();
492
- this._draw();
493
- }
494
- };
495
-
496
- SegmentsGroup.prototype.addToUpdatedSegments = function(segment) {
497
- if (this._updatedSegments.indexOf(segment) === -1) {
498
- this._updatedSegments.push(segment);
499
- }
500
- };
501
-
502
- SegmentsGroup.prototype.updateSegment = function(segment, newStartX, newEndX) {
503
- var newXs = this.manageCollision(segment, newStartX, newEndX);
504
-
505
- if (newXs.startX !== null) {
506
- segment.startTime = this._view.pixelsToTime(newXs.startX);
507
- }
508
-
509
- if (newXs.endX !== null) {
510
- segment.endTime = this._view.pixelsToTime(newXs.endX);
511
- }
512
-
513
- if (newXs) {
514
- this._updateSegment(segment);
515
-
516
- this.addToUpdatedSegments(segment);
517
-
518
- this._draw();
519
- }
520
- };
521
-
522
- SegmentsGroup.prototype.manageCollision = function(segment, newStartX, newEndX) {
523
- var newStartTime = null;
524
- var newEndTime = null;
525
- var startLimited = false;
526
- var endLimited = false;
527
- var segmentMagnetThreshold, width, previousSegment, nextSegment, newXs;
528
-
529
- if (this._isMagnetized) {
530
- segmentMagnetThreshold = this._view.pixelsToTime(
531
- this._peaks.options.segmentMagnetThreshold
532
- );
533
-
534
- if (newStartX !== null && newEndX !== null) {
535
- width = newEndX - newStartX;
536
- }
537
- }
538
-
539
- if (newStartX !== null) {
540
- // startMarker changed
541
- newStartTime = this._view.pixelsToTime(newStartX);
542
-
543
- if (this._segments[segment.id].prevSegmentId) {
544
- // there is another segment to the left
545
- previousSegment = this._segments[this._segments[segment.id].prevSegmentId].segment;
546
-
547
- if (this._isMagnetized) {
548
- if (newStartTime < previousSegment.endTime + segmentMagnetThreshold) {
549
- newStartX = this._view.timeToPixels(previousSegment.endTime);
550
- if (width) {
551
- newEndX = newStartX + width;
552
- }
553
-
554
- return {
555
- startX: newStartX,
556
- endX: newEndX
557
- };
558
- }
559
- }
560
- else if (segment.startTime >= newStartTime) {
561
- // startMarker moved to the left
562
- if (newStartTime < previousSegment.endTime) {
563
- // there is collision
564
- if (previousSegment.editable) {
565
- if (previousSegment.startTime + previousSegment.minSize > newStartTime) {
566
- newStartTime = previousSegment.startTime + previousSegment.minSize;
567
- startLimited = true;
568
- }
569
-
570
- if (previousSegment.endTime !== newStartTime) {
571
- newXs = this.manageCollision(
572
- previousSegment,
573
- this._view.timeToPixels(previousSegment.startTime),
574
- this._view.timeToPixels(newStartTime)
575
- );
576
-
577
- if (newXs.startX !== null) {
578
- previousSegment.startTime = this._view.pixelsToTime(newXs.startX);
579
- }
580
-
581
- if (newXs.endX !== null) {
582
- previousSegment.endTime = this._view.pixelsToTime(newXs.endX);
583
- }
584
-
585
- this._updateSegment(previousSegment);
586
- this.addToUpdatedSegments(previousSegment);
587
- }
588
- }
589
- else {
590
- newStartTime = previousSegment.endTime;
591
- startLimited = true;
592
- }
593
- }
594
- }
595
- }
596
- else {
597
- if (newStartTime < 0) {
598
- newStartTime = 0;
599
- startLimited = true;
600
- }
601
- }
602
- }
603
-
604
- if (newEndX !== null) {
605
- // endMarker changed
606
- newEndTime = this._view.pixelsToTime(newEndX);
607
-
608
- if (this._segments[segment.id].nextSegmentId) {
609
- // there is another segment to the right
610
- nextSegment = this._segments[this._segments[segment.id].nextSegmentId].segment;
611
-
612
- if (this._isMagnetized) {
613
- if (newEndTime > nextSegment.startTime - segmentMagnetThreshold) {
614
- newEndX = this._view.timeToPixels(nextSegment.startTime);
615
- if (width) {
616
- newStartX = newEndX - width;
617
- }
618
-
619
- return {
620
- startX: newStartX,
621
- endX: newEndX
622
- };
623
- }
624
- }
625
- else if (segment.endTime <= newEndTime) {
626
- // endMarker moved to the right
627
- if (newEndTime > nextSegment.startTime) {
628
- // there is collision
629
- if (nextSegment.editable) {
630
- if (nextSegment.endTime - nextSegment.minSize < newEndTime) {
631
- newEndTime = nextSegment.endTime - nextSegment.minSize;
632
- endLimited = true;
633
- }
634
-
635
- if (nextSegment.startTime !== newEndTime) {
636
- newXs = this.manageCollision(
637
- nextSegment,
638
- this._view.timeToPixels(newEndTime),
639
- this._view.timeToPixels(nextSegment.endTime)
640
- );
641
-
642
- if (newXs.startX !== null) {
643
- nextSegment.startTime = this._view.pixelsToTime(newXs.startX);
644
- }
645
-
646
- if (newXs.endX !== null) {
647
- nextSegment.endTime = this._view.pixelsToTime(newXs.endX);
648
- }
649
-
650
- this._updateSegment(nextSegment);
651
- this.addToUpdatedSegments(nextSegment);
652
- }
653
- }
654
- else {
655
- newEndTime = nextSegment.startTime;
656
- endLimited = true;
657
- }
658
- }
659
- }
660
- }
661
- else {
662
- // No limits on the right
663
- }
664
- }
665
-
666
- // Check for minimal size of segment
667
- if (newStartTime !== null && newEndTime !== null) {
668
- if (Utils.roundTime(newEndTime - newStartTime) < segment.minSize) {
669
- if (previousSegment && nextSegment) {
670
- if (Utils.roundTime(nextSegment.startTime - previousSegment.endTime) < segment.minSize) {
671
- return {
672
- startX: null,
673
- endX: null
674
- };
675
- }
676
- }
677
-
678
- if (startLimited) {
679
- newEndTime = newStartTime + segment.minSize;
680
- }
681
- else if (endLimited) {
682
- newStartTime = newEndTime - segment.minSize;
683
- }
684
- }
685
- }
686
- else if (newStartTime !== null) {
687
- if (Utils.roundTime(segment.endTime - newStartTime) < segment.minSize) {
688
- newStartTime = segment.endTime - segment.minSize;
689
- }
690
- }
691
- else if (newEndTime !== null) {
692
- if (Utils.roundTime(newEndTime - segment.startTime) < segment.minSize) {
693
- newEndTime = segment.startTime + segment.minSize;
694
- }
695
- }
696
-
697
- var output = {
698
- startX: null,
699
- endX: null
700
- };
701
-
702
- if (newStartTime !== null) {
703
- output.startX = this._view.timeToPixels(newStartTime);
704
- }
705
-
706
- if (newEndTime !== null) {
707
- output.endX = this._view.timeToPixels(newEndTime);
708
- }
709
-
710
- return output;
711
- };
712
-
713
- SegmentsGroup.prototype._getOverlappedSegments = function() {
714
- var self = this;
715
- var segments = this._getVisibleSegments();
716
-
717
- return segments.reduce(function(result, segment) {
718
- segments.forEach(function(segment2) {
719
- if (self._segmentsOverlapped(segment, segment2)) {
720
- if (!result.includes(segment2.id)) {
721
- result.push(segment2);
722
- }
723
- }
724
- });
725
-
726
- return result;
727
- }, []);
728
- };
729
-
730
- /**
731
- * Removes the given segment from the view.
732
- *
733
- * @param {Segment} segment
734
- */
735
-
736
- SegmentsGroup.prototype._removeSegment = function(segment) {
737
- var segmentShape = this._segmentShapes[segment.id];
738
-
739
- if (segmentShape) {
740
- delete this._segmentShapes[segment.id];
741
- segmentShape.destroy();
742
- }
743
- };
744
-
745
- /**
746
- * Toggles visibility of the segments layer.
747
- *
748
- * @param {Boolean} visible
749
- */
750
-
751
- SegmentsGroup.prototype.setVisible = function(visible) {
752
- this._group.setVisible(visible);
753
- };
754
-
755
- SegmentsGroup.prototype.draw = function() {
756
- this._draw();
757
- };
758
-
759
- SegmentsGroup.prototype._segmentsOverlapped = function(segment1, segment2) {
760
- var endsLater = (segment1.startTime < segment2.startTime)
761
- && (segment1.endTime > segment2.startTime);
762
- var startsEarlier = (segment1.startTime > segment2.startTime)
763
- && (segment1.startTime < segment2.endTime);
764
-
765
- return endsLater || startsEarlier;
766
- };
767
-
768
- SegmentsGroup.prototype.destroy = function() {
769
- this._peaks.off('segments.setMagnetizing', this.setMagnetizing);
770
- this._peaks.off('segment.setIndicators', this.setIndicators);
771
- this._peaks.off('segments.relative_ids_refreshed', this._onRelativeIdsRefreshed);
772
- };
773
-
774
- SegmentsGroup.prototype.fitToView = function() {
775
- for (var segmentId in this._segmentShapes) {
776
- if (Utils.objectHasProperty(this._segmentShapes, segmentId)) {
777
- var segmentShape = this._segmentShapes[segmentId];
778
-
779
- segmentShape.fitToView();
780
- }
781
- }
782
- };
783
-
784
- SegmentsGroup.prototype.contains = function(segment) {
785
- for (var id in this._segments) {
786
- if (Utils.objectHasProperty(this._segments, id)) {
787
- if (id === segment.id) {
788
- return true;
789
- }
790
- }
791
- }
792
-
793
- return false;
794
- };
795
-
796
- SegmentsGroup.prototype.getHeight = function() {
797
- return this._group.getHeight();
798
- };
799
-
800
- return SegmentsGroup;
801
- });
1
+ /**
2
+ * @file
3
+ *
4
+ * Defines the {@link SegmentsGroup} class.
5
+ *
6
+ * @module segments-group
7
+ */
8
+
9
+ define([
10
+ './segment-shape',
11
+ '../utils',
12
+ 'konva'
13
+ ], function(
14
+ SegmentShape,
15
+ Utils,
16
+ Konva) {
17
+ 'use strict';
18
+
19
+ /**
20
+ * Creates a Konva.Group that displays segment markers against the audio
21
+ * waveform.
22
+ *
23
+ * @class
24
+ * @alias SegmentsGroup
25
+ *
26
+ * @param {Peaks} peaks
27
+ * @param {WaveformOverview|WaveformZoomView} view
28
+ * @param {Boolean} allowEditing
29
+ */
30
+
31
+ function SegmentsGroup(peaks, view, allowEditing) {
32
+ this._peaks = peaks;
33
+ this._view = view;
34
+ this._allowEditing = allowEditing;
35
+
36
+ this._firstSegmentId = null;
37
+ this._segments = {};
38
+ this._lastSegmentId = null;
39
+
40
+ this._segmentShapes = {};
41
+ this._group = new Konva.Group();
42
+
43
+ this._updatedSegments = [];
44
+
45
+ this._isMagnetized = false;
46
+
47
+ this._peaks.on('handler.segments.setMagnetizing', this.setMagnetizing.bind(this));
48
+ this._peaks.on('model.segment.setIndicators', this.setIndicators.bind(this));
49
+ this._peaks.on('handler.segments.relative_ids_refreshed', this._onRelativeIdsRefreshed.bind(this));
50
+ }
51
+
52
+ SegmentsGroup.prototype._onRelativeIdsRefreshed = function() {
53
+ for (var id in this._segmentShapes) {
54
+ if (Utils.objectHasProperty(this._segmentShapes, id)) {
55
+ var segmentShape = this._segmentShapes[id];
56
+
57
+ var newText = '#'
58
+ + segmentShape._segment.relativeId
59
+ + ' '
60
+ + Utils.removeLineBreaks(segmentShape._segment.labelText);
61
+
62
+ if (newText === segmentShape._label.text) {
63
+ return;
64
+ }
65
+
66
+ segmentShape._label.setText(newText);
67
+ }
68
+ }
69
+ };
70
+
71
+ SegmentsGroup.prototype.isEmpty = function() {
72
+ return Object.keys(this._segments).length === 0;
73
+ };
74
+
75
+ SegmentsGroup.prototype.countRemainingElements = function() {
76
+ return Object.keys(this._segments).length;
77
+ };
78
+
79
+ /**
80
+ * Adds the group to the given {Konva.Group}.
81
+ *
82
+ * @param {Konva.Group} group
83
+ */
84
+
85
+ SegmentsGroup.prototype.moveTo = function(group) {
86
+ this._group.moveTo(group);
87
+ };
88
+
89
+ SegmentsGroup.prototype.moveToTop = function() {
90
+ this._group.moveToTop();
91
+ };
92
+
93
+ SegmentsGroup.prototype.enableEditing = function(enable) {
94
+ this._allowEditing = enable;
95
+ };
96
+
97
+ SegmentsGroup.prototype.isEditingEnabled = function() {
98
+ return this._allowEditing;
99
+ };
100
+
101
+ SegmentsGroup.prototype.y = function(value) {
102
+ return this._group.y(value);
103
+ };
104
+
105
+ SegmentsGroup.prototype.getActiveSegment = function(time) {
106
+ var activeSegment = null;
107
+ var currentSegment = null;
108
+ var nextSegmentId = null;
109
+
110
+ do {
111
+ if (!currentSegment) {
112
+ currentSegment = this._segments[this._firstSegmentId];
113
+ }
114
+ else {
115
+ currentSegment = this._segments[currentSegment.nextSegmentId];
116
+ }
117
+
118
+ if (currentSegment) {
119
+ if (currentSegment.segment.startTime > time) {
120
+ // We didn't find an active segment and will not in the remainings segments
121
+ break;
122
+ }
123
+
124
+ if (currentSegment.segment.startTime <= time && currentSegment.segment.endTime > time) {
125
+ activeSegment = currentSegment.segment;
126
+ break;
127
+ }
128
+ }
129
+ else {
130
+ break;
131
+ }
132
+
133
+ nextSegmentId = currentSegment.nextSegmentId;
134
+ } while (nextSegmentId);
135
+
136
+ return activeSegment;
137
+ };
138
+
139
+ SegmentsGroup.prototype.onSegmentsUpdate = function(segment) {
140
+ if (this._segments[segment.id]) {
141
+ var redraw = false;
142
+ var segmentShape = this._segmentShapes[segment.id];
143
+ var frameOffset = this._view.getFrameOffset();
144
+ var width = this._view.getWidth();
145
+ var frameStartTime = this._view.pixelsToTime(frameOffset);
146
+ var frameEndTime = this._view.pixelsToTime(frameOffset + width);
147
+
148
+ this._deleteSegment(segment);
149
+ this._addSegment(segment);
150
+
151
+ if (segmentShape) {
152
+ this._removeSegment(segment);
153
+ redraw = true;
154
+ }
155
+
156
+ if (segment.isVisible(frameStartTime, frameEndTime)) {
157
+ this._addSegmentShape(segment);
158
+ redraw = true;
159
+ }
160
+
161
+ if (redraw) {
162
+ this.updateSegments(frameStartTime, frameEndTime);
163
+ }
164
+ }
165
+ };
166
+
167
+ SegmentsGroup.prototype.onSegmentUpdated = function() {
168
+ this._peaks.emit('segments.updated', this._updatedSegments);
169
+ this._updatedSegments = [];
170
+ };
171
+
172
+ SegmentsGroup.prototype.onSegmentsAdd = function(segments) {
173
+ var self = this;
174
+
175
+ var frameOffset = self._view.getFrameOffset();
176
+ var width = self._view.getWidth();
177
+
178
+ var frameStartTime = self._view.pixelsToTime(frameOffset);
179
+ var frameEndTime = self._view.pixelsToTime(frameOffset + width);
180
+
181
+ segments.forEach(function(segment) {
182
+ self._addSegment(segment);
183
+ });
184
+
185
+ self.updateSegments(frameStartTime, frameEndTime);
186
+ };
187
+
188
+ SegmentsGroup.prototype.onSegmentsRemove = function(segments) {
189
+ var self = this;
190
+
191
+ segments.forEach(function(segment) {
192
+ var index = self._updatedSegments.indexOf(segment);
193
+
194
+ if (index > -1) {
195
+ self._updatedSegments.splice(index, 1);
196
+ }
197
+
198
+ self._removeSegment(segment);
199
+ self._deleteSegment(segment);
200
+ });
201
+
202
+ this._draw();
203
+ };
204
+
205
+ SegmentsGroup.prototype.onSegmentsRemoveAll = function() {
206
+ this._group.removeChildren();
207
+ this._firstSegmentId = null;
208
+ this._segments = {};
209
+ this._lastSegmentId = null;
210
+
211
+ this._segmentShapes = {};
212
+
213
+ this._draw();
214
+ };
215
+
216
+ SegmentsGroup.prototype._addSegment = function(segment) {
217
+ var newSegment = {
218
+ segment: segment,
219
+ prevSegmentId: null,
220
+ nextSegmentId: null
221
+ };
222
+
223
+ if (this._firstSegmentId) {
224
+ var currentSegment = null;
225
+
226
+ do {
227
+ if (!currentSegment) {
228
+ currentSegment = this._segments[this._firstSegmentId];
229
+ }
230
+ else {
231
+ currentSegment = this._segments[currentSegment.nextSegmentId];
232
+ }
233
+
234
+ if (segment.startTime <= currentSegment.segment.startTime) {
235
+ if (currentSegment.prevSegmentId) {
236
+ this._segments[currentSegment.prevSegmentId].nextSegmentId = segment.id;
237
+ newSegment.prevSegmentId = currentSegment.prevSegmentId;
238
+ }
239
+ else {
240
+ this._firstSegmentId = segment.id;
241
+ }
242
+
243
+ currentSegment.prevSegmentId = segment.id;
244
+ newSegment.nextSegmentId = currentSegment.segment.id;
245
+
246
+ this._segments[segment.id] = newSegment;
247
+ break;
248
+ }
249
+ } while (currentSegment.nextSegmentId);
250
+
251
+ if (!newSegment.prevSegmentId && !newSegment.nextSegmentId) {
252
+ currentSegment.nextSegmentId = segment.id;
253
+ newSegment.prevSegmentId = currentSegment.segment.id;
254
+ this._segments[segment.id] = newSegment;
255
+ this._lastSegmentId = segment.id;
256
+ }
257
+ }
258
+ else {
259
+ this._firstSegmentId = segment.id;
260
+ this._segments[segment.id] = newSegment;
261
+ this._lastSegmentId = segment.id;
262
+ }
263
+ };
264
+
265
+ SegmentsGroup.prototype._deleteSegment = function(segment) {
266
+ if (this._segments[segment.id].prevSegmentId) {
267
+ this._segments[this._segments[segment.id].prevSegmentId].nextSegmentId
268
+ = this._segments[segment.id].nextSegmentId;
269
+ }
270
+
271
+ if (this._segments[segment.id].nextSegmentId) {
272
+ this._segments[this._segments[segment.id].nextSegmentId].prevSegmentId
273
+ = this._segments[segment.id].prevSegmentId;
274
+ }
275
+
276
+ if (this._firstSegmentId === segment.id) {
277
+ this._firstSegmentId = this._segments[segment.id].nextSegmentId;
278
+ }
279
+
280
+ if (this._lastSegmentId === segment.id) {
281
+ this._lastSegmentId = this._segments[segment.id].prevSegmentId;
282
+ }
283
+
284
+ delete this._segments[segment.id];
285
+ };
286
+
287
+ SegmentsGroup.prototype.getSegmentsGroupLength = function() {
288
+ if (this._segments[this._lastSegmentId]) {
289
+ return this._view.timeToPixels(this._segments[this._lastSegmentId].segment.endTime);
290
+ }
291
+
292
+ return 0;
293
+ };
294
+
295
+ /**
296
+ * Creates the Konva UI objects for a given segment.
297
+ *
298
+ * @private
299
+ * @param {Segment} segment
300
+ * @returns {SegmentShape}
301
+ */
302
+
303
+ SegmentsGroup.prototype._createSegmentShape = function(segment) {
304
+ return new SegmentShape(segment, this._peaks, this, this._view);
305
+ };
306
+
307
+ /**
308
+ * Adds a Konva UI object to the group for a given segment.
309
+ *
310
+ * @private
311
+ * @param {Segment} segment
312
+ * @returns {SegmentShape}
313
+ */
314
+
315
+ SegmentsGroup.prototype._addSegmentShape = function(segment) {
316
+ var segmentShape = this._createSegmentShape(segment);
317
+
318
+ segmentShape.moveTo(this._group, this);
319
+
320
+ this._segmentShapes[segment.id] = segmentShape;
321
+
322
+ return segmentShape;
323
+ };
324
+
325
+ SegmentsGroup.prototype.updateSegmentsOnMove = function(segment, marker) {
326
+ this._updateSegments(segment, marker);
327
+ };
328
+
329
+ /**
330
+ * Updates the positions of all displayed segments in the view.
331
+ *
332
+ * @param {Number} startTime The start of the visible range in the view,
333
+ * in seconds.
334
+ * @param {Number} endTime The end of the visible range in the view,
335
+ * in seconds.
336
+ */
337
+
338
+ SegmentsGroup.prototype.updateSegments = function(startTime, endTime) {
339
+ // Update segments in visible time range.
340
+ var segments = this.find(startTime, endTime);
341
+
342
+ var count = segments.length;
343
+
344
+ segments.forEach(this._updateSegment.bind(this));
345
+
346
+ // TODO: in the overview all segments are visible, so no need to check
347
+ count += this._removeInvisibleSegments(startTime, endTime);
348
+
349
+ if (count > 0) {
350
+ this._draw();
351
+ }
352
+ };
353
+
354
+ SegmentsGroup.prototype.find = function(startTime, endTime) {
355
+ var currentSegment = null;
356
+ var visibleSegments = [];
357
+
358
+ if (this._firstSegmentId) {
359
+ do {
360
+ if (!currentSegment) {
361
+ currentSegment = this._segments[this._firstSegmentId];
362
+ }
363
+ else {
364
+ currentSegment = this._segments[currentSegment.nextSegmentId];
365
+ }
366
+
367
+ if (currentSegment.segment.isVisible(startTime, endTime)) {
368
+ visibleSegments.push(currentSegment.segment);
369
+ }
370
+ else if (visibleSegments.length) {
371
+ break;
372
+ }
373
+ } while (currentSegment.nextSegmentId);
374
+ }
375
+
376
+ return visibleSegments;
377
+ };
378
+
379
+ SegmentsGroup.prototype._draw = function() {
380
+ this._view.drawSourcesLayer();
381
+ };
382
+
383
+ /**
384
+ * @private
385
+ * @param {Segment} segment
386
+ */
387
+
388
+ SegmentsGroup.prototype._updateSegment = function(segment) {
389
+ var segmentShape = this._findOrAddSegmentShape(segment);
390
+
391
+ segmentShape.update();
392
+ };
393
+
394
+ SegmentsGroup.prototype.getCurrentHeight = function() {
395
+ var currentHeight = 0;
396
+
397
+ for (var id in this._segmentShapes) {
398
+ if (Utils.objectHasProperty(this._segmentShapes, id)) {
399
+ currentHeight = this._segmentShapes[id].getSegmentHeight();
400
+ break;
401
+ }
402
+ }
403
+
404
+ if (!currentHeight) {
405
+ if (this.isEmpty()) {
406
+ currentHeight = this._peaks.options.emptyLineHeight;
407
+ }
408
+ else {
409
+ currentHeight = this._peaks.options.segmentHeight;
410
+ }
411
+ }
412
+
413
+ return currentHeight;
414
+ };
415
+
416
+ /**
417
+ * @private
418
+ * @param {Segment} segment
419
+ */
420
+
421
+ SegmentsGroup.prototype._findOrAddSegmentShape = function(segment) {
422
+ var segmentShape = this._segmentShapes[segment.id];
423
+
424
+ if (!segmentShape) {
425
+ segmentShape = this._addSegmentShape(segment);
426
+ }
427
+
428
+ return segmentShape;
429
+ };
430
+
431
+ /**
432
+ * Removes any segments that are not visible, i.e., are not within and do not
433
+ * overlap the given time range.
434
+ *
435
+ * @private
436
+ * @param {Number} startTime The start of the visible time range, in seconds.
437
+ * @param {Number} endTime The end of the visible time range, in seconds.
438
+ * @returns {Number} The number of segments removed.
439
+ */
440
+
441
+ SegmentsGroup.prototype._removeInvisibleSegments = function(startTime, endTime) {
442
+ var count = 0;
443
+
444
+ for (var segmentId in this._segmentShapes) {
445
+ if (Utils.objectHasProperty(this._segmentShapes, segmentId)) {
446
+ var segment = this._segmentShapes[segmentId].getSegment();
447
+
448
+ if (!segment.isVisible(startTime, endTime)) {
449
+ this._removeSegment(segment);
450
+ count++;
451
+ }
452
+ }
453
+ }
454
+
455
+ return count;
456
+ };
457
+
458
+ SegmentsGroup.prototype.getVisibleSegments = function() {
459
+ return this._getVisibleSegments();
460
+ };
461
+
462
+ SegmentsGroup.prototype._getVisibleSegments = function() {
463
+ var frameOffset = this._view.getFrameOffset();
464
+ var width = this._view.getWidth();
465
+ var frameStartTime = this._view.pixelsToTime(frameOffset);
466
+ var frameEndTime = this._view.pixelsToTime(frameOffset + width);
467
+
468
+ var visibleSegments = [];
469
+
470
+ for (var segmentId in this._segmentShapes) {
471
+ if (Utils.objectHasProperty(this._segmentShapes, segmentId)) {
472
+ var segment = this._segmentShapes[segmentId]._segment;
473
+
474
+ if (segment.isVisible(frameStartTime, frameEndTime)) {
475
+ visibleSegments.push(segment);
476
+ }
477
+ }
478
+ }
479
+
480
+ return visibleSegments;
481
+ };
482
+
483
+ SegmentsGroup.prototype.setMagnetizing = function(bool) {
484
+ this._isMagnetized = bool;
485
+ };
486
+
487
+ SegmentsGroup.prototype.isMagnetized = function() {
488
+ return this._isMagnetized;
489
+ };
490
+
491
+ SegmentsGroup.prototype.setIndicators = function(segment) {
492
+ var segmentShape = this._segmentShapes[segment.id];
493
+
494
+ if (segmentShape) {
495
+ segmentShape.createIndicators();
496
+ this._draw();
497
+ }
498
+ };
499
+
500
+ SegmentsGroup.prototype.addToUpdatedSegments = function(segment) {
501
+ if (this._updatedSegments.indexOf(segment) === -1) {
502
+ this._updatedSegments.push(segment);
503
+ }
504
+ };
505
+
506
+ SegmentsGroup.prototype.updateSegment = function(segment, newStartX, newEndX) {
507
+ var newXs = this.manageCollision(segment, newStartX, newEndX);
508
+
509
+ if (!Utils.isNullOrUndefined(newXs.startX)) {
510
+ segment.startTime = this._view.pixelsToTime(newXs.startX);
511
+ }
512
+
513
+ if (!Utils.isNullOrUndefined(newXs.endX)) {
514
+ segment.endTime = this._view.pixelsToTime(newXs.endX);
515
+ }
516
+
517
+ if (newXs) {
518
+ this._updateSegment(segment);
519
+
520
+ this.addToUpdatedSegments(segment);
521
+
522
+ this._draw();
523
+ }
524
+ };
525
+
526
+ SegmentsGroup.prototype.manageCollision = function(segment, newStartX, newEndX) {
527
+ var newStartTime = null;
528
+ var newEndTime = null;
529
+ var startLimited = false;
530
+ var endLimited = false;
531
+ var segmentMagnetThreshold, width, previousSegment, nextSegment, newXs;
532
+
533
+ if (this._isMagnetized) {
534
+ segmentMagnetThreshold = this._view.pixelsToTime(
535
+ this._peaks.options.segmentMagnetThreshold
536
+ );
537
+
538
+ if (!Utils.isNullOrUndefined(newStartX) && !Utils.isNullOrUndefined(newEndX)) {
539
+ width = newEndX - newStartX;
540
+ }
541
+ }
542
+
543
+ if (!Utils.isNullOrUndefined(newStartX)) {
544
+ // startMarker changed
545
+ newStartTime = this._view.pixelsToTime(newStartX);
546
+
547
+ if (this._segments[segment.id].prevSegmentId) {
548
+ // there is another segment to the left
549
+ previousSegment = this._segments[this._segments[segment.id].prevSegmentId].segment;
550
+
551
+ if (this._isMagnetized) {
552
+ if (newStartTime < previousSegment.endTime + segmentMagnetThreshold) {
553
+ newStartX = this._view.timeToPixels(previousSegment.endTime);
554
+ if (width) {
555
+ newEndX = newStartX + width;
556
+ }
557
+
558
+ return {
559
+ startX: newStartX,
560
+ endX: newEndX
561
+ };
562
+ }
563
+ }
564
+ else if (segment.startTime >= newStartTime) {
565
+ // startMarker moved to the left
566
+ if (newStartTime < previousSegment.endTime) {
567
+ // there is collision
568
+ if (previousSegment.editable) {
569
+ if (previousSegment.startTime + previousSegment.minSize > newStartTime) {
570
+ newStartTime = previousSegment.startTime + previousSegment.minSize;
571
+ startLimited = true;
572
+ }
573
+
574
+ if (previousSegment.endTime !== newStartTime) {
575
+ newXs = this.manageCollision(
576
+ previousSegment,
577
+ this._view.timeToPixels(previousSegment.startTime),
578
+ this._view.timeToPixels(newStartTime)
579
+ );
580
+
581
+ if (!Utils.isNullOrUndefined(newXs.startX)) {
582
+ previousSegment.startTime = this._view.pixelsToTime(newXs.startX);
583
+ }
584
+
585
+ if (!Utils.isNullOrUndefined(newXs.endX)) {
586
+ previousSegment.endTime = this._view.pixelsToTime(newXs.endX);
587
+ }
588
+
589
+ this._updateSegment(previousSegment);
590
+ this.addToUpdatedSegments(previousSegment);
591
+ }
592
+ }
593
+ else {
594
+ newStartTime = previousSegment.endTime;
595
+ startLimited = true;
596
+ }
597
+ }
598
+ }
599
+ }
600
+ else {
601
+ if (newStartTime < 0) {
602
+ newStartTime = 0;
603
+ startLimited = true;
604
+ }
605
+ }
606
+ }
607
+
608
+ if (!Utils.isNullOrUndefined(newEndX)) {
609
+ // endMarker changed
610
+ newEndTime = this._view.pixelsToTime(newEndX);
611
+
612
+ if (this._segments[segment.id].nextSegmentId) {
613
+ // there is another segment to the right
614
+ nextSegment = this._segments[this._segments[segment.id].nextSegmentId].segment;
615
+
616
+ if (this._isMagnetized) {
617
+ if (newEndTime > nextSegment.startTime - segmentMagnetThreshold) {
618
+ newEndX = this._view.timeToPixels(nextSegment.startTime);
619
+ if (width) {
620
+ newStartX = newEndX - width;
621
+ }
622
+
623
+ return {
624
+ startX: newStartX,
625
+ endX: newEndX
626
+ };
627
+ }
628
+ }
629
+ else if (segment.endTime <= newEndTime) {
630
+ // endMarker moved to the right
631
+ if (newEndTime > nextSegment.startTime) {
632
+ // there is collision
633
+ if (nextSegment.editable) {
634
+ if (nextSegment.endTime - nextSegment.minSize < newEndTime) {
635
+ newEndTime = nextSegment.endTime - nextSegment.minSize;
636
+ endLimited = true;
637
+ }
638
+
639
+ if (nextSegment.startTime !== newEndTime) {
640
+ newXs = this.manageCollision(
641
+ nextSegment,
642
+ this._view.timeToPixels(newEndTime),
643
+ this._view.timeToPixels(nextSegment.endTime)
644
+ );
645
+
646
+ if (!Utils.isNullOrUndefined(newXs.startX)) {
647
+ nextSegment.startTime = this._view.pixelsToTime(newXs.startX);
648
+ }
649
+
650
+ if (!Utils.isNullOrUndefined(newXs.endX)) {
651
+ nextSegment.endTime = this._view.pixelsToTime(newXs.endX);
652
+ }
653
+
654
+ this._updateSegment(nextSegment);
655
+ this.addToUpdatedSegments(nextSegment);
656
+ }
657
+ }
658
+ else {
659
+ newEndTime = nextSegment.startTime;
660
+ endLimited = true;
661
+ }
662
+ }
663
+ }
664
+ }
665
+ else {
666
+ // No limits on the right
667
+ }
668
+ }
669
+
670
+ // Check for minimal size of segment
671
+ if (!Utils.isNullOrUndefined(newStartTime) && !Utils.isNullOrUndefined(newEndTime)) {
672
+ if (Utils.roundTime(newEndTime - newStartTime) < segment.minSize) {
673
+ if (previousSegment && nextSegment) {
674
+ if (Utils.roundTime(nextSegment.startTime - previousSegment.endTime) < segment.minSize) {
675
+ return {
676
+ startX: null,
677
+ endX: null
678
+ };
679
+ }
680
+ }
681
+
682
+ if (startLimited) {
683
+ newEndTime = newStartTime + segment.minSize;
684
+ }
685
+ else if (endLimited) {
686
+ newStartTime = newEndTime - segment.minSize;
687
+ }
688
+ }
689
+ }
690
+ else if (!Utils.isNullOrUndefined(newStartTime)) {
691
+ if (Utils.roundTime(segment.endTime - newStartTime) < segment.minSize) {
692
+ newStartTime = segment.endTime - segment.minSize;
693
+ }
694
+ }
695
+ else if (!Utils.isNullOrUndefined(newEndTime)) {
696
+ if (Utils.roundTime(newEndTime - segment.startTime) < segment.minSize) {
697
+ newEndTime = segment.startTime + segment.minSize;
698
+ }
699
+ }
700
+
701
+ var output = {
702
+ startX: null,
703
+ endX: null
704
+ };
705
+
706
+ if (!Utils.isNullOrUndefined(newStartTime)) {
707
+ output.startX = this._view.timeToPixels(newStartTime);
708
+ }
709
+
710
+ if (!Utils.isNullOrUndefined(newEndTime)) {
711
+ output.endX = this._view.timeToPixels(newEndTime);
712
+ }
713
+
714
+ return output;
715
+ };
716
+
717
+ SegmentsGroup.prototype._getOverlappedSegments = function() {
718
+ var self = this;
719
+ var segments = this._getVisibleSegments();
720
+
721
+ return segments.reduce(function(result, segment) {
722
+ segments.forEach(function(segment2) {
723
+ if (self._segmentsOverlapped(segment, segment2)) {
724
+ if (!result.includes(segment2.id)) {
725
+ result.push(segment2);
726
+ }
727
+ }
728
+ });
729
+
730
+ return result;
731
+ }, []);
732
+ };
733
+
734
+ /**
735
+ * Removes the given segment from the view.
736
+ *
737
+ * @param {Segment} segment
738
+ */
739
+
740
+ SegmentsGroup.prototype._removeSegment = function(segment) {
741
+ var segmentShape = this._segmentShapes[segment.id];
742
+
743
+ if (segmentShape) {
744
+ delete this._segmentShapes[segment.id];
745
+ segmentShape.destroy();
746
+ }
747
+ };
748
+
749
+ /**
750
+ * Toggles visibility of the segments layer.
751
+ *
752
+ * @param {Boolean} visible
753
+ */
754
+
755
+ SegmentsGroup.prototype.setVisible = function(visible) {
756
+ this._group.setVisible(visible);
757
+ };
758
+
759
+ SegmentsGroup.prototype.draw = function() {
760
+ this._draw();
761
+ };
762
+
763
+ SegmentsGroup.prototype._segmentsOverlapped = function(segment1, segment2) {
764
+ var endsLater = (segment1.startTime < segment2.startTime)
765
+ && (segment1.endTime > segment2.startTime);
766
+ var startsEarlier = (segment1.startTime > segment2.startTime)
767
+ && (segment1.startTime < segment2.endTime);
768
+
769
+ return endsLater || startsEarlier;
770
+ };
771
+
772
+ SegmentsGroup.prototype.destroy = function() {
773
+ this._peaks.off('handler.segments.setMagnetizing', this.setMagnetizing);
774
+ this._peaks.off('model.segment.setIndicators', this.setIndicators);
775
+ this._peaks.off('handler.segments.relative_ids_refreshed', this._onRelativeIdsRefreshed);
776
+ };
777
+
778
+ SegmentsGroup.prototype.fitToView = function() {
779
+ for (var segmentId in this._segmentShapes) {
780
+ if (Utils.objectHasProperty(this._segmentShapes, segmentId)) {
781
+ var segmentShape = this._segmentShapes[segmentId];
782
+
783
+ segmentShape.fitToView();
784
+ }
785
+ }
786
+ };
787
+
788
+ SegmentsGroup.prototype.contains = function(segment) {
789
+ for (var id in this._segments) {
790
+ if (Utils.objectHasProperty(this._segments, id)) {
791
+ if (id === segment.id) {
792
+ return true;
793
+ }
794
+ }
795
+ }
796
+
797
+ return false;
798
+ };
799
+
800
+ SegmentsGroup.prototype.getHeight = function() {
801
+ return this._group.getHeight();
802
+ };
803
+
804
+ return SegmentsGroup;
805
+ });