@checksub_team/peaks_timeline 1.16.0-alpha.1 → 2.0.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.
Files changed (36) hide show
  1. package/package.json +1 -1
  2. package/peaks.js +4345 -4185
  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/{line.js → components/line-group.js} +213 -240
  9. package/src/components/line-groups.js +584 -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 -805
  17. package/src/{source-group.js → components/source-group.js} +1641 -1649
  18. package/src/{sources-layer.js → components/sources-layer.js} +716 -725
  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 +99 -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} +1262 -1269
  27. package/src/player.js +2 -2
  28. package/src/{timeline-segments.js → segment-handler.js} +427 -435
  29. package/src/{timeline-sources.js → source-handler.js} +510 -512
  30. package/src/utils.js +5 -1
  31. package/src/{timeline-zoomview.js → view.js} +133 -138
  32. package/src/lines.js +0 -550
  33. /package/src/{data.js → components/data.js} +0 -0
  34. /package/src/{loader.js → components/loader.js} +0 -0
  35. /package/src/{mouse-drag-handler.js → components/mouse-drag-handler.js} +0 -0
  36. /package/src/{svgs.js → components/svgs.js} +0 -0
@@ -1,1649 +1,1641 @@
1
- /**
2
- * @file
3
- *
4
- * Defines the {@link SourceGroup} class.
5
- *
6
- * @module source-group
7
- */
8
-
9
- define([
10
- './waveform-builder',
11
- './waveform-shape',
12
- './utils',
13
- './loader',
14
- 'konva'
15
- ], function(
16
- WaveformBuilder,
17
- WaveformShape,
18
- Utils,
19
- Loader,
20
- Konva) {
21
- 'use strict';
22
-
23
- var SPACING_BETWEEN_PREVIEW_AND_BORDER_RATIO = 0.15;
24
- var SPACING_BETWEEN_PREVIEWS = 1.5;
25
- var CORNER_RADIUS = 8;
26
- var INDICATOR_RADIUS = 4; // px
27
-
28
- /**
29
- * Creates a source group for the given source.
30
- *
31
- * @class
32
- * @alias SourceGroup
33
- *
34
- * @param {Source} source
35
- * @param {Peaks} peaks
36
- * @param {SourcesLayer} layer
37
- * @param {WaveformOverview|WaveformZoomView} view
38
- */
39
-
40
- function SourceGroup(source, peaks, layer, view) {
41
- this._source = source;
42
- this._peaks = peaks;
43
- this._layer = layer;
44
- this._view = view;
45
- this._indicators = {};
46
-
47
- var self = this;
48
-
49
- this._x = this._view.timeToPixels(source.startTime);
50
- this._roundedX = Math.round(this._x);
51
- this._width = this._view.timeToPixels(source.endTime - source.startTime);
52
- this._roundedWidth = Math.round(this._width);
53
- var heights = SourceGroup.getHeights(source, peaks);
54
-
55
- this._unwrappedHeight = heights.unwrapped;
56
- this._wrappedHeight = heights.wrapped;
57
- this._height = heights.current;
58
- this._borderWidth = this._source.borderWidth || 0;
59
- this._currentTimeToPixelsScaleUsed = this._view.getTimeToPixelsScale();
60
- this._selected = this._source.selected;
61
- this._isDragged = false;
62
-
63
- this._previewList = [];
64
-
65
- this._markersGroup = this._createMarkers();
66
-
67
- this._group = new Konva.Group({
68
- x: this._x,
69
- sourceId: this._source.id,
70
- draggable: this._source.draggable,
71
- dragBoundFunc: function() {
72
- return self._layer.onSourcesGroupDrag(this);
73
- },
74
- clipFunc: function(ctx) {
75
- self.drawSourceShape(ctx, null);
76
- }
77
- });
78
-
79
- this._group.on('dragstart', this._onDragStart.bind(this));
80
- this._group.on('dragend', this._onDragEnd.bind(this));
81
-
82
- this._cursor = null;
83
- this._group.on('mouseenter', function() {
84
- self._view.setHoveredElement(self);
85
- if (!self._source.loading) {
86
- self._showButtons();
87
- }
88
- });
89
-
90
- this._group.on('mouseleave', function() {
91
- self._view.setHoveredElement(null);
92
- self._hideButtons();
93
- });
94
-
95
- this._group.on('mouseover', function() {
96
- if (self._source.draggable) {
97
- self._view.setCursor(self._cursor || 'pointer');
98
- }
99
- if (self._view.getCurrentMode() === 'cut') {
100
- self.toggleDragging(false);
101
- self.toggleResizing(false);
102
- }
103
- });
104
-
105
- this._group.on('mouseout', function() {
106
- self._view.setCursor('default');
107
- if (self._view.getCurrentMode() === 'cut') {
108
- self.toggleDragging(true);
109
- self.toggleResizing(true);
110
- }
111
- });
112
-
113
- this._group.add(new Konva.Group());
114
-
115
- if (this._borderWidth) {
116
- this._border = new Konva.Shape({
117
- fill: this._source.borderColor,
118
- sceneFunc: function(ctx, shape) {
119
- self.drawSourceShape(ctx, shape);
120
- }
121
- });
122
- this._group.getChildren()[0].add(this._border);
123
- }
124
- this._addHandles();
125
-
126
- this.setWrapping(source.wrapped);
127
-
128
- this.setSelected();
129
-
130
- this._indicatorsGroup = new Konva.Group();
131
- this.addToContent(this._indicatorsGroup);
132
-
133
- this.createIndicators();
134
-
135
- this.setLoadingState(this._source.loading);
136
- }
137
-
138
- SourceGroup.prototype._onDragStart = function(element) {
139
- this._isDragged = true;
140
- this._layer.onSourcesGroupDragStart(element);
141
- };
142
-
143
- SourceGroup.prototype._onDragEnd = function(element) {
144
- this._isDragged = false;
145
- this._layer.onSourcesGroupDragEnd(element);
146
- };
147
-
148
- SourceGroup.prototype.isActive = function() {
149
- return this._isDragged;
150
- };
151
-
152
- SourceGroup.prototype.addToContent = function(newChild) {
153
- if (this._source.wrapped) {
154
- this._wrap.add(newChild);
155
- }
156
- else {
157
- this._unwrap.add(newChild);
158
- }
159
- };
160
-
161
- SourceGroup.prototype.prepareDragEnd = function() {
162
- var handleWidth = Math.min(this._peaks.options.sourceHandleWidth, this._width / 2);
163
-
164
- this._leftHandle.width(handleWidth);
165
- this._rightHandle.width(handleWidth);
166
- this._rightHandle.x(this._width - handleWidth);
167
- };
168
-
169
- SourceGroup.prototype._onSourceGroupHandleDrag = function(draggedElement, dragPos, leftHandle) {
170
- const diff = this._view.pixelsToTime(dragPos.x - this._mouseDownX);
171
- const timeOffsetDiff = this._view.getTimeOffset() - this._initialTimeOffset;
172
-
173
- const { start, end } = this._initialTimes;
174
-
175
- this._view.updateWithAutoScroll(
176
- function() {
177
- if (this._layer.manageSourceMovements(
178
- [this._source],
179
- leftHandle ? start + diff + timeOffsetDiff : null,
180
- leftHandle ? null : end + diff + timeOffsetDiff
181
- )) {
182
- this._layer.draw();
183
- }
184
- }.bind(this)
185
- );
186
-
187
- this._view.setTimelineLength(
188
- this._view.timeToPixels(this._source.endTime) + this._view.getWidth()
189
- );
190
-
191
- return {
192
- x: draggedElement.absolutePosition().x,
193
- y: draggedElement.absolutePosition().y
194
- };
195
- };
196
-
197
- SourceGroup.prototype.update = function() {
198
- const startPixel = this._view.timeToPixels(this._source.startTime);
199
- const endPixel = this._view.timeToPixels(this._source.endTime);
200
- const frameOffset = this._view.timeToPixels(this._view.getTimeOffset());
201
- const newTimeToPixelsScale = this._view.getTimeToPixelsScale();
202
-
203
- this._group.x(startPixel - frameOffset);
204
-
205
- this._x = startPixel;
206
- this._roundedX = Math.round(this._x);
207
-
208
- const newWidth = endPixel - startPixel;
209
-
210
- if (newWidth !== this._width) {
211
- this._width = newWidth;
212
- this._roundedWidth = Math.round(this._width);
213
-
214
- // the zoom was changed
215
- if (newTimeToPixelsScale !== this._currentTimeToPixelsScaleUsed) {
216
- this._currentTimeToPixelsScaleUsed = newTimeToPixelsScale;
217
-
218
- this._updateMarkers();
219
-
220
- this._rightHandle.x(this._width - this._rightHandle.width());
221
- }
222
- else {
223
- // the zoom was not changed, but the source was resized
224
- const newTitle = Utils.removeLineBreaks(this._source.getVisibleTitle());
225
-
226
- if (this._wrappedTitle && this._wrappedTitle.text() !== newTitle) {
227
- this._wrap.add(this._createTitle(true));
228
- }
229
- if (this._unwrappedTitle && this._unwrappedTitle.text() !== newTitle) {
230
- this._unwrap.add(this._createTitle(false));
231
- }
232
- }
233
-
234
- this._updateVolumeSlider();
235
- this._updateButtons();
236
- this._updateLoadingOverlay();
237
-
238
- // update unwrap
239
- this.updatePreviews();
240
- }
241
- };
242
-
243
- SourceGroup.prototype.setWrapping = function(wrap, forceCreate, notify) {
244
- if (wrap) {
245
- this._removeUnwrap();
246
- this._height = this._wrappedHeight;
247
- this._addWrap(forceCreate);
248
- }
249
- else {
250
- this._removeWrap();
251
- this._height = this._unwrappedHeight;
252
- this._addUnwrap(forceCreate);
253
- }
254
-
255
- this.setHandlesWrapping(wrap);
256
-
257
- if (notify) {
258
- this._peaks.emit('source.wrappingChanged', this);
259
- }
260
- };
261
-
262
- SourceGroup.prototype.setHandlesWrapping = function(wrap) {
263
- if (wrap) {
264
- this._leftHandle.height(this._wrappedHeight);
265
- this._rightHandle.height(this._wrappedHeight);
266
- }
267
- else {
268
- this._leftHandle.height(this._unwrappedHeight);
269
- this._rightHandle.height(this._unwrappedHeight);
270
- }
271
- };
272
-
273
- SourceGroup.prototype._onHandleDragStart = function() {
274
- this._initialTimeOffset = this._view.getTimeOffset();
275
- this._mouseDownX = this._view.getPointerPosition().x;
276
- this._initialTimes = {
277
- start: this._source.startTime,
278
- end: this._source.endTime
279
- };
280
-
281
- this._hideButtons();
282
- };
283
-
284
- SourceGroup.prototype._onHandleDragEnd = function() {
285
- this._showButtons();
286
- };
287
-
288
- SourceGroup.prototype._addHandles = function(forceCreate) {
289
- var self = this;
290
- var handleWidth = Math.min(this._peaks.options.sourceHandleWidth, this._width / 2);
291
-
292
- if (!this._leftHandle || forceCreate) {
293
- this._leftHandle = new Konva.Rect({
294
- x: 0,
295
- width: handleWidth,
296
- height: this._unwrappedHeight,
297
- visible: true,
298
- draggable: this._source.resizable,
299
- dragBoundFunc: function(pos) {
300
- return self._onSourceGroupHandleDrag(this, pos, true);
301
- }
302
- });
303
-
304
- this._leftHandle.on('dragstart', this._onHandleDragStart.bind(this));
305
-
306
- this._leftHandle.on('dragend', this._onHandleDragEnd.bind(this));
307
-
308
- if (this._source.resizable) {
309
- this._leftHandle.on('mouseover', function() {
310
- self._cursor = 'ew-resize';
311
- });
312
-
313
- this._leftHandle.on('mouseout', function() {
314
- self._cursor = null;
315
- });
316
- }
317
- }
318
-
319
- if (!this._rightHandle || forceCreate) {
320
- this._rightHandle = new Konva.Rect({
321
- x: this._width - handleWidth,
322
- width: handleWidth,
323
- height: this._unwrappedHeight,
324
- visible: true,
325
- draggable: this._source.resizable,
326
- dragBoundFunc: function(pos) {
327
- return self._onSourceGroupHandleDrag(this, pos, false);
328
- }
329
- });
330
-
331
- this._rightHandle.on('dragstart', this._onHandleDragStart.bind(this));
332
-
333
- this._rightHandle.on('dragend', this._onHandleDragEnd.bind(this));
334
-
335
- if (this._source.resizable) {
336
- this._rightHandle.on('mouseover', function() {
337
- self._cursor = 'ew-resize';
338
- });
339
-
340
- this._rightHandle.on('mouseout', function() {
341
- self._cursor = null;
342
- });
343
- }
344
- }
345
-
346
- this._group.add(this._leftHandle);
347
- this._group.add(this._rightHandle);
348
- };
349
-
350
- SourceGroup.prototype.toggleDragging = function(bool) {
351
- var background;
352
-
353
- if (this._wrap) {
354
- background = this._wrap.getChildren(function(node) {
355
- return node.getClassName() === 'Shape';
356
- })[0];
357
-
358
- if (background) {
359
- background.draggable(bool);
360
- }
361
- }
362
- if (this._unwrap) {
363
- background = this._unwrap.getChildren(function(node) {
364
- return node.getClassName() === 'Shape';
365
- })[0];
366
-
367
- if (background) {
368
- background.draggable(bool);
369
- }
370
- }
371
- };
372
-
373
- SourceGroup.prototype.toggleResizing = function(bool) {
374
- if (this._leftHandle) {
375
- this._leftHandle.draggable(bool);
376
- }
377
- if (this._rightHandle) {
378
- this._rightHandle.draggable(bool);
379
- }
380
- };
381
-
382
- SourceGroup.prototype.drawSourceShape = function(ctx, shape, addBorderWidth, fill) {
383
- var offset = addBorderWidth ? this._borderWidth : 0;
384
- var radius = this._source.borderRadius !== undefined && this._source.borderRadius !== null ?
385
- this._source.borderRadius :
386
- Math.max(
387
- 1,
388
- Math.min(
389
- this._roundedWidth / 2,
390
- Math.min(
391
- CORNER_RADIUS,
392
- this._height / 2
393
- )
394
- )
395
- );
396
- var x = Math.max(
397
- 0,
398
- this._view.getFrameOffset() - this._roundedX - radius
399
- );
400
- var width = Math.min(
401
- this._roundedWidth - x,
402
- this._view.getWidth() + radius - Math.max(
403
- 0,
404
- this._roundedX - this._view.getFrameOffset()
405
- )
406
- );
407
- var xWidth = x + width;
408
-
409
- ctx.beginPath();
410
- ctx.moveTo(x + radius, offset);
411
- ctx.lineTo(xWidth - radius, offset);
412
- ctx.quadraticCurveTo(xWidth - offset, offset, xWidth - offset, radius);
413
- ctx.lineTo(xWidth - offset, this._height - radius);
414
- ctx.quadraticCurveTo(
415
- xWidth - offset,
416
- this._height - offset,
417
- xWidth - radius,
418
- this._height - offset
419
- );
420
- ctx.lineTo(x + radius, this._height - offset);
421
- ctx.quadraticCurveTo(x + offset, this._height - offset, x + offset, this._height - radius);
422
- ctx.lineTo(x + offset, radius);
423
- ctx.quadraticCurveTo(x + offset, offset, x + radius, offset);
424
- ctx.closePath();
425
-
426
- if (fill) {
427
- if (this._source.shouldShowWarning()) {
428
- var gradient = ctx.createLinearGradient(0, 0, this._roundedWidth, 0);
429
-
430
- if (this._source.mediaEndTime < this._source.duration) {
431
- var rightStopPosition = Math.max(1 - (this._source.warningWidth / this._roundedWidth), 0.5);
432
-
433
- gradient.addColorStop(rightStopPosition, this._source.backgroundColor);
434
- gradient.addColorStop(1, this._source.warningColor);
435
- }
436
-
437
- if (this._source.mediaStartTime > 0) {
438
- var leftStopPosition = Math.min(this._source.warningWidth / this._roundedWidth, 0.5);
439
-
440
- gradient.addColorStop(0, this._source.warningColor);
441
- gradient.addColorStop(leftStopPosition, this._source.backgroundColor);
442
- }
443
-
444
- ctx.fillStyle = gradient;
445
- ctx.fill();
446
- }
447
- else {
448
- ctx.fillStyle = this._source.backgroundColor;
449
- ctx.fill();
450
- }
451
- }
452
-
453
- if (shape) {
454
- ctx.fillStrokeShape(shape);
455
- }
456
- };
457
-
458
- SourceGroup.prototype._addUnwrap = function(forceCreate) {
459
- if (!this._unwrap || forceCreate) {
460
- this._unwrap = this._createUnwrap();
461
- }
462
-
463
- this._group.getChildren()[0].add(this._unwrap);
464
- };
465
-
466
- SourceGroup.prototype._createUnwrap = function() {
467
- var self = this;
468
-
469
- var unwrap = new Konva.Group({
470
- width: this._width,
471
- height: this._unwrappedHeight,
472
- clipFunc: function(ctx) {
473
- self.drawSourceShape(ctx, null, true);
474
- }
475
- });
476
-
477
- var background = new Konva.Group();
478
-
479
- background.add(new Konva.Shape({
480
- sceneFunc: function(ctx, shape) {
481
- self.drawSourceShape(ctx, shape, true, true);
482
- }
483
- }));
484
-
485
- unwrap.add(background);
486
- unwrap.add(this._markersGroup);
487
- if (this._source.volumeRange && this._source.volume !== undefined) {
488
- unwrap.add(this._getVolumeSlider());
489
- }
490
- if (this._source.buttons.length > 0) {
491
- unwrap.add(this._getButtons());
492
- }
493
- unwrap.add(this._createTitle(false));
494
-
495
- return unwrap;
496
- };
497
-
498
- SourceGroup.prototype._addToUnwrap = function(element, inForeground) {
499
- if (inForeground) {
500
- this._unwrap.add(element);
501
- }
502
- else {
503
- this._unwrap.getChildren()[0].add(element);
504
- }
505
- };
506
-
507
- SourceGroup.prototype._removeUnwrap = function() {
508
- if (this._unwrap) {
509
- this._unwrap.remove();
510
- }
511
- };
512
-
513
- SourceGroup.prototype._addWrap = function(forceCreate) {
514
- if (!this._wrap || forceCreate) {
515
- this._wrap = this._createWrap();
516
- }
517
-
518
- this._group.getChildren()[0].add(this._wrap);
519
- };
520
-
521
- SourceGroup.prototype._createWrap = function() {
522
- var self = this;
523
-
524
- var wrap = new Konva.Group({
525
- width: this._width,
526
- height: this._wrappedHeight,
527
- clipFunc: function(ctx) {
528
- self.drawSourceShape(ctx, null, true);
529
- }
530
- });
531
-
532
- var background = new Konva.Group();
533
-
534
- background.add(new Konva.Shape({
535
- sceneFunc: function(ctx, shape) {
536
- self.drawSourceShape(ctx, shape, true, true);
537
- }
538
- }));
539
-
540
- wrap.add(background);
541
- wrap.add(this._markersGroup);
542
- if (this._source.volumeRange && this._source.volume !== undefined) {
543
- wrap.add(this._getVolumeSlider());
544
- }
545
- if (this._source.buttons.length > 0) {
546
- wrap.add(this._getButtons());
547
- }
548
- wrap.add(this._createTitle(true));
549
-
550
- return wrap;
551
- };
552
-
553
- SourceGroup.prototype._addToWrap = function(element, inForeground) {
554
- if (inForeground) {
555
- this._wrap.add(element);
556
- }
557
- else {
558
- this._wrap.getChildren()[0].add(element);
559
- }
560
- };
561
-
562
- SourceGroup.prototype._removeWrap = function() {
563
- if (this._wrap) {
564
- this._wrap.remove();
565
- }
566
- };
567
-
568
- SourceGroup.prototype._createTitle = function(isWrap) {
569
- var self = this;
570
- var defaultWidth;
571
- var y = (this._source.textPosition === 'bottom') ?
572
- Math.max(
573
- (isWrap ? this._wrappedHeight : this._unwrappedHeight)
574
- - this._source.textFontSize - this._peaks.options.sourceTextYOffset,
575
- this._peaks.options.sourceTextYOffset
576
- ) : this._peaks.options.sourceTextYOffset;
577
- var defaultXOffset = this._peaks.options.sourceTextXOffset;
578
- var maxXOffset = this._width - 2 * defaultXOffset;
579
-
580
- if (isWrap) {
581
- if (this._wrappedTitle) {
582
- this._wrappedTitle.destroy();
583
- this._wrappedTitle = null;
584
- }
585
- }
586
- else {
587
- if (this._unwrappedTitle) {
588
- this._unwrappedTitle.destroy();
589
- this._unwrappedTitle = null;
590
- }
591
- }
592
-
593
- var title = new Konva.Text({
594
- x: defaultXOffset,
595
- y: y,
596
- text: Utils.removeLineBreaks(this._source.getVisibleTitle()),
597
- textAlign: 'left',
598
- verticalAlign: 'middle',
599
- fontSize: this._source.textFontSize,
600
- fontFamily: this._source.textFont,
601
- fill: this._source.textColor,
602
- wrap: 'none',
603
- ellipsis: true,
604
- listening: false,
605
- sceneFunc: function(context, shape) {
606
- var absX = this.absolutePosition().x;
607
-
608
- if (self._source.textAutoScroll && absX < defaultXOffset) {
609
- this.offsetX(Math.max(Math.min(0, absX - defaultXOffset), -(maxXOffset - shape.width())));
610
- }
611
- defaultWidth = defaultWidth ? defaultWidth : shape.width();
612
- shape.width(Math.min(self._width - 10, defaultWidth));
613
- if (self._source.textBackgroundColor) {
614
- context.fillStyle = self._source.textBackgroundColor;
615
- context.fillRect(-5, -5, shape.width() + 10, shape.height() ? shape.height() + 10 : 0);
616
- }
617
- shape._sceneFunc(context);
618
- }
619
- });
620
-
621
- if (isWrap) {
622
- this._wrappedTitle = title;
623
- }
624
- else {
625
- this._unwrappedTitle = title;
626
- }
627
-
628
- return title;
629
- };
630
-
631
- SourceGroup.prototype.getWidth = function() {
632
- return this._width;
633
- };
634
-
635
- SourceGroup.prototype.getX = function() {
636
- return this._x;
637
- };
638
-
639
- SourceGroup.prototype.getY = function() {
640
- return this._group.absolutePosition().y;
641
- };
642
-
643
- SourceGroup.prototype.x = function(value) {
644
- if (value) {
645
- return this._group.x(value);
646
- }
647
- else {
648
- return this._group.x();
649
- }
650
- };
651
-
652
- SourceGroup.prototype.y = function(value) {
653
- if (value) {
654
- return this._group.y(value);
655
- }
656
- else {
657
- return this._group.y();
658
- }
659
- };
660
-
661
- SourceGroup.prototype.getSource = function() {
662
- return this._source;
663
- };
664
-
665
- SourceGroup.prototype.startDrag = function() {
666
- return this._group.startDrag();
667
- };
668
-
669
- SourceGroup.prototype.stopDrag = function() {
670
- return this._group.stopDrag();
671
- };
672
-
673
- SourceGroup.prototype.addToGroup = function(group) {
674
- group.add(this._group);
675
- };
676
-
677
- SourceGroup.prototype.isDescendantOf = function(group) {
678
- group.isAncestorOf(this._group);
679
- };
680
-
681
- SourceGroup.prototype.moveTo = function(group) {
682
- this._group.moveTo(group);
683
- };
684
-
685
- SourceGroup.prototype.getParent = function() {
686
- return this._group.getParent();
687
- };
688
-
689
- SourceGroup.prototype.remove = function() {
690
- this._group.remove();
691
- };
692
-
693
- SourceGroup.prototype.addImagePreview = function(content, url, redraw) {
694
- var preview = {
695
- type: 'image',
696
- group: new Konva.Group({
697
- height: this._unwrappedHeight,
698
- listening: false
699
- })
700
- };
701
-
702
- var imageData = this._layer.getLoadedData(url);
703
-
704
- if (!imageData) {
705
- imageData = new Image();
706
-
707
- var self = this;
708
-
709
- imageData.onload = function() {
710
- self._layer.setLoadedData(url, this);
711
- preview.loaded = true;
712
- self._createImagePreview(preview, imageData, redraw);
713
- };
714
-
715
- imageData.src = content;
716
- }
717
- else {
718
- preview.loaded = true;
719
- this._createImagePreview(preview, imageData, redraw);
720
- }
721
- };
722
-
723
- SourceGroup.prototype.addVideoPreview = function(content, url, redraw) {
724
- var preview = {
725
- type: 'video',
726
- group: new Konva.Group({
727
- y: this._source.binaryUrl && this._source.previewUrl ? this._source.binaryHeight : 0,
728
- height: this._source.binaryUrl && this._source.previewUrl ?
729
- this._source.previewHeight : this._unwrappedHeight,
730
- listening: false
731
- })
732
- };
733
-
734
- var imageData = this._layer.getLoadedData(url);
735
-
736
- if (!imageData) {
737
- var video = document.createElement('video');
738
- var self = this;
739
-
740
- video.onloadeddata = function() {
741
- this.currentTime = this.duration / 2;
742
-
743
- var canvas = document.createElement('canvas');
744
-
745
- canvas.width = this.videoWidth;
746
- canvas.height = this.videoHeight;
747
- canvas.getContext('2d').drawImage(this, 0, 0, canvas.width, canvas.height);
748
-
749
- imageData = new Image();
750
-
751
- imageData.onload = function() {
752
- self._layer.setLoadedData(url, this);
753
- preview.loaded = true;
754
- self._createImagePreview(preview, imageData, redraw);
755
- };
756
-
757
- imageData.src = canvas.toDataURL();
758
- };
759
-
760
- video.src = content;
761
- }
762
- else {
763
- preview.loaded = true;
764
- this._createImagePreview(preview, imageData, redraw);
765
- }
766
- };
767
-
768
- SourceGroup.prototype.addAudioPreview = function(type, content, url, redraw) {
769
- var preview = {
770
- type: 'audio',
771
- group: new Konva.Group({
772
- height: this._source.binaryUrl && this._source.previewUrl ?
773
- this._source.binaryHeight : this._unwrappedHeight,
774
- listening: false
775
- }),
776
- url: url
777
- };
778
-
779
- var self = this;
780
-
781
- var audioData = this._layer.getLoadedData(url);
782
-
783
- if (!audioData) {
784
- var waveformBuilder = new WaveformBuilder(this._peaks);
785
- var options = Object.assign({},this._peaks.options);
786
-
787
- if (type === 'audio') {
788
- options.objectUrl = content;
789
- }
790
- else {
791
- options.dataUri = content;
792
- }
793
-
794
- waveformBuilder.init(options, function(err, originalWaveformData) {
795
- if (err) {
796
- throw err;
797
- }
798
-
799
- originalWaveformData.hasAudio = self._hasAudio(originalWaveformData);
800
-
801
- if (originalWaveformData.hasAudio) {
802
- var newScale = originalWaveformData.sample_rate / self._view.getTimeToPixelsMaxZoom();
803
-
804
- if (newScale > originalWaveformData.scale) {
805
- self._minScale = newScale;
806
- }
807
- else {
808
- self._minScale = originalWaveformData.scale;
809
- }
810
-
811
- self._view.setTimeToPixelsMaxZoom(originalWaveformData.sample_rate / self._minScale);
812
- }
813
-
814
- self._layer.setLoadedData(url, originalWaveformData);
815
- self._layer.setLoadedData(
816
- url + '-scaled',
817
- { data: originalWaveformData, scale: originalWaveformData.sample_rate / self._minScale }
818
- );
819
- preview.loaded = true;
820
- self._createAudioPreview(preview, originalWaveformData, redraw);
821
- });
822
- }
823
- else {
824
- preview.loaded = true;
825
- this._createAudioPreview(preview, audioData, redraw);
826
- }
827
- };
828
-
829
- SourceGroup.prototype._hasAudio = function(waveformData) {
830
- var channels = waveformData.channels;
831
- var channel, someIsNotZero = false;
832
-
833
- for (var i = 0; i < channels; i++) {
834
- channel = waveformData.channel(i);
835
-
836
- someIsNotZero = channel.min_array().some(function(item) {
837
- return item !== 0;
838
- });
839
-
840
- if (!someIsNotZero) {
841
- someIsNotZero = channel.max_array().some(function(item) {
842
- return item !== 0;
843
- });
844
- }
845
-
846
- if (someIsNotZero) {
847
- break;
848
- }
849
- }
850
-
851
- return someIsNotZero;
852
- };
853
-
854
- SourceGroup.prototype._createAudioPreview = function(preview, waveformData, redraw) {
855
- if (waveformData.hasAudio) {
856
- var waveform = new WaveformShape({
857
- layer: this._layer,
858
- view: this._view,
859
- source: this._source,
860
- height: preview.group.height(),
861
- url: preview.url
862
- });
863
-
864
- preview.group.add(waveform);
865
- this._addToUnwrap(preview.group);
866
-
867
- if (redraw) {
868
- this._layer.rescale(true);
869
- }
870
-
871
- this._previewList.push(preview);
872
- }
873
- };
874
-
875
- SourceGroup.prototype.getAudioPreview = function() {
876
- return this._previewList.filter(function(preview) {
877
- return preview.type === 'audio';
878
- });
879
- };
880
-
881
- SourceGroup.prototype.setSelected = function() {
882
- this._selected = this._source.selected;
883
- if (this._border) {
884
- if (this._selected) {
885
- this._border.fill(this._source.selectedColor);
886
- this._borderWidth = this._peaks.options.sourceSelectedBorderWidth;
887
- }
888
- else {
889
- this._border.fill(this._source.borderColor);
890
- this._borderWidth = this._source.borderWidth;
891
- }
892
- }
893
- else {
894
- if (this._unwrap) {
895
- // update unwrap
896
- var unwrap_background = this._unwrap.getChildren(function(node) {
897
- return node.getClassName() === 'Shape';
898
- })[0];
899
-
900
- if (unwrap_background) {
901
- if (this._selected) {
902
- unwrap_background.stroke(this._source.selectedColor);
903
- unwrap_background.strokeWidth(this._peaks.options.sourceSelectedBorderWidth);
904
- }
905
- else {
906
- unwrap_background.strokeWidth(0);
907
- }
908
- }
909
- }
910
-
911
- if (this._wrap) {
912
- // update wrap
913
- var wrap_background = this._wrap.getChildren(function(node) {
914
- return node.getClassName() === 'Shape';
915
- })[0];
916
-
917
- if (wrap_background) {
918
- if (this._selected) {
919
- wrap_background.stroke(this._source.selectedColor);
920
- wrap_background.strokeWidth(this._peaks.options.sourceSelectedBorderWidth);
921
- }
922
- else {
923
- wrap_background.strokeWidth(0);
924
- }
925
- }
926
- }
927
- }
928
- };
929
-
930
- SourceGroup.prototype.updatePreviews = function() {
931
- var self = this;
932
-
933
- this._previewList.forEach(function(preview) {
934
- if (preview.loaded) {
935
- switch (preview.type) {
936
- case 'video':
937
- case 'image':
938
- // image or video preview
939
- if (self._unwrappedHeight !== preview.imageData.referenceHeight) {
940
- preview.imageData.referenceHeight = preview.group.height();
941
- preview.imageData.borderSpacing = SPACING_BETWEEN_PREVIEW_AND_BORDER_RATIO
942
- * preview.imageData.referenceHeight;
943
- preview.imageData.height = preview.imageData.referenceHeight
944
- - (2 * preview.imageData.borderSpacing);
945
- preview.imageData.width = preview.imageData.height
946
- * preview.imageData.dimRatio;
947
- preview.imageData.imageSpacing = preview.imageData.width
948
- * SPACING_BETWEEN_PREVIEWS;
949
- }
950
-
951
- var interImageSpacing = preview.imageData.width + preview.imageData.imageSpacing;
952
- var imageNumber;
953
-
954
- if (self._width > preview.imageData.borderSpacing) {
955
- imageNumber = Math.trunc(
956
- (self._width - preview.imageData.borderSpacing)
957
- / interImageSpacing
958
- ) + 1;
959
- }
960
- else {
961
- imageNumber = 0;
962
- }
963
-
964
- var imageList = preview.group.getChildren();
965
-
966
- var i = 0;
967
-
968
- for (i = 0; i < imageNumber; i++) {
969
- if (imageList.length > i) {
970
- imageList[i].visible(true);
971
- }
972
- else {
973
- var imagePreview = new Konva.Image({
974
- x: preview.imageData.borderSpacing + i * interImageSpacing,
975
- y: preview.imageData.borderSpacing,
976
- image: preview.imageData.image,
977
- width: preview.imageData.width,
978
- height: preview.imageData.height,
979
- listening: false,
980
- visible: true
981
- });
982
-
983
- preview.group.add(imagePreview);
984
- }
985
- }
986
-
987
- for (i = imageNumber; i < imageList.length; i++) {
988
- imageList[i].visible(false);
989
- }
990
- }
991
- }
992
- });
993
- };
994
-
995
- SourceGroup.prototype._createImagePreview = function(preview, image, redraw) {
996
- preview.imageData = {
997
- image: image,
998
- referenceHeight: null,
999
- dimRatio: null,
1000
- borderSpacing: null,
1001
- height: null,
1002
- width: null,
1003
- imageSpacing: null
1004
- };
1005
-
1006
- preview.imageData.referenceHeight = preview.group.height();
1007
- preview.imageData.dimRatio = image.width / image.height;
1008
- preview.imageData.borderSpacing = SPACING_BETWEEN_PREVIEW_AND_BORDER_RATIO
1009
- * preview.imageData.referenceHeight;
1010
- preview.imageData.height = preview.imageData.referenceHeight
1011
- - (2 * preview.imageData.borderSpacing);
1012
- preview.imageData.width = preview.imageData.height * preview.imageData.dimRatio;
1013
- preview.imageData.imageSpacing = preview.imageData.width * SPACING_BETWEEN_PREVIEWS;
1014
-
1015
- var currentX = preview.imageData.borderSpacing;
1016
-
1017
- while (currentX < this._width) {
1018
- var imagePreview = new Konva.Image({
1019
- x: currentX,
1020
- y: preview.imageData.borderSpacing,
1021
- image: image,
1022
- width: preview.imageData.width,
1023
- height: preview.imageData.height,
1024
- listening: false
1025
- });
1026
-
1027
- preview.group.add(imagePreview);
1028
-
1029
- currentX += preview.imageData.width + preview.imageData.imageSpacing;
1030
- }
1031
-
1032
- this._addToUnwrap(preview.group);
1033
-
1034
- if (redraw) {
1035
- this._group.draw();
1036
- }
1037
-
1038
- this._previewList.push(preview);
1039
- };
1040
-
1041
- SourceGroup.prototype.setLoadingState = function(isLoading) {
1042
- if (isLoading && !this._loadingOverlay) {
1043
- this._createLoadingOverlay();
1044
- }
1045
- else if (!isLoading && this._loadingOverlay) {
1046
- this._removeLoadingOverlay();
1047
- }
1048
-
1049
- if (this._loadingOverlay) {
1050
- this._loadingOverlay.visible(isLoading);
1051
- }
1052
- };
1053
-
1054
- SourceGroup.prototype._createLoadingOverlay = function() {
1055
- this._loadingOverlay = new Konva.Group({
1056
- x: 0,
1057
- y: 0,
1058
- width: this._width,
1059
- height: this._height,
1060
- listening: false
1061
- });
1062
-
1063
- // Semi-transparent background
1064
- var loadingBackground = new Konva.Rect({
1065
- x: 0,
1066
- y: 0,
1067
- width: this._width,
1068
- height: this._height,
1069
- fill: 'rgba(0, 0, 0, 0.7)'
1070
- });
1071
-
1072
- this._loader = new Loader();
1073
- this._loader.x(this._width / 2);
1074
- this._loader.y(this._height / 2);
1075
-
1076
- // Add overlay to the main group
1077
- this._loadingOverlay.add(loadingBackground);
1078
- this._loader.addTo(this._loadingOverlay);
1079
- this.addToContent(this._loadingOverlay);
1080
- };
1081
-
1082
- SourceGroup.prototype._removeLoadingOverlay = function() {
1083
- if (this._loadingOverlay) {
1084
- if (this._loader) {
1085
- this._loader.destroy();
1086
- this._loader = null;
1087
- }
1088
- this._loadingOverlay.destroy();
1089
- this._loadingOverlay = null;
1090
- }
1091
- };
1092
-
1093
- SourceGroup.prototype._updateLoadingOverlay = function() {
1094
- if (this._loadingOverlay) {
1095
- var self = this;
1096
-
1097
- this._loadingOverlay.width(self._width);
1098
- this._loadingOverlay.height(self._height);
1099
-
1100
- this._loadingOverlay.getChildren().forEach(function(child) {
1101
- if (child instanceof Konva.Rect) {
1102
- child.width(self._width);
1103
- child.height(self._height);
1104
- }
1105
- else {
1106
- child.x(self._width / 2);
1107
- }
1108
- });
1109
- }
1110
- };
1111
-
1112
- SourceGroup.prototype.isWrapped = function() {
1113
- return this._source.wrapped;
1114
- };
1115
-
1116
- SourceGroup.prototype.getCurrentHeight = function() {
1117
- return this._height;
1118
- };
1119
-
1120
- SourceGroup.prototype.getHeights = function() {
1121
- return {
1122
- unwrapped: this._unwrappedHeight,
1123
- wrapped: this._wrappedHeight,
1124
- current: this._height
1125
- };
1126
- };
1127
-
1128
- SourceGroup.prototype.setVisible = function(boolean) {
1129
- this._group.visible(boolean);
1130
- };
1131
-
1132
- SourceGroup.prototype.setListening = function(boolean) {
1133
- this._group.listening(boolean);
1134
- };
1135
-
1136
- SourceGroup.prototype.isVisible = function() {
1137
- return this._group.visible();
1138
- };
1139
-
1140
- SourceGroup.prototype.isCuttable = function() {
1141
- return this._source.cuttable;
1142
- };
1143
-
1144
- SourceGroup.prototype.isDeletable = function() {
1145
- return this._source.deletable;
1146
- };
1147
-
1148
- SourceGroup.prototype.getLine = function() {
1149
- return this._source.position;
1150
- };
1151
-
1152
- SourceGroup.prototype.getAbsoluteBoundingBox = function() {
1153
- var stageContainer = this._group.getStage().container();
1154
- var containerRect = stageContainer.getBoundingClientRect();
1155
-
1156
- var elementPos = this._group.getAbsolutePosition();
1157
-
1158
- return {
1159
- left: containerRect.left + elementPos.x,
1160
- top: containerRect.top + elementPos.y,
1161
- width: this._width,
1162
- height: this._height
1163
- };
1164
- };
1165
-
1166
- SourceGroup.prototype.getButtonBoundingBox = function(buttonId) {
1167
- if (!this._buttonsGroup) {
1168
- return null;
1169
- }
1170
-
1171
- var buttonIdx = this._source.buttons.findIndex(function(button) {
1172
- return button.id === buttonId;
1173
- });
1174
-
1175
- if (buttonIdx === -1) {
1176
- return null;
1177
- }
1178
-
1179
- var button = this._source.buttons[buttonIdx];
1180
- var buttonGroup = this._buttonsGroup.getChildren()[buttonIdx];
1181
- var buttonPos = buttonGroup.getAbsolutePosition(this._group);
1182
-
1183
- return {
1184
- left: buttonPos.x,
1185
- top: buttonPos.y,
1186
- width: button.width,
1187
- height: button.height
1188
- };
1189
- };
1190
-
1191
- SourceGroup.prototype.createIndicators = function() {
1192
- var newIndicatorsColors = this._source.indicators;
1193
-
1194
- var oldIndicators = this._indicators;
1195
- var newIndicators = {};
1196
-
1197
- if (newIndicatorsColors) {
1198
- newIndicatorsColors.forEach(function(indicatorColor) {
1199
- var oldIndicator = oldIndicators[indicatorColor];
1200
-
1201
- if (oldIndicator) {
1202
- newIndicators[indicatorColor] = oldIndicator;
1203
- delete oldIndicators[indicatorColor];
1204
- }
1205
- else {
1206
- newIndicators[indicatorColor] = null;
1207
- }
1208
- });
1209
-
1210
- for (var color in oldIndicators) {
1211
- if (Utils.objectHasProperty(oldIndicators, color)) {
1212
- oldIndicators[color].destroy();
1213
- }
1214
- }
1215
- }
1216
-
1217
- this._indicators = Object.keys(newIndicators)
1218
- .sort()
1219
- .reverse()
1220
- .reduce(function(objEntries, key) {
1221
- objEntries[key] = newIndicators[key];
1222
- return objEntries;
1223
- }, {}
1224
- );
1225
-
1226
- this._createIndicators();
1227
- };
1228
-
1229
- SourceGroup.prototype._createIndicators = function() {
1230
- var currentX = 0;
1231
- var zIndex = 0;
1232
-
1233
- for (var color in this._indicators) {
1234
- if (Utils.objectHasProperty(this._indicators, color)) {
1235
- if (!this._indicators[color]) {
1236
- this._indicators[color] = new Konva.Circle({
1237
- radius: INDICATOR_RADIUS,
1238
- fill: color,
1239
- strokeEnabled: false
1240
- });
1241
- this._indicatorsGroup.add(this._indicators[color]);
1242
- }
1243
-
1244
- this._indicators[color].x(currentX);
1245
- this._indicators[color].zIndex(zIndex);
1246
- currentX -= INDICATOR_RADIUS;
1247
- zIndex += 1;
1248
- }
1249
- }
1250
-
1251
- this._indicatorsGroup.offsetX(currentX - this._peaks.options.sourceIndicatorsXOffset);
1252
- this._indicatorsGroup.offsetY(-this._peaks.options.sourceIndicatorsYOffset);
1253
- };
1254
-
1255
- SourceGroup.prototype._createMarkers = function() {
1256
- const markersGroup = new Konva.Group({
1257
- listening: false
1258
- });
1259
-
1260
- this._source.markers.forEach(function(marker) {
1261
- const markerX = this._view.timeToPixels(marker - this._source.mediaStartTime);
1262
-
1263
- var markerLine = new Konva.Line({
1264
- points: [markerX, 0, markerX, this._unwrappedHeight],
1265
- stroke: this._source.markerColor,
1266
- strokeWidth: this._source.markerWidth
1267
- });
1268
-
1269
- markersGroup.add(markerLine);
1270
- }.bind(this));
1271
-
1272
- return markersGroup;
1273
- };
1274
-
1275
- SourceGroup.prototype._createButtons = function() {
1276
- var buttonsGroup = new Konva.Group({
1277
- listening: true,
1278
- x: this._width,
1279
- visible: false,
1280
- opacity: 0
1281
- });
1282
- var buttonsGroupWidth = 0;
1283
- var buttonsGap = this._peaks.options.sourceButtonsGap;
1284
- var self = this;
1285
-
1286
- this._source.buttons.forEach(function(button) {
1287
- const {
1288
- id,
1289
- width,
1290
- height,
1291
- cornerRadius,
1292
- color,
1293
- hoverColor,
1294
- borderColor,
1295
- borderWidth,
1296
- svg,
1297
- image
1298
- } = button;
1299
-
1300
- if (buttonsGroupWidth > 0) {
1301
- buttonsGroupWidth += buttonsGap;
1302
- }
1303
-
1304
- var buttonGroup = new Konva.Group({
1305
- x: buttonsGroupWidth,
1306
- y: 0,
1307
- listening: true
1308
- });
1309
-
1310
- var buttonRect = new Konva.Rect({
1311
- width: width,
1312
- height: height,
1313
- fill: color,
1314
- stroke: borderColor,
1315
- strokeWidth: borderWidth,
1316
- cornerRadius: cornerRadius
1317
- });
1318
-
1319
- buttonsGroupWidth += width;
1320
-
1321
- buttonGroup.add(buttonRect);
1322
-
1323
- if (svg) {
1324
- var svgIcon = new Konva.Path({
1325
- x: width / 2,
1326
- y: height / 2,
1327
- data: svg.path,
1328
- fill: svg.color,
1329
- offsetX: svg.width / 2,
1330
- offsetY: svg.height / 2,
1331
- listening: false
1332
- });
1333
-
1334
- buttonGroup.add(svgIcon);
1335
- }
1336
- else if (image) {
1337
- var imageObj = new Image();
1338
-
1339
- imageObj.onload = function() {
1340
- var imageIcon = new Konva.Image({
1341
- x: width / 2,
1342
- y: height / 2,
1343
- image: imageObj,
1344
- offsetX: image.width / 2,
1345
- offsetY: image.height / 2,
1346
- listening: false
1347
- });
1348
-
1349
- buttonGroup.add(imageIcon);
1350
- };
1351
-
1352
- imageObj.src = image.data;
1353
- }
1354
-
1355
- buttonGroup.on('mouseover', function() {
1356
- self._view.setClickable(false);
1357
- if (hoverColor) {
1358
- buttonRect.fill(hoverColor);
1359
- }
1360
- self._peaks.emit('source.buttonEnter', self._source, id);
1361
- });
1362
-
1363
- buttonGroup.on('mouseout', function() {
1364
- self._view.setClickable(true);
1365
- if (buttonRect.fill() !== color) {
1366
- buttonRect.fill(color);
1367
- }
1368
- self._peaks.emit('source.buttonLeave', self._source, id);
1369
- });
1370
-
1371
- buttonGroup.on('click', function() {
1372
- self._peaks.emit('source.buttonClicked', self._source, id);
1373
- });
1374
-
1375
- buttonsGroup.add(buttonGroup);
1376
- });
1377
-
1378
- buttonsGroup.offsetX(
1379
- buttonsGroupWidth
1380
- + this._borderWidth
1381
- + this._peaks.options.sourceButtonsPadding
1382
- + this._peaks.options.sourceButtonsXOffset
1383
- );
1384
- buttonsGroup.offsetY(
1385
- -this._borderWidth
1386
- - this._peaks.options.sourceButtonsPadding
1387
- - this._peaks.options.sourceButtonsYOffset
1388
- );
1389
-
1390
- return buttonsGroup;
1391
- };
1392
-
1393
- SourceGroup.prototype._updateMarkers = function() {
1394
- const self = this;
1395
-
1396
- if (this._markersGroup) {
1397
- this._markersGroup.getChildren().forEach(function(markerLine, index) {
1398
- const marker = self._source.markers[index];
1399
- const markerX = self._view.timeToPixels(marker - self._source.mediaStartTime);
1400
-
1401
- markerLine.points([markerX, 0, markerX, self._unwrappedHeight]);
1402
- });
1403
- }
1404
- };
1405
-
1406
- SourceGroup.prototype._updateButtons = function() {
1407
- if (this._buttonsGroup) {
1408
- this._buttonsGroup.x(this._width);
1409
- }
1410
- };
1411
-
1412
- SourceGroup.prototype._getButtons = function() {
1413
- if (!this._buttonsGroup) {
1414
- this._buttonsGroup = this._createButtons();
1415
- }
1416
-
1417
- return this._buttonsGroup;
1418
- };
1419
-
1420
- SourceGroup.prototype._showButtons = function() {
1421
- if (this._buttonsGroup) {
1422
- if (this._buttonsAnimation) {
1423
- this._buttonsAnimation.destroy();
1424
- this._buttonsAnimation = null;
1425
- }
1426
-
1427
- var self = this;
1428
-
1429
- this._buttonsGroup.visible(true);
1430
- this._buttonsAnimation = new Konva.Tween({
1431
- node: this._buttonsGroup,
1432
- opacity: 1,
1433
- duration: 0.2,
1434
- easing: Konva.Easings.EaseOut,
1435
- onFinish: function() {
1436
- self._buttonsAnimation.destroy();
1437
- self._buttonsAnimation = null;
1438
- }
1439
- });
1440
- this._buttonsAnimation.play();
1441
- }
1442
- };
1443
-
1444
- SourceGroup.prototype._hideButtons = function() {
1445
- if (this._buttonsGroup) {
1446
- if (this._buttonsAnimation) {
1447
- this._buttonsAnimation.destroy();
1448
- this._buttonsAnimation = null;
1449
- }
1450
-
1451
- var self = this;
1452
-
1453
- this._buttonsAnimation = new Konva.Tween({
1454
- node: this._buttonsGroup,
1455
- opacity: 0,
1456
- duration: 0.2,
1457
- easing: Konva.Easings.EaseOut,
1458
- onFinish: function() {
1459
- self._buttonsGroup.visible(false);
1460
- self._buttonsAnimation.destroy();
1461
- self._buttonsAnimation = null;
1462
- }
1463
- });
1464
- this._buttonsAnimation.play();
1465
- }
1466
- };
1467
-
1468
- SourceGroup.prototype._getYFromVolume = function(volume) {
1469
- return this._borderWidth + (this._height - 2 * this._borderWidth) * (
1470
- this._source.volumeRange[1] - volume
1471
- ) / (
1472
- this._source.volumeRange[1] - this._source.volumeRange[0]
1473
- );
1474
- };
1475
-
1476
- SourceGroup.prototype._getVolumeFromY = function(y) {
1477
- return this._source.volumeRange[1] - (
1478
- (y - this._borderWidth) / (this._height - 2 * this._borderWidth)
1479
- ) * (
1480
- this._source.volumeRange[1] - this._source.volumeRange[0]
1481
- );
1482
- };
1483
-
1484
- SourceGroup.prototype._updateVolumeSlider = function() {
1485
- const width = this._width;
1486
-
1487
- if (this._volumeSliderGroup) {
1488
- this._volumeSliderGroup.getChildren().forEach(function(child) {
1489
- if (child instanceof Konva.Group) {
1490
- child.width(width);
1491
- child.getChildren().forEach(function(node) {
1492
- if (node instanceof Konva.Line) {
1493
- node.points([0, 0, width, 0]);
1494
- }
1495
- });
1496
- }
1497
- });
1498
- }
1499
- };
1500
-
1501
- SourceGroup.prototype._getVolumeSlider = function() {
1502
- if (!this._volumeSliderGroup) {
1503
- this._volumeSliderGroup = this._createVolumeSlider();
1504
- }
1505
-
1506
- return this._volumeSliderGroup;
1507
- };
1508
-
1509
- SourceGroup.prototype._createVolumeSlider = function() {
1510
- var self = this;
1511
-
1512
- var volumeY = this._getYFromVolume(this._source.volume);
1513
-
1514
- var volumeGroup = new Konva.Group({
1515
- x: 0,
1516
- y: 0
1517
- });
1518
-
1519
- var volumeText = new Konva.Text({
1520
- x: 0,
1521
- y: volumeY - 20,
1522
- text: '100%',
1523
- fontSize: 12,
1524
- fill: this._source.volumeSliderColor,
1525
- visible: false
1526
- });
1527
-
1528
- var maxTextWidth = volumeText.width();
1529
- var maxTextHeight = volumeText.height();
1530
-
1531
- var volumeSliderGroup = new Konva.Group({
1532
- x: 0,
1533
- y: volumeY,
1534
- draggable: true,
1535
- dragBoundFunc: function(pos) {
1536
- var y = Math.min(
1537
- volumeGroup.absolutePosition().y + self._height - self._borderWidth,
1538
- Math.max(
1539
- volumeGroup.absolutePosition().y + self._borderWidth,
1540
- pos.y
1541
- )
1542
- );
1543
-
1544
- var textX = Math.min(
1545
- volumeGroup.absolutePosition().x + self._width - maxTextWidth - self._borderWidth,
1546
- Math.max(
1547
- volumeGroup.absolutePosition().x + self._borderWidth,
1548
- self._view.getPointerPosition().x - maxTextWidth
1549
- )
1550
- );
1551
- var textY = y - (self._source.volumeSliderWidth / 2) - maxTextHeight;
1552
-
1553
- volumeText.absolutePosition({
1554
- x: textX,
1555
- y: textY < volumeGroup.absolutePosition().y + self._borderWidth ?
1556
- y + self._source.volumeSliderWidth :
1557
- textY
1558
- });
1559
-
1560
- return { x: this.absolutePosition().x, y: y };
1561
- }
1562
- });
1563
-
1564
- var volumeSliderLine = new Konva.Line({
1565
- points: [0, 0, this._width, 0],
1566
- stroke: this._source.volumeSliderColor,
1567
- strokeWidth: this._source.volumeSliderWidth
1568
- });
1569
-
1570
- var volumeSliderRect = new Konva.Rect({
1571
- x: 0,
1572
- y: -this._source.volumeSliderDraggingWidth / 2,
1573
- width: this._width,
1574
- height: this._source.volumeSliderDraggingWidth,
1575
- opacity: 0
1576
- });
1577
-
1578
- volumeSliderGroup.add(volumeSliderRect);
1579
- volumeSliderGroup.add(volumeSliderLine);
1580
-
1581
- volumeSliderGroup.on('dragstart', function() {
1582
- volumeText.visible(true);
1583
- });
1584
-
1585
- volumeSliderGroup.on('dragmove', function() {
1586
- var volume = self._getVolumeFromY(volumeSliderGroup.y());
1587
-
1588
- volumeText.text((volume * 100).toFixed(0) + '%');
1589
-
1590
- self._source.volume = Math.max(self._source.volumeRange[0], Math.min(volume, self._source.volumeRange[1]));
1591
- self._peaks.emit('source.volumeChanged', self._source);
1592
-
1593
- self._group.draw();
1594
- });
1595
-
1596
- volumeSliderGroup.on('dragend', function() {
1597
- volumeText.visible(false);
1598
- });
1599
-
1600
- volumeSliderGroup.on('mouseover', function() {
1601
- self._cursor = 'ns-resize';
1602
- });
1603
-
1604
- volumeSliderGroup.on('mouseout', function() {
1605
- self._cursor = null;
1606
- });
1607
-
1608
- volumeGroup.add(volumeSliderGroup);
1609
- volumeGroup.add(volumeText);
1610
-
1611
- return volumeGroup;
1612
- };
1613
-
1614
- SourceGroup.prototype.destroy = function() {
1615
- if (this._buttonsAnimation) {
1616
- this._buttonsAnimation.destroy();
1617
- this._buttonsAnimation = null;
1618
- }
1619
-
1620
- if (this._loader) {
1621
- this._loader.destroy();
1622
- this._loader = null;
1623
- }
1624
-
1625
- this._group.destroy();
1626
- };
1627
-
1628
- /**
1629
- * Static method to get height for a source
1630
- * @param {Source} source - The source object
1631
- * @param {Object} peaks - The peaks instance (for options)
1632
- * @returns {number} The calculated height
1633
- */
1634
- SourceGroup.getHeights = function(source, peaks) {
1635
- var unwrappedHeight = source.binaryHeight && source.previewHeight ?
1636
- source.binaryHeight + source.previewHeight :
1637
- peaks.options.lineHeight;
1638
- var wrappedHeight = peaks.options.wrappedLineHeight;
1639
- var height = source.wrapped ? wrappedHeight : unwrappedHeight;
1640
-
1641
- return {
1642
- unwrapped: unwrappedHeight,
1643
- wrapped: wrappedHeight,
1644
- current: height
1645
- };
1646
- };
1647
-
1648
- return SourceGroup;
1649
- });
1
+ /**
2
+ * @file
3
+ *
4
+ * Defines the {@link SourceGroup} class.
5
+ *
6
+ * @module source-group
7
+ */
8
+
9
+ define([
10
+ './waveform-builder',
11
+ './waveform-shape',
12
+ './loader',
13
+ '../utils',
14
+ 'konva'
15
+ ], function(
16
+ WaveformBuilder,
17
+ WaveformShape,
18
+ Loader,
19
+ Utils,
20
+ Konva) {
21
+ 'use strict';
22
+
23
+ var SPACING_BETWEEN_PREVIEW_AND_BORDER_RATIO = 0.15;
24
+ var SPACING_BETWEEN_PREVIEWS = 1.5;
25
+ var CORNER_RADIUS = 8;
26
+ var INDICATOR_RADIUS = 4; // px
27
+
28
+ /**
29
+ * Creates a source group for the given source.
30
+ *
31
+ * @class
32
+ * @alias SourceGroup
33
+ *
34
+ * @param {Source} source
35
+ * @param {Peaks} peaks
36
+ * @param {SourcesLayer} layer
37
+ * @param {WaveformOverview|WaveformZoomView} view
38
+ */
39
+
40
+ function SourceGroup(source, peaks, layer, view) {
41
+ this._source = source;
42
+ this._peaks = peaks;
43
+ this._layer = layer;
44
+ this._view = view;
45
+ this._indicators = {};
46
+
47
+ var self = this;
48
+
49
+ this._x = this._view.timeToPixels(source.startTime);
50
+ this._width = this._view.timeToPixels(source.endTime - source.startTime);
51
+ var heights = SourceGroup.getHeights(source, peaks);
52
+
53
+ this._unwrappedHeight = heights.unwrapped;
54
+ this._wrappedHeight = heights.wrapped;
55
+ this._height = heights.current;
56
+ this._borderWidth = this._source.borderWidth || 0;
57
+ this._currentTimeToPixelsScaleUsed = this._view.getTimeToPixelsScale();
58
+ this._selected = this._source.selected;
59
+ this._isDragged = false;
60
+
61
+ this._previewList = [];
62
+
63
+ this._markersGroup = this._createMarkers();
64
+
65
+ this._group = new Konva.Group({
66
+ x: this._x,
67
+ sourceId: this._source.id,
68
+ draggable: this._source.draggable,
69
+ dragBoundFunc: function() {
70
+ return self._layer.onSourcesGroupDrag(this);
71
+ },
72
+ clipFunc: function(ctx) {
73
+ self.drawSourceShape(ctx, null);
74
+ }
75
+ });
76
+
77
+ this._group.on('dragstart', this._onDragStart.bind(this));
78
+ this._group.on('dragend', this._onDragEnd.bind(this));
79
+
80
+ this._cursor = null;
81
+ this._group.on('mouseenter', function() {
82
+ self._view.setHoveredElement(self);
83
+ if (!self._source.loading) {
84
+ self._showButtons();
85
+ }
86
+ });
87
+
88
+ this._group.on('mouseleave', function() {
89
+ self._view.setHoveredElement(null);
90
+ self._hideButtons();
91
+ });
92
+
93
+ this._group.on('mouseover', function() {
94
+ if (self._source.draggable) {
95
+ self._view.setCursor(self._cursor || 'pointer');
96
+ }
97
+ if (self._view.getCurrentMode() === 'cut') {
98
+ self.toggleDragging(false);
99
+ self.toggleResizing(false);
100
+ }
101
+ });
102
+
103
+ this._group.on('mouseout', function() {
104
+ self._view.setCursor('default');
105
+ if (self._view.getCurrentMode() === 'cut') {
106
+ self.toggleDragging(true);
107
+ self.toggleResizing(true);
108
+ }
109
+ });
110
+
111
+ this._group.add(new Konva.Group());
112
+
113
+ if (this._borderWidth) {
114
+ this._border = new Konva.Shape({
115
+ fill: this._source.borderColor,
116
+ sceneFunc: function(ctx, shape) {
117
+ self.drawSourceShape(ctx, shape);
118
+ }
119
+ });
120
+ this._group.getChildren()[0].add(this._border);
121
+ }
122
+ this._addHandles();
123
+
124
+ this.setWrapping(source.wrapped);
125
+
126
+ this.setSelected();
127
+
128
+ this._indicatorsGroup = new Konva.Group();
129
+ this.addToContent(this._indicatorsGroup);
130
+
131
+ this.createIndicators();
132
+
133
+ this.setLoadingState(this._source.loading);
134
+ }
135
+
136
+ SourceGroup.prototype._onDragStart = function(element) {
137
+ this._isDragged = true;
138
+ this._layer.onSourcesGroupDragStart(element);
139
+ };
140
+
141
+ SourceGroup.prototype._onDragEnd = function(element) {
142
+ this._isDragged = false;
143
+ this._layer.onSourcesGroupDragEnd(element);
144
+ };
145
+
146
+ SourceGroup.prototype.isActive = function() {
147
+ return this._isDragged;
148
+ };
149
+
150
+ SourceGroup.prototype.addToContent = function(newChild) {
151
+ if (this._source.wrapped) {
152
+ this._wrap.add(newChild);
153
+ }
154
+ else {
155
+ this._unwrap.add(newChild);
156
+ }
157
+ };
158
+
159
+ SourceGroup.prototype.prepareDragEnd = function() {
160
+ var handleWidth = Math.min(this._peaks.options.sourceHandleWidth, this._width / 2);
161
+
162
+ this._leftHandle.width(handleWidth);
163
+ this._rightHandle.width(handleWidth);
164
+ this._rightHandle.x(this._width - handleWidth);
165
+ };
166
+
167
+ SourceGroup.prototype._onSourceGroupHandleDrag = function(draggedElement, dragPos, leftHandle) {
168
+ const diff = this._view.pixelsToTime(dragPos.x - this._mouseDownX);
169
+ const timeOffsetDiff = this._view.getTimeOffset() - this._initialTimeOffset;
170
+
171
+ const { start, end } = this._initialTimes;
172
+
173
+ this._view.updateWithAutoScroll(
174
+ function() {
175
+ if (this._layer.manageSourceMovements(
176
+ [this._source],
177
+ leftHandle ? start + diff + timeOffsetDiff : null,
178
+ leftHandle ? null : end + diff + timeOffsetDiff
179
+ )) {
180
+ this._layer.draw();
181
+ }
182
+ }.bind(this)
183
+ );
184
+
185
+ return {
186
+ x: draggedElement.absolutePosition().x,
187
+ y: draggedElement.absolutePosition().y
188
+ };
189
+ };
190
+
191
+ SourceGroup.prototype.update = function() {
192
+ const startPixel = this._view.timeToPixels(this._source.startTime);
193
+ const endPixel = this._view.timeToPixels(this._source.endTime);
194
+ const frameOffset = this._view.timeToPixels(this._view.getTimeOffset());
195
+ const newTimeToPixelsScale = this._view.getTimeToPixelsScale();
196
+
197
+ this._group.x(startPixel - frameOffset);
198
+
199
+ this._x = startPixel;
200
+
201
+ const newWidth = endPixel - startPixel;
202
+
203
+ if (newWidth !== this._width) {
204
+ this._width = newWidth;
205
+
206
+ // the zoom was changed
207
+ if (newTimeToPixelsScale !== this._currentTimeToPixelsScaleUsed) {
208
+ this._currentTimeToPixelsScaleUsed = newTimeToPixelsScale;
209
+
210
+ this._updateMarkers();
211
+
212
+ this._rightHandle.x(this._width - this._rightHandle.width());
213
+ }
214
+ else {
215
+ // the zoom was not changed, but the source was resized
216
+ const newTitle = Utils.removeLineBreaks(this._source.getVisibleTitle());
217
+
218
+ if (this._wrappedTitle && this._wrappedTitle.text() !== newTitle) {
219
+ this._wrap.add(this._createTitle(true));
220
+ }
221
+ if (this._unwrappedTitle && this._unwrappedTitle.text() !== newTitle) {
222
+ this._unwrap.add(this._createTitle(false));
223
+ }
224
+ }
225
+
226
+ this._updateVolumeSlider();
227
+ this._updateButtons();
228
+ this._updateLoadingOverlay();
229
+
230
+ // update unwrap
231
+ this.updatePreviews();
232
+ }
233
+ };
234
+
235
+ SourceGroup.prototype.setWrapping = function(wrap, forceCreate, notify) {
236
+ if (wrap) {
237
+ this._removeUnwrap();
238
+ this._height = this._wrappedHeight;
239
+ this._addWrap(forceCreate);
240
+ }
241
+ else {
242
+ this._removeWrap();
243
+ this._height = this._unwrappedHeight;
244
+ this._addUnwrap(forceCreate);
245
+ }
246
+
247
+ this.setHandlesWrapping(wrap);
248
+
249
+ if (notify) {
250
+ this._peaks.emit('source.wrappingChanged', this);
251
+ }
252
+ };
253
+
254
+ SourceGroup.prototype.setHandlesWrapping = function(wrap) {
255
+ if (wrap) {
256
+ this._leftHandle.height(this._wrappedHeight);
257
+ this._rightHandle.height(this._wrappedHeight);
258
+ }
259
+ else {
260
+ this._leftHandle.height(this._unwrappedHeight);
261
+ this._rightHandle.height(this._unwrappedHeight);
262
+ }
263
+ };
264
+
265
+ SourceGroup.prototype._onHandleDragStart = function() {
266
+ this._initialTimeOffset = this._view.getTimeOffset();
267
+ this._mouseDownX = this._view.getPointerPosition().x;
268
+ this._initialTimes = {
269
+ start: this._source.startTime,
270
+ end: this._source.endTime
271
+ };
272
+ this._isDragged = true;
273
+
274
+ this._hideButtons();
275
+ };
276
+
277
+ SourceGroup.prototype._onHandleDragEnd = function() {
278
+ this._isDragged = false;
279
+ this._showButtons();
280
+ };
281
+
282
+ SourceGroup.prototype._addHandles = function(forceCreate) {
283
+ var self = this;
284
+ var handleWidth = Math.min(this._peaks.options.sourceHandleWidth, this._width / 2);
285
+
286
+ if (!this._leftHandle || forceCreate) {
287
+ this._leftHandle = new Konva.Rect({
288
+ x: 0,
289
+ width: handleWidth,
290
+ height: this._unwrappedHeight,
291
+ visible: true,
292
+ draggable: this._source.resizable,
293
+ dragBoundFunc: function(pos) {
294
+ return self._onSourceGroupHandleDrag(this, pos, true);
295
+ }
296
+ });
297
+
298
+ this._leftHandle.on('dragstart', this._onHandleDragStart.bind(this));
299
+
300
+ this._leftHandle.on('dragend', this._onHandleDragEnd.bind(this));
301
+
302
+ if (this._source.resizable) {
303
+ this._leftHandle.on('mouseover', function() {
304
+ self._cursor = 'ew-resize';
305
+ });
306
+
307
+ this._leftHandle.on('mouseout', function() {
308
+ self._cursor = null;
309
+ });
310
+ }
311
+ }
312
+
313
+ if (!this._rightHandle || forceCreate) {
314
+ this._rightHandle = new Konva.Rect({
315
+ x: this._width - handleWidth,
316
+ width: handleWidth,
317
+ height: this._unwrappedHeight,
318
+ visible: true,
319
+ draggable: this._source.resizable,
320
+ dragBoundFunc: function(pos) {
321
+ return self._onSourceGroupHandleDrag(this, pos, false);
322
+ }
323
+ });
324
+
325
+ this._rightHandle.on('dragstart', this._onHandleDragStart.bind(this));
326
+
327
+ this._rightHandle.on('dragend', this._onHandleDragEnd.bind(this));
328
+
329
+ if (this._source.resizable) {
330
+ this._rightHandle.on('mouseover', function() {
331
+ self._cursor = 'ew-resize';
332
+ });
333
+
334
+ this._rightHandle.on('mouseout', function() {
335
+ self._cursor = null;
336
+ });
337
+ }
338
+ }
339
+
340
+ this._group.add(this._leftHandle);
341
+ this._group.add(this._rightHandle);
342
+ };
343
+
344
+ SourceGroup.prototype.toggleDragging = function(bool) {
345
+ var background;
346
+
347
+ if (this._wrap) {
348
+ background = this._wrap.getChildren(function(node) {
349
+ return node.getClassName() === 'Shape';
350
+ })[0];
351
+
352
+ if (background) {
353
+ background.draggable(bool);
354
+ }
355
+ }
356
+ if (this._unwrap) {
357
+ background = this._unwrap.getChildren(function(node) {
358
+ return node.getClassName() === 'Shape';
359
+ })[0];
360
+
361
+ if (background) {
362
+ background.draggable(bool);
363
+ }
364
+ }
365
+ };
366
+
367
+ SourceGroup.prototype.toggleResizing = function(bool) {
368
+ if (this._leftHandle) {
369
+ this._leftHandle.draggable(bool);
370
+ }
371
+ if (this._rightHandle) {
372
+ this._rightHandle.draggable(bool);
373
+ }
374
+ };
375
+
376
+ SourceGroup.prototype.drawSourceShape = function(ctx, shape, addBorderWidth, fill) {
377
+ var offset = addBorderWidth ? this._borderWidth : 0;
378
+ var radius = !Utils.isNullOrUndefined(this._source.borderRadius) ?
379
+ this._source.borderRadius :
380
+ Math.max(
381
+ 1,
382
+ Math.min(
383
+ this._width / 2,
384
+ Math.min(
385
+ CORNER_RADIUS,
386
+ this._height / 2
387
+ )
388
+ )
389
+ );
390
+ var x = Math.max(
391
+ 0,
392
+ this._view.getFrameOffset() - this._x - 2 * radius
393
+ );
394
+ var width = Math.min(
395
+ this._width - x,
396
+ this._view.getWidth() + 4 * radius - Math.max(
397
+ 0,
398
+ this._x - this._view.getFrameOffset()
399
+ )
400
+ );
401
+ var xWidth = x + width;
402
+
403
+ if (width > 0) {
404
+ ctx.beginPath();
405
+ ctx.moveTo(x + radius, offset);
406
+ ctx.lineTo(xWidth - radius, offset);
407
+ ctx.quadraticCurveTo(xWidth - offset, offset, xWidth - offset, radius);
408
+ ctx.lineTo(xWidth - offset, this._height - radius);
409
+ ctx.quadraticCurveTo(
410
+ xWidth - offset,
411
+ this._height - offset,
412
+ xWidth - radius,
413
+ this._height - offset
414
+ );
415
+ ctx.lineTo(x + radius, this._height - offset);
416
+ ctx.quadraticCurveTo(x + offset, this._height - offset, x + offset, this._height - radius);
417
+ ctx.lineTo(x + offset, radius);
418
+ ctx.quadraticCurveTo(x + offset, offset, x + radius, offset);
419
+ ctx.closePath();
420
+
421
+ if (fill) {
422
+ if (this._source.shouldShowWarning()) {
423
+ var gradient = ctx.createLinearGradient(0, 0, this._width, 0);
424
+
425
+ if (this._source.mediaEndTime < this._source.duration) {
426
+ var rightStopPosition = Math.max(1 - (this._source.warningWidth / this._width), 0.5);
427
+
428
+ gradient.addColorStop(rightStopPosition, this._source.backgroundColor);
429
+ gradient.addColorStop(1, this._source.warningColor);
430
+ }
431
+
432
+ if (this._source.mediaStartTime > 0) {
433
+ var leftStopPosition = Math.min(this._source.warningWidth / this._width, 0.5);
434
+
435
+ gradient.addColorStop(0, this._source.warningColor);
436
+ gradient.addColorStop(leftStopPosition, this._source.backgroundColor);
437
+ }
438
+
439
+ ctx.fillStyle = gradient;
440
+ ctx.fill();
441
+ }
442
+ else {
443
+ ctx.fillStyle = this._source.backgroundColor;
444
+ ctx.fill();
445
+ }
446
+ }
447
+
448
+ if (shape) {
449
+ ctx.fillStrokeShape(shape);
450
+ }
451
+ }
452
+ };
453
+
454
+ SourceGroup.prototype._addUnwrap = function(forceCreate) {
455
+ if (!this._unwrap || forceCreate) {
456
+ this._unwrap = this._createUnwrap();
457
+ }
458
+
459
+ this._group.getChildren()[0].add(this._unwrap);
460
+ };
461
+
462
+ SourceGroup.prototype._createUnwrap = function() {
463
+ var self = this;
464
+
465
+ var unwrap = new Konva.Group({
466
+ width: this._width,
467
+ height: this._unwrappedHeight,
468
+ clipFunc: function(ctx) {
469
+ self.drawSourceShape(ctx, null, true);
470
+ }
471
+ });
472
+
473
+ var background = new Konva.Group();
474
+
475
+ background.add(new Konva.Shape({
476
+ sceneFunc: function(ctx, shape) {
477
+ self.drawSourceShape(ctx, shape, true, true);
478
+ }
479
+ }));
480
+
481
+ unwrap.add(background);
482
+ unwrap.add(this._markersGroup);
483
+ if (this._source.volumeRange && this._source.volume !== undefined) {
484
+ unwrap.add(this._getVolumeSlider());
485
+ }
486
+ if (this._source.buttons.length > 0) {
487
+ unwrap.add(this._getButtons());
488
+ }
489
+ unwrap.add(this._createTitle(false));
490
+
491
+ return unwrap;
492
+ };
493
+
494
+ SourceGroup.prototype._addToUnwrap = function(element, inForeground) {
495
+ if (inForeground) {
496
+ this._unwrap.add(element);
497
+ }
498
+ else {
499
+ this._unwrap.getChildren()[0].add(element);
500
+ }
501
+ };
502
+
503
+ SourceGroup.prototype._removeUnwrap = function() {
504
+ if (this._unwrap) {
505
+ this._unwrap.remove();
506
+ }
507
+ };
508
+
509
+ SourceGroup.prototype._addWrap = function(forceCreate) {
510
+ if (!this._wrap || forceCreate) {
511
+ this._wrap = this._createWrap();
512
+ }
513
+
514
+ this._group.getChildren()[0].add(this._wrap);
515
+ };
516
+
517
+ SourceGroup.prototype._createWrap = function() {
518
+ var self = this;
519
+
520
+ var wrap = new Konva.Group({
521
+ width: this._width,
522
+ height: this._wrappedHeight,
523
+ clipFunc: function(ctx) {
524
+ self.drawSourceShape(ctx, null, true);
525
+ }
526
+ });
527
+
528
+ var background = new Konva.Group();
529
+
530
+ background.add(new Konva.Shape({
531
+ sceneFunc: function(ctx, shape) {
532
+ self.drawSourceShape(ctx, shape, true, true);
533
+ }
534
+ }));
535
+
536
+ wrap.add(background);
537
+ wrap.add(this._markersGroup);
538
+ if (this._source.volumeRange && this._source.volume !== undefined) {
539
+ wrap.add(this._getVolumeSlider());
540
+ }
541
+ if (this._source.buttons.length > 0) {
542
+ wrap.add(this._getButtons());
543
+ }
544
+ wrap.add(this._createTitle(true));
545
+
546
+ return wrap;
547
+ };
548
+
549
+ SourceGroup.prototype._addToWrap = function(element, inForeground) {
550
+ if (inForeground) {
551
+ this._wrap.add(element);
552
+ }
553
+ else {
554
+ this._wrap.getChildren()[0].add(element);
555
+ }
556
+ };
557
+
558
+ SourceGroup.prototype._removeWrap = function() {
559
+ if (this._wrap) {
560
+ this._wrap.remove();
561
+ }
562
+ };
563
+
564
+ SourceGroup.prototype._createTitle = function(isWrap) {
565
+ var self = this;
566
+ var defaultWidth;
567
+ var y = (this._source.textPosition === 'bottom') ?
568
+ Math.max(
569
+ (isWrap ? this._wrappedHeight : this._unwrappedHeight)
570
+ - this._source.textFontSize - this._peaks.options.sourceTextYOffset,
571
+ this._peaks.options.sourceTextYOffset
572
+ ) : this._peaks.options.sourceTextYOffset;
573
+ var defaultXOffset = this._peaks.options.sourceTextXOffset;
574
+ var maxXOffset = this._width - 2 * defaultXOffset;
575
+
576
+ if (isWrap) {
577
+ if (this._wrappedTitle) {
578
+ this._wrappedTitle.destroy();
579
+ this._wrappedTitle = null;
580
+ }
581
+ }
582
+ else {
583
+ if (this._unwrappedTitle) {
584
+ this._unwrappedTitle.destroy();
585
+ this._unwrappedTitle = null;
586
+ }
587
+ }
588
+
589
+ var title = new Konva.Text({
590
+ x: defaultXOffset,
591
+ y: y,
592
+ text: Utils.removeLineBreaks(this._source.getVisibleTitle()),
593
+ textAlign: 'left',
594
+ verticalAlign: 'middle',
595
+ fontSize: this._source.textFontSize,
596
+ fontFamily: this._source.textFont,
597
+ fill: this._source.textColor,
598
+ wrap: 'none',
599
+ ellipsis: true,
600
+ listening: false,
601
+ sceneFunc: function(context, shape) {
602
+ var absX = this.absolutePosition().x;
603
+
604
+ if (self._source.textAutoScroll && absX < defaultXOffset) {
605
+ this.offsetX(Math.max(Math.min(0, absX - defaultXOffset), -(maxXOffset - shape.width())));
606
+ }
607
+ defaultWidth = defaultWidth ? defaultWidth : shape.width();
608
+ shape.width(Math.min(self._width - 10, defaultWidth));
609
+ if (self._source.textBackgroundColor) {
610
+ context.fillStyle = self._source.textBackgroundColor;
611
+ context.fillRect(-5, -5, shape.width() + 10, shape.height() ? shape.height() + 10 : 0);
612
+ }
613
+ shape._sceneFunc(context);
614
+ }
615
+ });
616
+
617
+ if (isWrap) {
618
+ this._wrappedTitle = title;
619
+ }
620
+ else {
621
+ this._unwrappedTitle = title;
622
+ }
623
+
624
+ return title;
625
+ };
626
+
627
+ SourceGroup.prototype.getWidth = function() {
628
+ return this._width;
629
+ };
630
+
631
+ SourceGroup.prototype.getX = function() {
632
+ return this._x;
633
+ };
634
+
635
+ SourceGroup.prototype.getAbsoluteY = function() {
636
+ return this._group.absolutePosition().y;
637
+ };
638
+
639
+ SourceGroup.prototype.x = function(value) {
640
+ if (typeof value !== 'number') {
641
+ return this._group.x();
642
+ }
643
+ return this._group.x(value);
644
+ };
645
+
646
+ SourceGroup.prototype.y = function(value) {
647
+ if (typeof value !== 'number') {
648
+ return this._group.y();
649
+ }
650
+ return this._group.y(value);
651
+ };
652
+
653
+ SourceGroup.prototype.getSource = function() {
654
+ return this._source;
655
+ };
656
+
657
+ SourceGroup.prototype.startDrag = function() {
658
+ return this._group.startDrag();
659
+ };
660
+
661
+ SourceGroup.prototype.stopDrag = function() {
662
+ return this._group.stopDrag();
663
+ };
664
+
665
+ SourceGroup.prototype.moveTo = function(group) {
666
+ this._group.moveTo(group);
667
+ };
668
+
669
+ SourceGroup.prototype.isDescendantOf = function(group) {
670
+ return group.isAncestorOf(this._group);
671
+ };
672
+
673
+ SourceGroup.prototype.hideButKeepFocus = function() {
674
+ this._group.moveTo(this._view.getTempLayer());
675
+ };
676
+
677
+ SourceGroup.prototype.getParent = function() {
678
+ return this._group.getParent();
679
+ };
680
+
681
+ SourceGroup.prototype.remove = function() {
682
+ this._group.remove();
683
+ };
684
+
685
+ SourceGroup.prototype.addImagePreview = function(content, url, redraw) {
686
+ var preview = {
687
+ type: 'image',
688
+ group: new Konva.Group({
689
+ height: this._unwrappedHeight,
690
+ listening: false
691
+ })
692
+ };
693
+
694
+ var imageData = this._layer.getLoadedData(url);
695
+
696
+ if (!imageData) {
697
+ imageData = new Image();
698
+
699
+ var self = this;
700
+
701
+ imageData.onload = function() {
702
+ self._layer.setLoadedData(url, this);
703
+ preview.loaded = true;
704
+ self._createImagePreview(preview, imageData, redraw);
705
+ };
706
+
707
+ imageData.src = content;
708
+ }
709
+ else {
710
+ preview.loaded = true;
711
+ this._createImagePreview(preview, imageData, redraw);
712
+ }
713
+ };
714
+
715
+ SourceGroup.prototype.addVideoPreview = function(content, url, redraw) {
716
+ var preview = {
717
+ type: 'video',
718
+ group: new Konva.Group({
719
+ y: this._source.binaryUrl && this._source.previewUrl ? this._source.binaryHeight : 0,
720
+ height: this._source.binaryUrl && this._source.previewUrl ?
721
+ this._source.previewHeight : this._unwrappedHeight,
722
+ listening: false
723
+ })
724
+ };
725
+
726
+ var imageData = this._layer.getLoadedData(url);
727
+
728
+ if (!imageData) {
729
+ var video = document.createElement('video');
730
+ var self = this;
731
+
732
+ video.onloadeddata = function() {
733
+ this.currentTime = this.duration / 2;
734
+
735
+ var canvas = document.createElement('canvas');
736
+
737
+ canvas.width = this.videoWidth;
738
+ canvas.height = this.videoHeight;
739
+ canvas.getContext('2d').drawImage(this, 0, 0, canvas.width, canvas.height);
740
+
741
+ imageData = new Image();
742
+
743
+ imageData.onload = function() {
744
+ self._layer.setLoadedData(url, this);
745
+ preview.loaded = true;
746
+ self._createImagePreview(preview, imageData, redraw);
747
+ };
748
+
749
+ imageData.src = canvas.toDataURL();
750
+ };
751
+
752
+ video.src = content;
753
+ }
754
+ else {
755
+ preview.loaded = true;
756
+ this._createImagePreview(preview, imageData, redraw);
757
+ }
758
+ };
759
+
760
+ SourceGroup.prototype.addAudioPreview = function(type, content, url, redraw) {
761
+ var preview = {
762
+ type: 'audio',
763
+ group: new Konva.Group({
764
+ height: this._source.binaryUrl && this._source.previewUrl ?
765
+ this._source.binaryHeight : this._unwrappedHeight,
766
+ listening: false
767
+ }),
768
+ url: url
769
+ };
770
+
771
+ var self = this;
772
+
773
+ var audioData = this._layer.getLoadedData(url);
774
+
775
+ if (!audioData) {
776
+ var waveformBuilder = new WaveformBuilder(this._peaks);
777
+ var options = Object.assign({},this._peaks.options);
778
+
779
+ if (type === 'audio') {
780
+ options.objectUrl = content;
781
+ }
782
+ else {
783
+ options.dataUri = content;
784
+ }
785
+
786
+ waveformBuilder.init(options, function(err, originalWaveformData) {
787
+ if (err) {
788
+ throw err;
789
+ }
790
+
791
+ originalWaveformData.hasAudio = self._hasAudio(originalWaveformData);
792
+
793
+ if (originalWaveformData.hasAudio) {
794
+ var newScale = originalWaveformData.sample_rate / self._view.getTimeToPixelsMaxZoom();
795
+
796
+ if (newScale > originalWaveformData.scale) {
797
+ self._minScale = newScale;
798
+ }
799
+ else {
800
+ self._minScale = originalWaveformData.scale;
801
+ }
802
+
803
+ self._view.setTimeToPixelsMaxZoom(originalWaveformData.sample_rate / self._minScale);
804
+ }
805
+
806
+ self._layer.setLoadedData(url, originalWaveformData);
807
+ self._layer.setLoadedData(
808
+ url + '-scaled',
809
+ { data: originalWaveformData, scale: originalWaveformData.sample_rate / self._minScale }
810
+ );
811
+ preview.loaded = true;
812
+ self._createAudioPreview(preview, originalWaveformData, redraw);
813
+ });
814
+ }
815
+ else {
816
+ preview.loaded = true;
817
+ this._createAudioPreview(preview, audioData, redraw);
818
+ }
819
+ };
820
+
821
+ SourceGroup.prototype._hasAudio = function(waveformData) {
822
+ var channels = waveformData.channels;
823
+ var channel, someIsNotZero = false;
824
+
825
+ for (var i = 0; i < channels; i++) {
826
+ channel = waveformData.channel(i);
827
+
828
+ someIsNotZero = channel.min_array().some(function(item) {
829
+ return item !== 0;
830
+ });
831
+
832
+ if (!someIsNotZero) {
833
+ someIsNotZero = channel.max_array().some(function(item) {
834
+ return item !== 0;
835
+ });
836
+ }
837
+
838
+ if (someIsNotZero) {
839
+ break;
840
+ }
841
+ }
842
+
843
+ return someIsNotZero;
844
+ };
845
+
846
+ SourceGroup.prototype._createAudioPreview = function(preview, waveformData, redraw) {
847
+ if (waveformData.hasAudio) {
848
+ var waveform = new WaveformShape({
849
+ layer: this._layer,
850
+ view: this._view,
851
+ source: this._source,
852
+ height: preview.group.height(),
853
+ url: preview.url
854
+ });
855
+
856
+ preview.group.add(waveform);
857
+ this._addToUnwrap(preview.group);
858
+
859
+ if (redraw) {
860
+ this._layer.rescale(true);
861
+ }
862
+
863
+ this._previewList.push(preview);
864
+ }
865
+ };
866
+
867
+ SourceGroup.prototype.getAudioPreview = function() {
868
+ return this._previewList.filter(function(preview) {
869
+ return preview.type === 'audio';
870
+ });
871
+ };
872
+
873
+ SourceGroup.prototype.setSelected = function() {
874
+ this._selected = this._source.selected;
875
+ if (this._border) {
876
+ if (this._selected) {
877
+ this._border.fill(this._source.selectedColor);
878
+ this._borderWidth = this._peaks.options.sourceSelectedBorderWidth;
879
+ }
880
+ else {
881
+ this._border.fill(this._source.borderColor);
882
+ this._borderWidth = this._source.borderWidth;
883
+ }
884
+ }
885
+ else {
886
+ if (this._unwrap) {
887
+ // update unwrap
888
+ var unwrap_background = this._unwrap.getChildren(function(node) {
889
+ return node.getClassName() === 'Shape';
890
+ })[0];
891
+
892
+ if (unwrap_background) {
893
+ if (this._selected) {
894
+ unwrap_background.stroke(this._source.selectedColor);
895
+ unwrap_background.strokeWidth(this._peaks.options.sourceSelectedBorderWidth);
896
+ }
897
+ else {
898
+ unwrap_background.strokeWidth(0);
899
+ }
900
+ }
901
+ }
902
+
903
+ if (this._wrap) {
904
+ // update wrap
905
+ var wrap_background = this._wrap.getChildren(function(node) {
906
+ return node.getClassName() === 'Shape';
907
+ })[0];
908
+
909
+ if (wrap_background) {
910
+ if (this._selected) {
911
+ wrap_background.stroke(this._source.selectedColor);
912
+ wrap_background.strokeWidth(this._peaks.options.sourceSelectedBorderWidth);
913
+ }
914
+ else {
915
+ wrap_background.strokeWidth(0);
916
+ }
917
+ }
918
+ }
919
+ }
920
+ };
921
+
922
+ SourceGroup.prototype.updatePreviews = function() {
923
+ var self = this;
924
+
925
+ this._previewList.forEach(function(preview) {
926
+ if (preview.loaded) {
927
+ switch (preview.type) {
928
+ case 'video':
929
+ case 'image':
930
+ // image or video preview
931
+ if (self._unwrappedHeight !== preview.imageData.referenceHeight) {
932
+ preview.imageData.referenceHeight = preview.group.height();
933
+ preview.imageData.borderSpacing = SPACING_BETWEEN_PREVIEW_AND_BORDER_RATIO
934
+ * preview.imageData.referenceHeight;
935
+ preview.imageData.height = preview.imageData.referenceHeight
936
+ - (2 * preview.imageData.borderSpacing);
937
+ preview.imageData.width = preview.imageData.height
938
+ * preview.imageData.dimRatio;
939
+ preview.imageData.imageSpacing = preview.imageData.width
940
+ * SPACING_BETWEEN_PREVIEWS;
941
+ }
942
+
943
+ var interImageSpacing = preview.imageData.width + preview.imageData.imageSpacing;
944
+ var imageNumber;
945
+
946
+ if (self._width > preview.imageData.borderSpacing) {
947
+ imageNumber = Math.trunc(
948
+ (self._width - preview.imageData.borderSpacing)
949
+ / interImageSpacing
950
+ ) + 1;
951
+ }
952
+ else {
953
+ imageNumber = 0;
954
+ }
955
+
956
+ var imageList = preview.group.getChildren();
957
+
958
+ var i = 0;
959
+
960
+ for (i = 0; i < imageNumber; i++) {
961
+ if (imageList.length > i) {
962
+ imageList[i].visible(true);
963
+ }
964
+ else {
965
+ var imagePreview = new Konva.Image({
966
+ x: preview.imageData.borderSpacing + i * interImageSpacing,
967
+ y: preview.imageData.borderSpacing,
968
+ image: preview.imageData.image,
969
+ width: preview.imageData.width,
970
+ height: preview.imageData.height,
971
+ listening: false,
972
+ visible: true
973
+ });
974
+
975
+ preview.group.add(imagePreview);
976
+ }
977
+ }
978
+
979
+ for (i = imageNumber; i < imageList.length; i++) {
980
+ imageList[i].visible(false);
981
+ }
982
+ }
983
+ }
984
+ });
985
+ };
986
+
987
+ SourceGroup.prototype._createImagePreview = function(preview, image, redraw) {
988
+ preview.imageData = {
989
+ image: image,
990
+ referenceHeight: null,
991
+ dimRatio: null,
992
+ borderSpacing: null,
993
+ height: null,
994
+ width: null,
995
+ imageSpacing: null
996
+ };
997
+
998
+ preview.imageData.referenceHeight = preview.group.height();
999
+ preview.imageData.dimRatio = image.width / image.height;
1000
+ preview.imageData.borderSpacing = SPACING_BETWEEN_PREVIEW_AND_BORDER_RATIO
1001
+ * preview.imageData.referenceHeight;
1002
+ preview.imageData.height = preview.imageData.referenceHeight
1003
+ - (2 * preview.imageData.borderSpacing);
1004
+ preview.imageData.width = preview.imageData.height * preview.imageData.dimRatio;
1005
+ preview.imageData.imageSpacing = preview.imageData.width * SPACING_BETWEEN_PREVIEWS;
1006
+
1007
+ var currentX = preview.imageData.borderSpacing;
1008
+
1009
+ while (currentX < this._width) {
1010
+ var imagePreview = new Konva.Image({
1011
+ x: currentX,
1012
+ y: preview.imageData.borderSpacing,
1013
+ image: image,
1014
+ width: preview.imageData.width,
1015
+ height: preview.imageData.height,
1016
+ listening: false
1017
+ });
1018
+
1019
+ preview.group.add(imagePreview);
1020
+
1021
+ currentX += preview.imageData.width + preview.imageData.imageSpacing;
1022
+ }
1023
+
1024
+ this._addToUnwrap(preview.group);
1025
+
1026
+ if (redraw) {
1027
+ this._group.draw();
1028
+ }
1029
+
1030
+ this._previewList.push(preview);
1031
+ };
1032
+
1033
+ SourceGroup.prototype.setLoadingState = function(isLoading) {
1034
+ if (isLoading && !this._loadingOverlay) {
1035
+ this._createLoadingOverlay();
1036
+ }
1037
+ else if (!isLoading && this._loadingOverlay) {
1038
+ this._removeLoadingOverlay();
1039
+ }
1040
+
1041
+ if (this._loadingOverlay) {
1042
+ this._loadingOverlay.visible(isLoading);
1043
+ }
1044
+ };
1045
+
1046
+ SourceGroup.prototype._createLoadingOverlay = function() {
1047
+ this._loadingOverlay = new Konva.Group({
1048
+ x: 0,
1049
+ y: 0,
1050
+ width: this._width,
1051
+ height: this._height,
1052
+ listening: false
1053
+ });
1054
+
1055
+ // Semi-transparent background
1056
+ var loadingBackground = new Konva.Rect({
1057
+ x: 0,
1058
+ y: 0,
1059
+ width: this._width,
1060
+ height: this._height,
1061
+ fill: 'rgba(0, 0, 0, 0.7)'
1062
+ });
1063
+
1064
+ this._loader = new Loader();
1065
+ this._loader.x(this._width / 2);
1066
+ this._loader.y(this._height / 2);
1067
+
1068
+ // Add overlay to the main group
1069
+ this._loadingOverlay.add(loadingBackground);
1070
+ this._loader.addTo(this._loadingOverlay);
1071
+ this.addToContent(this._loadingOverlay);
1072
+ };
1073
+
1074
+ SourceGroup.prototype._removeLoadingOverlay = function() {
1075
+ if (this._loadingOverlay) {
1076
+ if (this._loader) {
1077
+ this._loader.destroy();
1078
+ this._loader = null;
1079
+ }
1080
+ this._loadingOverlay.destroy();
1081
+ this._loadingOverlay = null;
1082
+ }
1083
+ };
1084
+
1085
+ SourceGroup.prototype._updateLoadingOverlay = function() {
1086
+ if (this._loadingOverlay) {
1087
+ var self = this;
1088
+
1089
+ this._loadingOverlay.width(self._width);
1090
+ this._loadingOverlay.height(self._height);
1091
+
1092
+ this._loadingOverlay.getChildren().forEach(function(child) {
1093
+ if (child instanceof Konva.Rect) {
1094
+ child.width(self._width);
1095
+ child.height(self._height);
1096
+ }
1097
+ else {
1098
+ child.x(self._width / 2);
1099
+ }
1100
+ });
1101
+ }
1102
+ };
1103
+
1104
+ SourceGroup.prototype.isWrapped = function() {
1105
+ return this._source.wrapped;
1106
+ };
1107
+
1108
+ SourceGroup.prototype.getCurrentHeight = function() {
1109
+ return this._height;
1110
+ };
1111
+
1112
+ SourceGroup.prototype.getHeights = function() {
1113
+ return {
1114
+ unwrapped: this._unwrappedHeight,
1115
+ wrapped: this._wrappedHeight,
1116
+ current: this._height
1117
+ };
1118
+ };
1119
+
1120
+ SourceGroup.prototype.setVisible = function(boolean) {
1121
+ this._group.visible(boolean);
1122
+ };
1123
+
1124
+ SourceGroup.prototype.setListening = function(boolean) {
1125
+ this._group.listening(boolean);
1126
+ };
1127
+
1128
+ SourceGroup.prototype.isVisible = function() {
1129
+ return this._group.visible();
1130
+ };
1131
+
1132
+ SourceGroup.prototype.isCuttable = function() {
1133
+ return this._source.cuttable;
1134
+ };
1135
+
1136
+ SourceGroup.prototype.isDeletable = function() {
1137
+ return this._source.deletable;
1138
+ };
1139
+
1140
+ SourceGroup.prototype.getLine = function() {
1141
+ return this._source.lineId;
1142
+ };
1143
+
1144
+ SourceGroup.prototype.getAbsoluteBoundingBox = function() {
1145
+ var stageContainer = this._group.getStage().container();
1146
+ var containerRect = stageContainer.getBoundingClientRect();
1147
+
1148
+ var elementPos = this._group.getAbsolutePosition();
1149
+
1150
+ return {
1151
+ left: containerRect.left + elementPos.x,
1152
+ top: containerRect.top + elementPos.y,
1153
+ width: this._width,
1154
+ height: this._height
1155
+ };
1156
+ };
1157
+
1158
+ SourceGroup.prototype.getButtonBoundingBox = function(buttonId) {
1159
+ if (!this._buttonsGroup) {
1160
+ return null;
1161
+ }
1162
+
1163
+ var buttonIdx = this._source.buttons.findIndex(function(button) {
1164
+ return button.id === buttonId;
1165
+ });
1166
+
1167
+ if (buttonIdx === -1) {
1168
+ return null;
1169
+ }
1170
+
1171
+ var button = this._source.buttons[buttonIdx];
1172
+ var buttonGroup = this._buttonsGroup.getChildren()[buttonIdx];
1173
+ var buttonPos = buttonGroup.getAbsolutePosition(this._group);
1174
+
1175
+ return {
1176
+ left: buttonPos.x,
1177
+ top: buttonPos.y,
1178
+ width: button.width,
1179
+ height: button.height
1180
+ };
1181
+ };
1182
+
1183
+ SourceGroup.prototype.createIndicators = function() {
1184
+ var newIndicatorsColors = this._source.indicators;
1185
+
1186
+ var oldIndicators = this._indicators;
1187
+ var newIndicators = {};
1188
+
1189
+ if (newIndicatorsColors) {
1190
+ newIndicatorsColors.forEach(function(indicatorColor) {
1191
+ var oldIndicator = oldIndicators[indicatorColor];
1192
+
1193
+ if (oldIndicator) {
1194
+ newIndicators[indicatorColor] = oldIndicator;
1195
+ delete oldIndicators[indicatorColor];
1196
+ }
1197
+ else {
1198
+ newIndicators[indicatorColor] = null;
1199
+ }
1200
+ });
1201
+
1202
+ for (var color in oldIndicators) {
1203
+ if (Utils.objectHasProperty(oldIndicators, color)) {
1204
+ oldIndicators[color].destroy();
1205
+ }
1206
+ }
1207
+ }
1208
+
1209
+ this._indicators = Object.keys(newIndicators)
1210
+ .sort()
1211
+ .reverse()
1212
+ .reduce(function(objEntries, key) {
1213
+ objEntries[key] = newIndicators[key];
1214
+ return objEntries;
1215
+ }, {}
1216
+ );
1217
+
1218
+ this._createIndicators();
1219
+ };
1220
+
1221
+ SourceGroup.prototype._createIndicators = function() {
1222
+ var currentX = 0;
1223
+ var zIndex = 0;
1224
+
1225
+ for (var color in this._indicators) {
1226
+ if (Utils.objectHasProperty(this._indicators, color)) {
1227
+ if (!this._indicators[color]) {
1228
+ this._indicators[color] = new Konva.Circle({
1229
+ radius: INDICATOR_RADIUS,
1230
+ fill: color,
1231
+ strokeEnabled: false
1232
+ });
1233
+ this._indicatorsGroup.add(this._indicators[color]);
1234
+ }
1235
+
1236
+ this._indicators[color].x(currentX);
1237
+ this._indicators[color].zIndex(zIndex);
1238
+ currentX -= INDICATOR_RADIUS;
1239
+ zIndex += 1;
1240
+ }
1241
+ }
1242
+
1243
+ this._indicatorsGroup.offsetX(currentX - this._peaks.options.sourceIndicatorsXOffset);
1244
+ this._indicatorsGroup.offsetY(-this._peaks.options.sourceIndicatorsYOffset);
1245
+ };
1246
+
1247
+ SourceGroup.prototype._createMarkers = function() {
1248
+ const markersGroup = new Konva.Group({
1249
+ listening: false
1250
+ });
1251
+
1252
+ this._source.markers.forEach(function(marker) {
1253
+ const markerX = this._view.timeToPixels(marker - this._source.mediaStartTime);
1254
+
1255
+ var markerLine = new Konva.Line({
1256
+ points: [markerX, 0, markerX, this._unwrappedHeight],
1257
+ stroke: this._source.markerColor,
1258
+ strokeWidth: this._source.markerWidth
1259
+ });
1260
+
1261
+ markersGroup.add(markerLine);
1262
+ }.bind(this));
1263
+
1264
+ return markersGroup;
1265
+ };
1266
+
1267
+ SourceGroup.prototype._createButtons = function() {
1268
+ var buttonsGroup = new Konva.Group({
1269
+ listening: true,
1270
+ x: this._width,
1271
+ visible: false,
1272
+ opacity: 0
1273
+ });
1274
+ var buttonsGroupWidth = 0;
1275
+ var buttonsGap = this._peaks.options.sourceButtonsGap;
1276
+ var self = this;
1277
+
1278
+ this._source.buttons.forEach(function(button) {
1279
+ const {
1280
+ id,
1281
+ width,
1282
+ height,
1283
+ cornerRadius,
1284
+ color,
1285
+ hoverColor,
1286
+ borderColor,
1287
+ borderWidth,
1288
+ svg,
1289
+ image
1290
+ } = button;
1291
+
1292
+ if (buttonsGroupWidth > 0) {
1293
+ buttonsGroupWidth += buttonsGap;
1294
+ }
1295
+
1296
+ var buttonGroup = new Konva.Group({
1297
+ x: buttonsGroupWidth,
1298
+ y: 0,
1299
+ listening: true
1300
+ });
1301
+
1302
+ var buttonRect = new Konva.Rect({
1303
+ width: width,
1304
+ height: height,
1305
+ fill: color,
1306
+ stroke: borderColor,
1307
+ strokeWidth: borderWidth,
1308
+ cornerRadius: cornerRadius
1309
+ });
1310
+
1311
+ buttonsGroupWidth += width;
1312
+
1313
+ buttonGroup.add(buttonRect);
1314
+
1315
+ if (svg) {
1316
+ var svgIcon = new Konva.Path({
1317
+ x: width / 2,
1318
+ y: height / 2,
1319
+ data: svg.path,
1320
+ fill: svg.color,
1321
+ offsetX: svg.width / 2,
1322
+ offsetY: svg.height / 2,
1323
+ listening: false
1324
+ });
1325
+
1326
+ buttonGroup.add(svgIcon);
1327
+ }
1328
+ else if (image) {
1329
+ var imageObj = new Image();
1330
+
1331
+ imageObj.onload = function() {
1332
+ var imageIcon = new Konva.Image({
1333
+ x: width / 2,
1334
+ y: height / 2,
1335
+ image: imageObj,
1336
+ offsetX: image.width / 2,
1337
+ offsetY: image.height / 2,
1338
+ listening: false
1339
+ });
1340
+
1341
+ buttonGroup.add(imageIcon);
1342
+ };
1343
+
1344
+ imageObj.src = image.data;
1345
+ }
1346
+
1347
+ buttonGroup.on('mouseover', function() {
1348
+ self._view.setClickable(false);
1349
+ if (hoverColor) {
1350
+ buttonRect.fill(hoverColor);
1351
+ }
1352
+ self._peaks.emit('source.buttonEnter', self._source, id);
1353
+ });
1354
+
1355
+ buttonGroup.on('mouseout', function() {
1356
+ self._view.setClickable(true);
1357
+ if (buttonRect.fill() !== color) {
1358
+ buttonRect.fill(color);
1359
+ }
1360
+ self._peaks.emit('source.buttonLeave', self._source, id);
1361
+ });
1362
+
1363
+ buttonGroup.on('click', function() {
1364
+ self._peaks.emit('source.buttonClicked', self._source, id);
1365
+ });
1366
+
1367
+ buttonsGroup.add(buttonGroup);
1368
+ });
1369
+
1370
+ buttonsGroup.offsetX(
1371
+ buttonsGroupWidth
1372
+ + this._borderWidth
1373
+ + this._peaks.options.sourceButtonsPadding
1374
+ + this._peaks.options.sourceButtonsXOffset
1375
+ );
1376
+ buttonsGroup.offsetY(
1377
+ -this._borderWidth
1378
+ - this._peaks.options.sourceButtonsPadding
1379
+ - this._peaks.options.sourceButtonsYOffset
1380
+ );
1381
+
1382
+ return buttonsGroup;
1383
+ };
1384
+
1385
+ SourceGroup.prototype._updateMarkers = function() {
1386
+ const self = this;
1387
+
1388
+ if (this._markersGroup) {
1389
+ this._markersGroup.getChildren().forEach(function(markerLine, index) {
1390
+ const marker = self._source.markers[index];
1391
+ const markerX = self._view.timeToPixels(marker - self._source.mediaStartTime);
1392
+
1393
+ markerLine.points([markerX, 0, markerX, self._unwrappedHeight]);
1394
+ });
1395
+ }
1396
+ };
1397
+
1398
+ SourceGroup.prototype._updateButtons = function() {
1399
+ if (this._buttonsGroup) {
1400
+ this._buttonsGroup.x(this._width);
1401
+ }
1402
+ };
1403
+
1404
+ SourceGroup.prototype._getButtons = function() {
1405
+ if (!this._buttonsGroup) {
1406
+ this._buttonsGroup = this._createButtons();
1407
+ }
1408
+
1409
+ return this._buttonsGroup;
1410
+ };
1411
+
1412
+ SourceGroup.prototype._showButtons = function() {
1413
+ if (this._buttonsGroup) {
1414
+ if (this._buttonsAnimation) {
1415
+ this._buttonsAnimation.destroy();
1416
+ this._buttonsAnimation = null;
1417
+ }
1418
+
1419
+ var self = this;
1420
+
1421
+ this._buttonsGroup.visible(true);
1422
+ this._buttonsAnimation = new Konva.Tween({
1423
+ node: this._buttonsGroup,
1424
+ opacity: 1,
1425
+ duration: 0.2,
1426
+ easing: Konva.Easings.EaseOut,
1427
+ onFinish: function() {
1428
+ self._buttonsAnimation.destroy();
1429
+ self._buttonsAnimation = null;
1430
+ }
1431
+ });
1432
+ this._buttonsAnimation.play();
1433
+ }
1434
+ };
1435
+
1436
+ SourceGroup.prototype._hideButtons = function() {
1437
+ if (this._buttonsGroup) {
1438
+ if (this._buttonsAnimation) {
1439
+ this._buttonsAnimation.destroy();
1440
+ this._buttonsAnimation = null;
1441
+ }
1442
+
1443
+ var self = this;
1444
+
1445
+ this._buttonsAnimation = new Konva.Tween({
1446
+ node: this._buttonsGroup,
1447
+ opacity: 0,
1448
+ duration: 0.2,
1449
+ easing: Konva.Easings.EaseOut,
1450
+ onFinish: function() {
1451
+ self._buttonsGroup.visible(false);
1452
+ self._buttonsAnimation.destroy();
1453
+ self._buttonsAnimation = null;
1454
+ }
1455
+ });
1456
+ this._buttonsAnimation.play();
1457
+ }
1458
+ };
1459
+
1460
+ SourceGroup.prototype._getYFromVolume = function(volume) {
1461
+ return this._borderWidth + (this._height - 2 * this._borderWidth) * (
1462
+ this._source.volumeRange[1] - volume
1463
+ ) / (
1464
+ this._source.volumeRange[1] - this._source.volumeRange[0]
1465
+ );
1466
+ };
1467
+
1468
+ SourceGroup.prototype._getVolumeFromY = function(y) {
1469
+ return this._source.volumeRange[1] - (
1470
+ (y - this._borderWidth) / (this._height - 2 * this._borderWidth)
1471
+ ) * (
1472
+ this._source.volumeRange[1] - this._source.volumeRange[0]
1473
+ );
1474
+ };
1475
+
1476
+ SourceGroup.prototype._updateVolumeSlider = function() {
1477
+ const width = this._width;
1478
+
1479
+ if (this._volumeSliderGroup) {
1480
+ this._volumeSliderGroup.getChildren().forEach(function(child) {
1481
+ if (child instanceof Konva.Group) {
1482
+ child.width(width);
1483
+ child.getChildren().forEach(function(node) {
1484
+ if (node instanceof Konva.Line) {
1485
+ node.points([0, 0, width, 0]);
1486
+ }
1487
+ });
1488
+ }
1489
+ });
1490
+ }
1491
+ };
1492
+
1493
+ SourceGroup.prototype._getVolumeSlider = function() {
1494
+ if (!this._volumeSliderGroup) {
1495
+ this._volumeSliderGroup = this._createVolumeSlider();
1496
+ }
1497
+
1498
+ return this._volumeSliderGroup;
1499
+ };
1500
+
1501
+ SourceGroup.prototype._createVolumeSlider = function() {
1502
+ var self = this;
1503
+
1504
+ var volumeY = this._getYFromVolume(this._source.volume);
1505
+
1506
+ var volumeGroup = new Konva.Group({
1507
+ x: 0,
1508
+ y: 0
1509
+ });
1510
+
1511
+ var volumeText = new Konva.Text({
1512
+ x: 0,
1513
+ y: volumeY - 20,
1514
+ text: '100%',
1515
+ fontSize: 12,
1516
+ fill: this._source.volumeSliderColor,
1517
+ visible: false
1518
+ });
1519
+
1520
+ var maxTextWidth = volumeText.width();
1521
+ var maxTextHeight = volumeText.height();
1522
+
1523
+ var volumeSliderGroup = new Konva.Group({
1524
+ x: 0,
1525
+ y: volumeY,
1526
+ draggable: true,
1527
+ dragBoundFunc: function(pos) {
1528
+ var y = Math.min(
1529
+ volumeGroup.absolutePosition().y + self._height - self._borderWidth,
1530
+ Math.max(
1531
+ volumeGroup.absolutePosition().y + self._borderWidth,
1532
+ pos.y
1533
+ )
1534
+ );
1535
+
1536
+ var textX = Math.min(
1537
+ volumeGroup.absolutePosition().x + self._width - maxTextWidth - self._borderWidth,
1538
+ Math.max(
1539
+ volumeGroup.absolutePosition().x + self._borderWidth,
1540
+ self._view.getPointerPosition().x - maxTextWidth
1541
+ )
1542
+ );
1543
+ var textY = y - (self._source.volumeSliderWidth / 2) - maxTextHeight;
1544
+
1545
+ volumeText.absolutePosition({
1546
+ x: textX,
1547
+ y: textY < volumeGroup.absolutePosition().y + self._borderWidth ?
1548
+ y + self._source.volumeSliderWidth :
1549
+ textY
1550
+ });
1551
+
1552
+ return { x: this.absolutePosition().x, y: y };
1553
+ }
1554
+ });
1555
+
1556
+ var volumeSliderLine = new Konva.Line({
1557
+ points: [0, 0, this._width, 0],
1558
+ stroke: this._source.volumeSliderColor,
1559
+ strokeWidth: this._source.volumeSliderWidth
1560
+ });
1561
+
1562
+ var volumeSliderRect = new Konva.Rect({
1563
+ x: 0,
1564
+ y: -this._source.volumeSliderDraggingWidth / 2,
1565
+ width: this._width,
1566
+ height: this._source.volumeSliderDraggingWidth,
1567
+ opacity: 0
1568
+ });
1569
+
1570
+ volumeSliderGroup.add(volumeSliderRect);
1571
+ volumeSliderGroup.add(volumeSliderLine);
1572
+
1573
+ volumeSliderGroup.on('dragstart', function() {
1574
+ volumeText.visible(true);
1575
+ });
1576
+
1577
+ volumeSliderGroup.on('dragmove', function() {
1578
+ var volume = self._getVolumeFromY(volumeSliderGroup.y());
1579
+
1580
+ volumeText.text((volume * 100).toFixed(0) + '%');
1581
+
1582
+ self._source.volume = Math.max(self._source.volumeRange[0], Math.min(volume, self._source.volumeRange[1]));
1583
+ self._peaks.emit('source.volumeChanged', self._source);
1584
+
1585
+ self._group.draw();
1586
+ });
1587
+
1588
+ volumeSliderGroup.on('dragend', function() {
1589
+ volumeText.visible(false);
1590
+ });
1591
+
1592
+ volumeSliderGroup.on('mouseover', function() {
1593
+ self._cursor = 'ns-resize';
1594
+ });
1595
+
1596
+ volumeSliderGroup.on('mouseout', function() {
1597
+ self._cursor = null;
1598
+ });
1599
+
1600
+ volumeGroup.add(volumeSliderGroup);
1601
+ volumeGroup.add(volumeText);
1602
+
1603
+ return volumeGroup;
1604
+ };
1605
+
1606
+ SourceGroup.prototype.destroy = function() {
1607
+ if (this._buttonsAnimation) {
1608
+ this._buttonsAnimation.destroy();
1609
+ this._buttonsAnimation = null;
1610
+ }
1611
+
1612
+ if (this._loader) {
1613
+ this._loader.destroy();
1614
+ this._loader = null;
1615
+ }
1616
+
1617
+ this._group.destroy();
1618
+ };
1619
+
1620
+ /**
1621
+ * Static method to get height for a source
1622
+ * @param {Source} source - The source object
1623
+ * @param {Object} peaks - The peaks instance (for options)
1624
+ * @returns {number} The calculated height
1625
+ */
1626
+ SourceGroup.getHeights = function(source, peaks) {
1627
+ var unwrappedHeight = source.binaryHeight && source.previewHeight ?
1628
+ source.binaryHeight + source.previewHeight :
1629
+ peaks.options.lineHeight;
1630
+ var wrappedHeight = peaks.options.wrappedLineHeight;
1631
+ var height = source.wrapped ? wrappedHeight : unwrappedHeight;
1632
+
1633
+ return {
1634
+ unwrapped: unwrappedHeight,
1635
+ wrapped: wrappedHeight,
1636
+ current: height
1637
+ };
1638
+ };
1639
+
1640
+ return SourceGroup;
1641
+ });