@checksub_team/peaks_timeline 1.16.1 → 2.0.0-alpha.10

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