@checksub_team/peaks_timeline 2.4.0 → 2.5.0-alpha.0

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.
package/peaks.js.d.ts CHANGED
@@ -267,6 +267,12 @@ declare module 'peaks.js' {
267
267
  interface PeaksInstance {
268
268
  setSource: (options: SetSourceOptions, callback: SetSourceCallback) => void;
269
269
  destroy: () => void;
270
+ getSelectedElements: () => object[];
271
+ selectSourceById: (sourceId: string) => void;
272
+ selectSourcesOnLineAfter: (lineId: string, time: number) => void;
273
+ selectSegmentById: (segmentId: string) => void;
274
+ selectSegmentsOnLineAfter: (lineId: string | number, time: number) => void;
275
+ deselectAll: (notify?: boolean) => void;
270
276
  /** Player API */
271
277
  player: {
272
278
  play: () => void;
@@ -646,6 +646,20 @@ define([
646
646
  return sources;
647
647
  };
648
648
 
649
+ /**
650
+ * Returns all segments on this line whose start time is at or after the given time.
651
+ *
652
+ * @param {Number} time
653
+ * @returns {Array<Segment>}
654
+ */
655
+ LineGroup.prototype.getSegmentsAfter = function(time) {
656
+ if (!this.isSegmentsLine()) {
657
+ return [];
658
+ }
659
+
660
+ return this._segmentsGroup.getSegmentsAfter(time);
661
+ };
662
+
649
663
  LineGroup.prototype.getSourcesAround = function(time) {
650
664
  var left = null;
651
665
  var right = null;
@@ -120,8 +120,13 @@ define([
120
120
  this._segmentsGroups[segment.line].onSegmentsUpdate(segment);
121
121
  };
122
122
 
123
- LineGroups.prototype._onSegmentUpdated = function(segment) {
124
- this._segmentsGroups[segment.line].onSegmentUpdated();
123
+ LineGroups.prototype._onSegmentUpdated = function() {
124
+ for (var lineId in this._segmentsGroups) {
125
+ if (Utils.objectHasProperty(this._segmentsGroups, lineId)
126
+ && this._segmentsGroups[lineId].hasUpdatedSegments()) {
127
+ this._segmentsGroups[lineId].onSegmentUpdated();
128
+ }
129
+ }
125
130
  };
126
131
 
127
132
  LineGroups.prototype._onSegmentsRemove = function(segments) {
@@ -232,6 +237,23 @@ define([
232
237
  return this._lineGroupsById[lineId].getSourcesAfter(time);
233
238
  };
234
239
 
240
+ /**
241
+ * Returns all segments in the given segment group or displayed line whose start time is at or after the given time.
242
+ *
243
+ * @param {String|Number} lineId A rendered line identifier or a segment group identifier.
244
+ * @param {Number} time
245
+ * @returns {Array<Segment>}
246
+ */
247
+ LineGroups.prototype.getSegmentsOnLineAfter = function(lineId, time) {
248
+ const lineGroup = this._lineGroupsById[lineId] || this._segmentsGroupToLine[lineId];
249
+
250
+ if (!lineGroup) {
251
+ return [];
252
+ }
253
+
254
+ return lineGroup.getSegmentsAfter(time);
255
+ };
256
+
235
257
  LineGroups.prototype.getSegmentsGroups = function() {
236
258
  return this._segmentsGroups;
237
259
  };
@@ -93,6 +93,12 @@ define([
93
93
  stage.add(this._layer);
94
94
  };
95
95
 
96
+ /**
97
+ * Selects the given elements.
98
+ *
99
+ * @param {Array<Source|Segment>} elements Elements to select.
100
+ * @param {Boolean} notify When <code>true</code>, selection events are emitted.
101
+ */
96
102
  ModeLayer.prototype.selectElements = function(elements, notify) {
97
103
  const sources = [];
98
104
  const segments = [];
@@ -232,12 +238,11 @@ define([
232
238
  const hoveredKonvaElement = this._view.getHoveredElement();
233
239
 
234
240
  if (hoveredKonvaElement) {
235
- if (hoveredKonvaElement instanceof SourceGroup) {
236
- this.selectElements([hoveredKonvaElement.getSource()], true);
237
- }
238
- else {
239
- this.selectElements([hoveredKonvaElement.getSegment()], true);
240
- }
241
+ const element = hoveredKonvaElement instanceof SourceGroup ?
242
+ hoveredKonvaElement.getSource() :
243
+ hoveredKonvaElement.getSegment();
244
+
245
+ this.selectElements([element], true);
241
246
  }
242
247
  else {
243
248
  this.deselectDifference([], true);
@@ -84,50 +84,8 @@ define([
84
84
  }
85
85
  };
86
86
 
87
- SegmentMarker.prototype._dragBoundFunc = function(pos) {
88
- if (this._startMarker) {
89
- var newStartX;
90
-
91
- if (this._segment.duration) {
92
- newStartX = Math.max(
93
- pos.x + this._view.getFrameOffset(),
94
- this._view.timeToPixels(this._segment.endTime - this._segment.duration)
95
- );
96
- }
97
- else {
98
- newStartX = pos.x + this._view.getFrameOffset();
99
- }
100
-
101
- this._segmentShape.getSegmentsGroup().updateSegment(
102
- this._segment,
103
- newStartX,
104
- null
105
- );
106
- }
107
- else {
108
- var newEndX;
109
-
110
- if (this._segment.duration) {
111
- newEndX = Math.min(
112
- pos.x + this._view.getFrameOffset() + this._marker.getHandleWidth(),
113
- this._view.timeToPixels(this._segment.startTime + this._segment.duration)
114
- );
115
- }
116
- else {
117
- newEndX = pos.x + this._view.getFrameOffset() + this._marker.getHandleWidth();
118
- }
119
-
120
- this._segmentShape.getSegmentsGroup().updateSegment(
121
- this._segment,
122
- null,
123
- newEndX
124
- );
125
- }
126
-
127
- return {
128
- x: this._group.getAbsolutePosition().x,
129
- y: this._group.getAbsolutePosition().y
130
- };
87
+ SegmentMarker.prototype._dragBoundFunc = function() {
88
+ return this._view._sourcesLayer.onSegmentHandleDrag(this);
131
89
  };
132
90
 
133
91
  SegmentMarker.prototype.moveTo = function(group) {
@@ -142,6 +100,10 @@ define([
142
100
  return this._group.getX();
143
101
  };
144
102
 
103
+ SegmentMarker.prototype.getAbsolutePosition = function() {
104
+ return this._group.getAbsolutePosition();
105
+ };
106
+
145
107
  SegmentMarker.prototype.getWidth = function() {
146
108
  return this._group.getWidth();
147
109
  };
@@ -162,6 +124,10 @@ define([
162
124
  this._group.setX(x);
163
125
  };
164
126
 
127
+ SegmentMarker.prototype.stopDrag = function() {
128
+ this._group.stopDrag();
129
+ };
130
+
165
131
  SegmentMarker.prototype.timeUpdated = function(time) {
166
132
  if (this._marker.timeUpdated) {
167
133
  this._marker.timeUpdated(time);
@@ -125,20 +125,7 @@ define([
125
125
  }
126
126
 
127
127
  SegmentShape.prototype._onShapeGroupDrag = function(draggedElement) {
128
- const diff = this._view.getPointerPosition().x - this._mouseDownX;
129
-
130
- this._group.updateSegment(
131
- this._segment,
132
- this._initialStartPixel + diff, this._initialEndPixel + diff
133
- );
134
-
135
- this._startMarker.timeUpdated(this._segment.startTime);
136
- this._endMarker.timeUpdated(this._segment.endTime);
137
-
138
- return {
139
- x: draggedElement.absolutePosition().x,
140
- y: draggedElement.absolutePosition().y
141
- };
128
+ return this._view._sourcesLayer.onSegmentDrag(draggedElement);
142
129
  };
143
130
 
144
131
  SegmentShape.prototype._cornerRadius = function() {
@@ -148,8 +135,12 @@ define([
148
135
  };
149
136
 
150
137
  SegmentShape.prototype.update = function() {
151
- var startPixel = this._view.timeToPixels(this._segment.startTime);
152
- var endPixel = this._view.timeToPixels(this._segment.endTime);
138
+ this._applyDisplayTimes(this._segment.startTime, this._segment.endTime);
139
+ };
140
+
141
+ SegmentShape.prototype._applyDisplayTimes = function(startTime, endTime) {
142
+ var startPixel = this._view.timeToPixels(startTime);
143
+ var endPixel = this._view.timeToPixels(endTime);
153
144
  var frameOffset = this._view.timeToPixels(this._view.getTimeOffset());
154
145
 
155
146
  this._shapeGroup.x(startPixel - frameOffset);
@@ -186,12 +177,12 @@ define([
186
177
 
187
178
  if (this._startMarker) {
188
179
  this._startMarker.setX(startPixel - frameOffset);
189
- this._startMarker.timeUpdated(this._segment.startTime);
180
+ this._startMarker.timeUpdated(startTime);
190
181
  }
191
182
 
192
183
  if (this._endMarker) {
193
184
  this._endMarker.setX(endPixel - this._endMarker.getHandleWidth() - frameOffset);
194
- this._endMarker.timeUpdated(this._segment.endTime);
185
+ this._endMarker.timeUpdated(endTime);
195
186
  }
196
187
 
197
188
  if (this._label) {
@@ -224,6 +215,10 @@ define([
224
215
  return this._endMarker;
225
216
  };
226
217
 
218
+ SegmentShape.prototype.stopDrag = function() {
219
+ this._shapeGroup.stopDrag();
220
+ };
221
+
227
222
  SegmentShape.prototype.moveTo = function(group, segmentsGroup) {
228
223
  if (segmentsGroup) {
229
224
  this._segmentsGroup = segmentsGroup;
@@ -412,19 +407,13 @@ define([
412
407
  SegmentShape.prototype._onSegmentDragStart = function() {
413
408
  this._view.setCursor('grab');
414
409
 
415
- this._mouseDownX = this._view.getPointerPosition().x;
416
- this._initialStartTime = this._segment.startTime;
417
- this._initialStartPixel = this._view.timeToPixels(this._initialStartTime);
418
- this._initialEndTime = this._segment.endTime;
419
- this._initialEndPixel = this._view.timeToPixels(this._initialEndTime);
420
-
421
- this._peaks.emit('segments.dragstart', this._segment);
410
+ this._view._sourcesLayer.onSegmentDragStart(this);
422
411
  };
423
412
 
424
413
  SegmentShape.prototype._onSegmentDragEnd = function() {
425
414
  this._view.setCursor('pointer');
426
415
 
427
- this._peaks.emit('segments.dragend', this._segment);
416
+ this._view._sourcesLayer.onSegmentDragEnd(this);
428
417
  };
429
418
 
430
419
  /**
@@ -440,9 +429,7 @@ define([
440
429
  */
441
430
 
442
431
  SegmentShape.prototype._onSegmentHandleDragStart = function(segmentMarker) {
443
- var startMarker = segmentMarker.isStartMarker();
444
-
445
- this._peaks.emit('segments.dragstart', this._segment, startMarker);
432
+ this._view._sourcesLayer.onSegmentHandleDragStart(segmentMarker);
446
433
  };
447
434
 
448
435
  /**
@@ -450,9 +437,7 @@ define([
450
437
  */
451
438
 
452
439
  SegmentShape.prototype._onSegmentHandleDragEnd = function(segmentMarker) {
453
- var startMarker = segmentMarker.isStartMarker();
454
-
455
- this._peaks.emit('segments.dragend', this._segment, startMarker);
440
+ this._view._sourcesLayer.onSegmentHandleDragEnd(segmentMarker);
456
441
  };
457
442
 
458
443
  SegmentShape.prototype.fitToView = function() {
@@ -392,6 +392,35 @@ define([
392
392
  return visibleSegments;
393
393
  };
394
394
 
395
+ /**
396
+ * Returns all segments on this line whose start time is at or after the given time.
397
+ *
398
+ * @param {Number} time
399
+ * @returns {Array<Segment>}
400
+ */
401
+ SegmentsGroup.prototype.getSegmentsAfter = function(time) {
402
+ const segments = [];
403
+ var currentId = this._firstSegmentId;
404
+
405
+ while (currentId) {
406
+ var segmentData = this._segments[currentId];
407
+
408
+ if (segmentData.segment.startTime >= time) {
409
+ while (currentId) {
410
+ segmentData = this._segments[currentId];
411
+
412
+ segments.push(segmentData.segment);
413
+ currentId = segmentData.nextSegmentId;
414
+ }
415
+ break;
416
+ }
417
+
418
+ currentId = segmentData.nextSegmentId;
419
+ }
420
+
421
+ return segments;
422
+ };
423
+
395
424
  SegmentsGroup.prototype._draw = function() {
396
425
  this._view.batchDrawSourcesLayer();
397
426
  };
@@ -504,6 +533,10 @@ define([
504
533
  return this._isMagnetized;
505
534
  };
506
535
 
536
+ SegmentsGroup.prototype.markSegmentsUpdated = function(segments) {
537
+ segments.forEach(this.addToUpdatedSegments.bind(this));
538
+ };
539
+
507
540
  SegmentsGroup.prototype.setIndicators = function(segment) {
508
541
  var segmentShape = this._segmentShapes[segment.id];
509
542
 
@@ -519,15 +552,129 @@ define([
519
552
  }
520
553
  };
521
554
 
522
- SegmentsGroup.prototype.updateSegment = function(segment, newStartX, newEndX) {
555
+ SegmentsGroup.prototype.hasUpdatedSegments = function() {
556
+ return this._updatedSegments.length > 0;
557
+ };
558
+
559
+ /**
560
+ * Returns the allowed drag offset bounds for a set of segments that move together.
561
+ *
562
+ * @param {Array<Segment>} segments
563
+ * @param {Object<String, {startTime: Number, endTime: Number}>} initialPositions
564
+ * @returns {{minTimeOffset: Number, maxTimeOffset: Number}}
565
+ */
566
+ SegmentsGroup.prototype.getSegmentsDragTimeLimits = function(segments, initialPositions) {
567
+ var selectedIds = {};
568
+ var minTimeOffset = -Infinity;
569
+ var maxTimeOffset = Infinity;
570
+
571
+ segments.forEach(function(segment) {
572
+ selectedIds[segment.id] = true;
573
+ });
574
+
575
+ segments.forEach(function(segment) {
576
+ var segmentData = this._segments[segment.id];
577
+ var initialPosition = initialPositions[segment.id];
578
+ var previousSegmentId = segmentData.prevSegmentId;
579
+ var nextSegmentId = segmentData.nextSegmentId;
580
+
581
+ while (previousSegmentId && selectedIds[previousSegmentId]) {
582
+ previousSegmentId = this._segments[previousSegmentId].prevSegmentId;
583
+ }
584
+
585
+ while (nextSegmentId && selectedIds[nextSegmentId]) {
586
+ nextSegmentId = this._segments[nextSegmentId].nextSegmentId;
587
+ }
588
+
589
+ if (previousSegmentId) {
590
+ minTimeOffset = Math.max(
591
+ minTimeOffset,
592
+ this._segments[previousSegmentId].segment.endTime - initialPosition.startTime
593
+ );
594
+ }
595
+ else {
596
+ minTimeOffset = Math.max(minTimeOffset, -initialPosition.startTime);
597
+ }
598
+
599
+ if (nextSegmentId) {
600
+ maxTimeOffset = Math.min(
601
+ maxTimeOffset,
602
+ this._segments[nextSegmentId].segment.startTime - initialPosition.endTime
603
+ );
604
+ }
605
+ }.bind(this));
606
+
607
+ return {
608
+ minTimeOffset: minTimeOffset,
609
+ maxTimeOffset: maxTimeOffset
610
+ };
611
+ };
612
+
613
+ /**
614
+ * Updates a set of dragged segments by the same time offset and refreshes only the visible slice.
615
+ *
616
+ * @param {Array<Segment>} segments
617
+ * @param {Object<String, {startTime: Number, endTime: Number}>} initialPositions
618
+ * @param {Number} timeOffset
619
+ */
620
+ SegmentsGroup.prototype.dragSegmentsByTimeOffset = function(segments, initialPositions, timeOffset) {
621
+ var hasChanges = false;
622
+
623
+ segments.forEach(function(segment) {
624
+ var initialPosition = initialPositions[segment.id];
625
+ var newStartTime = Utils.roundTime(initialPosition.startTime + timeOffset);
626
+ var newEndTime = Utils.roundTime(initialPosition.endTime + timeOffset);
627
+
628
+ if (segment.startTime !== newStartTime || segment.endTime !== newEndTime) {
629
+ segment.updateTimes(newStartTime, newEndTime);
630
+ hasChanges = true;
631
+ }
632
+ });
633
+
634
+ if (hasChanges) {
635
+ this._updateVisibleSegmentsInView();
636
+ }
637
+ };
638
+
639
+ /**
640
+ * Returns the current visible time range for the view.
641
+ *
642
+ * @returns {{startTime: Number, endTime: Number}}
643
+ */
644
+ SegmentsGroup.prototype._getVisibleTimeRange = function() {
645
+ var frameOffset = this._view.getFrameOffset();
646
+ var width = this._view.getWidth();
647
+
648
+ return {
649
+ startTime: this._view.pixelsToTime(frameOffset),
650
+ endTime: this._view.pixelsToTime(frameOffset + width)
651
+ };
652
+ };
653
+
654
+ /**
655
+ * Refreshes the rendered segments for the current viewport without forcing an immediate draw.
656
+ */
657
+ SegmentsGroup.prototype._updateVisibleSegmentsInView = function() {
658
+ var visibleTimeRange = this._getVisibleTimeRange();
659
+
660
+ this.find(visibleTimeRange.startTime, visibleTimeRange.endTime)
661
+ .forEach(this._updateSegment.bind(this));
662
+ this._removeInvisibleSegments(visibleTimeRange.startTime, visibleTimeRange.endTime);
663
+ };
664
+
665
+ SegmentsGroup.prototype.updateSegment = function(segment, newStartX, newEndX, shouldDraw) {
523
666
  var newXs = this.manageCollision(segment, newStartX, newEndX);
524
667
 
668
+ if (Utils.isNullOrUndefined(shouldDraw)) {
669
+ shouldDraw = true;
670
+ }
671
+
525
672
  if (!Utils.isNullOrUndefined(newXs.startX)) {
526
- segment.startTime = this._view.pixelsToTime(newXs.startX);
673
+ segment.updateTimes(this._view.pixelsToTime(newXs.startX), null);
527
674
  }
528
675
 
529
676
  if (!Utils.isNullOrUndefined(newXs.endX)) {
530
- segment.endTime = this._view.pixelsToTime(newXs.endX);
677
+ segment.updateTimes(null, this._view.pixelsToTime(newXs.endX));
531
678
  }
532
679
 
533
680
  if (newXs) {
@@ -535,7 +682,9 @@ define([
535
682
 
536
683
  this.addToUpdatedSegments(segment);
537
684
 
538
- this._draw();
685
+ if (shouldDraw) {
686
+ this._draw();
687
+ }
539
688
  }
540
689
  };
541
690
 
@@ -263,30 +263,7 @@ define([
263
263
  };
264
264
 
265
265
  SourceGroup.prototype._onSourceGroupHandleDrag = function(draggedElement, leftHandle) {
266
- const { start, end } = this._initialTimes;
267
-
268
- this._view.updateWithAutoScroll(
269
- function() {
270
- var pointer = this._view.getPointerPosition();
271
- var pointerX = pointer ? pointer.x : this._mouseDownX;
272
-
273
- const diff = this._view.pixelsToTime(pointerX - this._mouseDownX);
274
- const timeOffsetDiff = this._view.getTimeOffset() - this._initialTimeOffset;
275
-
276
- if (this._layer.manageSourceMovements(
277
- [this._source],
278
- leftHandle ? start + diff + timeOffsetDiff : null,
279
- leftHandle ? null : end + diff + timeOffsetDiff
280
- )) {
281
- this._layer.batchDraw();
282
- }
283
- }.bind(this)
284
- , null, false);
285
-
286
- return {
287
- x: draggedElement.absolutePosition().x,
288
- y: draggedElement.absolutePosition().y
289
- };
266
+ return this._layer.onSourceHandleDrag(draggedElement, leftHandle);
290
267
  };
291
268
 
292
269
  SourceGroup.prototype.update = function() {
@@ -373,21 +350,16 @@ define([
373
350
  }
374
351
  };
375
352
 
376
- SourceGroup.prototype._onHandleDragStart = function() {
377
- this._initialTimeOffset = this._view.getTimeOffset();
378
- this._mouseDownX = this._view.getPointerPosition().x;
379
- this._initialTimes = {
380
- start: this._source.startTime,
381
- end: this._source.endTime
382
- };
353
+ SourceGroup.prototype._onHandleDragStart = function(leftHandle) {
383
354
  this._isHandleDragged = true;
384
355
  this._hideButtons();
356
+ this._layer.onSourceHandleDragStart(this, leftHandle);
385
357
  };
386
358
 
387
359
  SourceGroup.prototype._onHandleDragEnd = function() {
388
360
  this._isHandleDragged = false;
389
361
  this._showButtons();
390
- this._layer.processSourceUpdates([this._source]);
362
+ this._layer.onSourceHandleDragEnd(this);
391
363
  };
392
364
 
393
365
  SourceGroup.prototype._addHandles = function(forceCreate) {
@@ -408,7 +380,7 @@ define([
408
380
 
409
381
  this._leftHandle.on('dragstart', function(event) {
410
382
  event.cancelBubble = true;
411
- self._onHandleDragStart(event);
383
+ self._onHandleDragStart(true);
412
384
  });
413
385
 
414
386
  this._leftHandle.on('dragend', function(event) {
@@ -441,7 +413,7 @@ define([
441
413
 
442
414
  this._rightHandle.on('dragstart', function(event) {
443
415
  event.cancelBubble = true;
444
- self._onHandleDragStart(event);
416
+ self._onHandleDragStart(false);
445
417
  });
446
418
 
447
419
  this._rightHandle.on('dragend', function(event) {