@checksub_team/peaks_timeline 1.16.0-alpha.2 → 2.0.0-alpha.0

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