@checksub_team/peaks_timeline 1.4.17

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.
@@ -0,0 +1,866 @@
1
+ /**
2
+ * @file
3
+ *
4
+ * Defines the {@link TimelineZoomView} class.
5
+ *
6
+ * @module timeline-zoomview
7
+ */
8
+
9
+ define([
10
+ './mouse-drag-handler',
11
+ './playhead-layer',
12
+ './sources-layer',
13
+ './mode-layer',
14
+ './timeline-axis',
15
+ './utils',
16
+ 'konva'
17
+ ], function(
18
+ MouseDragHandler,
19
+ PlayheadLayer,
20
+ SourcesLayer,
21
+ ModeLayer,
22
+ TimelineAxis,
23
+ Utils,
24
+ Konva) {
25
+ 'use strict';
26
+
27
+ /**
28
+ * Creates a zoomable timeline view.
29
+ *
30
+ * @class
31
+ * @alias TimelineZoomView
32
+ *
33
+ * @param {HTMLElement} container
34
+ * @param {Peaks} peaks
35
+ */
36
+
37
+ function TimelineZoomView(container, peaks) {
38
+ var self = this;
39
+
40
+ self._container = container;
41
+ self._peaks = peaks;
42
+
43
+ // Bind event handlers
44
+ self._onTimeUpdate = self._onTimeUpdate.bind(self);
45
+ self._onSeek = self._onSeek.bind(self);
46
+ self._onPlay = self._onPlay.bind(self);
47
+ self._onPause = self._onPause.bind(self);
48
+ self._onWindowResize = self._onWindowResize.bind(self);
49
+ self._onKeyboardLeft = self._onKeyboardLeft.bind(self);
50
+ self._onKeyboardRight = self._onKeyboardRight.bind(self);
51
+ self._onKeyboardShiftLeft = self._onKeyboardShiftLeft.bind(self);
52
+ self._onKeyboardShiftRight = self._onKeyboardShiftRight.bind(self);
53
+ self._onDefaultMode = self._onDefaultMode.bind(self);
54
+ self._onCutMode = self._onCutMode.bind(self);
55
+
56
+ // Register event handlers
57
+ self._peaks.on('timeline.update', self._onTimeUpdate);
58
+ self._peaks.on('user_seek', self._onSeek);
59
+ self._peaks.on('timeline.play', self._onPlay);
60
+ self._peaks.on('timeline.pause', self._onPause);
61
+ self._peaks.on('window_resize', self._onWindowResize);
62
+ self._peaks.on('keyboard.left', self._onKeyboardLeft);
63
+ self._peaks.on('keyboard.right', self._onKeyboardRight);
64
+ self._peaks.on('keyboard.shift_left', self._onKeyboardShiftLeft);
65
+ self._peaks.on('keyboard.shift_right', self._onKeyboardShiftRight);
66
+ self._peaks.on('default_mode', self._onDefaultMode);
67
+ self._peaks.on('cut_mode', self._onCutMode);
68
+
69
+ self._enableAutoScroll = true;
70
+ self._amplitudeScale = 1.0;
71
+ self._options = peaks.options;
72
+ self._sources = peaks.sources;
73
+ self._timelineLength = 0;
74
+ self._timeToPixelsScale = self._options.initialZoomLevel;
75
+ self._timeToPixelsMinScale = self._options.minScale;
76
+
77
+ self._resizeTimeoutId = null;
78
+ self._isFocused = false;
79
+
80
+ self._width = container.clientWidth;
81
+ self._height = container.clientHeight || self._options.height;
82
+
83
+ self._originalWidth = self._width;
84
+
85
+ // The pixel offset of the current frame being displayed
86
+ self.setFrameOffset(0);
87
+ self._frameOffsetY = 0;
88
+
89
+ self._preventWrappingChange = false;
90
+
91
+ container.oncontextmenu = function() {
92
+ return false;
93
+ };
94
+
95
+ container.style.whiteSpace = 'nowrap';
96
+
97
+ var lineIndicatorContainer = document.createElement('div');
98
+ var stageContainer = document.createElement('div');
99
+
100
+ lineIndicatorContainer.id = 'line-indicator-container';
101
+ stageContainer.id = 'stage-container';
102
+
103
+ stageContainer.style.display = 'inline-block';
104
+ stageContainer.style.zIndex = 0;
105
+ lineIndicatorContainer.style.display = 'inline-block';
106
+ lineIndicatorContainer.style.zIndex = 1;
107
+
108
+ container.appendChild(lineIndicatorContainer);
109
+ container.appendChild(stageContainer);
110
+
111
+ self._stage = new Konva.Stage({
112
+ container: stageContainer,
113
+ width: self._width - self._peaks.options.lineIndicatorWidth,
114
+ height: self._height
115
+ });
116
+
117
+ self._width -= self._peaks.options.lineIndicatorWidth;
118
+
119
+ self._axis = new TimelineAxis(self._peaks, self, {
120
+ axisGridlineColor: this._options.axisGridlineColor,
121
+ axisLabelColor: this._options.axisLabelColor
122
+ });
123
+
124
+ self._axis.addBackToStage(self._stage);
125
+
126
+ self._sourcesLayer = new SourcesLayer(peaks, self, true);
127
+ self._sourcesLayer.addToStage(self._stage);
128
+
129
+ self._axis.addFrontToStage(self._stage);
130
+
131
+ self._playheadLayer = new PlayheadLayer(
132
+ peaks,
133
+ self,
134
+ self._sourcesLayer.getSegmentsGroup(),
135
+ self._options.showPlayheadTime
136
+ );
137
+
138
+ self._playheadLayer.addToStage(self._stage);
139
+
140
+ var time = self._peaks.player.getCurrentTime();
141
+
142
+ self._syncPlayhead(time);
143
+
144
+ self._hoveredElement = null;
145
+
146
+ self._modeLayer = new ModeLayer(peaks, self, self._stage, 'default');
147
+ self._modeLayer.addToStage(self._stage);
148
+
149
+ self._mouseDragHandler = new MouseDragHandler(self._stage, {
150
+ onMouseDown: function(mousePosX, mousePosY) {
151
+ this.initialFrameOffset = self._frameOffset;
152
+ this.initialFrameOffsetY = self._frameOffsetY;
153
+ this.mouseDownX = mousePosX;
154
+ this.mouseDownY = mousePosY;
155
+ self.enableAutoScroll(false);
156
+ },
157
+
158
+ onMouseMove: function(mousePosX, mousePosY) {
159
+ // Moving the mouse to the left increases the time position of the
160
+ // left-hand edge of the visible waveform.
161
+ var diff = this.mouseDownX - mousePosX;
162
+ var diffY = this.mouseDownY - mousePosY;
163
+
164
+ var newFrameOffset = null;
165
+
166
+ if (self.isListening()) {
167
+ newFrameOffset = Math.max(
168
+ this.initialFrameOffset + diff, 0
169
+ );
170
+ }
171
+
172
+ var height = self._sourcesLayer._lines.height() - self._height;
173
+ var newFrameOffsetY = 0;
174
+
175
+ if (self._peaks.options.enableVerticalScrolling && height > 0) {
176
+ newFrameOffsetY = Utils.clamp(
177
+ this.initialFrameOffsetY + diffY, 0, height
178
+ );
179
+ }
180
+ else {
181
+ self._frameOffsetY = 0;
182
+ }
183
+
184
+ if ((newFrameOffset !== this.initialFrameOffset)
185
+ || (newFrameOffsetY !== this.initialFrameOffsetY)) {
186
+ self.updateTimeline(
187
+ newFrameOffset,
188
+ newFrameOffsetY
189
+ );
190
+ }
191
+ },
192
+
193
+ onMouseUp: function() {
194
+ self.enableAutoScroll(true);
195
+ }
196
+ });
197
+
198
+ this._stage.on('mouseover', function() {
199
+ self._isFocused = true;
200
+ });
201
+
202
+ this._stage.on('mouseout', function() {
203
+ self._isFocused = false;
204
+ });
205
+
206
+ this._stage.on('click', function(event) {
207
+ self._peaks.emit('zoomview.click', event);
208
+ self._isFocused = true;
209
+ // Set playhead position only on click release, when not dragging.
210
+ if (self._modeLayer.getCurrentMode() === 'default' && !self._mouseDragHandler.isDragging()) {
211
+ var mouseDownX = Math.floor(self._stage.getPointerPosition().x);
212
+
213
+ var pixelIndex = self._frameOffset + mouseDownX;
214
+
215
+ var time = self.pixelsToTime(pixelIndex);
216
+
217
+ if (!(self._options.blockUpdatingOnMouseClickWithMetaKey && event.metaKey)
218
+ && !(self._options.blockUpdatingOnMouseClickWithCtrlKey && event.ctrlKey)) {
219
+ self.updateTimeline(pixelIndex - mouseDownX);
220
+ self._peaks.player.seek(time);
221
+ }
222
+
223
+ self._peaks.emit('zoomview.updateTime', event, time);
224
+ }
225
+ });
226
+
227
+ this._stage.on('dblclick', function(event) {
228
+ var mousePosX = event.evt.layerX;
229
+
230
+ var pixelIndex = self._frameOffset + mousePosX;
231
+
232
+ var time = self.pixelsToTime(pixelIndex);
233
+
234
+ self._peaks.emit('zoomview.dblclick', time);
235
+ });
236
+
237
+ this._stage.on('wheel', function(e) {
238
+ // prevent parent scrolling
239
+ e.evt.preventDefault();
240
+
241
+ if (self._peaks.keyboardHandler.isCtrlCmdPressed()) {
242
+ if (e.evt.deltaY > 0) {
243
+ self.setZoom(
244
+ self.getTimeToPixelsScale() + Math.floor(self.getTimeToPixelsScale() / 10) + 1
245
+ );
246
+ }
247
+ else if ((e.evt.deltaY < 0)) {
248
+ self.setZoom(
249
+ self.getTimeToPixelsScale() - Math.floor(self.getTimeToPixelsScale() / 10) + 1
250
+ );
251
+ }
252
+
253
+ self.updateTimelineLength();
254
+ }
255
+ else {
256
+ var diff = e.evt.deltaX * 2;
257
+ var diffY = e.evt.deltaY / 2;
258
+
259
+ var newFrameOffset = null;
260
+
261
+ if (self.isListening()) {
262
+ newFrameOffset = Utils.clamp(
263
+ self.getFrameOffset() + diff, 0, self._timelineLength - self._width
264
+ );
265
+ }
266
+
267
+ var height = self._sourcesLayer._lines.height() - self._height;
268
+ var newFrameOffsetY = 0;
269
+
270
+ if (self._peaks.options.enableVerticalScrolling && height > 0) {
271
+ newFrameOffsetY = Utils.clamp(
272
+ self.getFrameOffsetY() + diffY, 0, height
273
+ );
274
+ }
275
+ else {
276
+ self._frameOffsetY = 0;
277
+ }
278
+
279
+ if ((newFrameOffset !== self.getFrameOffset())
280
+ || (newFrameOffsetY !== self.getFrameOffsetY())) {
281
+ self.updateTimeline(
282
+ newFrameOffset,
283
+ newFrameOffsetY
284
+ );
285
+ }
286
+ }
287
+ });
288
+ }
289
+
290
+ TimelineZoomView.prototype.updateWithAutoScroll = function(obj, updateInInterval,
291
+ updateOutInterval) {
292
+ var self = this;
293
+ var posX = this.getPointerPosition().x;
294
+ var threshold = Math.round(this._peaks.options.autoScrollThreshold * this.getWidth());
295
+
296
+ obj._limited = 0;
297
+
298
+ if (posX < threshold) {
299
+ obj._limited = Math.round(-30 * Math.min(1, (threshold - posX) / threshold));
300
+ }
301
+ else if (posX > this.getWidth() - threshold) {
302
+ obj._limited = Math.round(
303
+ 30 * Math.min(1, (posX - (this.getWidth() - threshold)) / threshold)
304
+ );
305
+ }
306
+
307
+ if (obj._limited && self.getFrameOffset() > 0 || obj._limited > 0) {
308
+ if (!obj._scrollingInterval) {
309
+ obj._scrollingInterval = setInterval(
310
+ function() {
311
+ var newOffset = self.getFrameOffset() + obj._limited;
312
+
313
+ if (newOffset < 0) {
314
+ self.updateTimeline(0, null, false);
315
+ clearInterval(obj._scrollingInterval);
316
+ obj._scrollingInterval = null;
317
+ }
318
+ else {
319
+ self.updateTimeline(self.getFrameOffset() + obj._limited, null, false);
320
+ }
321
+
322
+ updateInInterval();
323
+ },
324
+ 10
325
+ );
326
+ }
327
+ }
328
+ else {
329
+ if (obj._scrollingInterval) {
330
+ clearInterval(obj._scrollingInterval);
331
+ obj._scrollingInterval = null;
332
+ }
333
+
334
+ if (updateOutInterval) {
335
+ updateOutInterval();
336
+ }
337
+ else {
338
+ updateInInterval();
339
+ }
340
+ }
341
+
342
+ return {
343
+ x: obj.absolutePosition().x,
344
+ y: obj.absolutePosition().y
345
+ };
346
+ };
347
+
348
+ TimelineZoomView.prototype.getCurrentMode = function() {
349
+ return this._modeLayer.getCurrentMode();
350
+ };
351
+
352
+ TimelineZoomView.prototype.overrideInteractions = function(bool, areInteractionsAllowed) {
353
+ this._sourcesLayer._lines.overrideInteractions(bool, areInteractionsAllowed);
354
+ this._sourcesLayer.stopDrag();
355
+ this._sourcesLayer.draw();
356
+ };
357
+
358
+ TimelineZoomView.prototype.allowInteractions = function(forSources, forSegments) {
359
+ this._sourcesLayer._lines.allowInteractions(forSources, forSegments);
360
+ this._sourcesLayer.stopDrag();
361
+ this._sourcesLayer.draw();
362
+ };
363
+
364
+ TimelineZoomView.prototype.isListening = function() {
365
+ return this._stage.listening();
366
+ };
367
+
368
+ TimelineZoomView.prototype.isFocused = function() {
369
+ return this._isFocused;
370
+ };
371
+
372
+ TimelineZoomView.prototype.drawSourcesLayer = function() {
373
+ this._sourcesLayer.draw();
374
+ };
375
+
376
+ TimelineZoomView.prototype.getSegmentsGroup = function() {
377
+ return this._sourcesLayer.getSegmentsGroup();
378
+ };
379
+
380
+ TimelineZoomView.prototype.getTimeToPixelsScale = function() {
381
+ return this._timeToPixelsScale;
382
+ };
383
+
384
+ TimelineZoomView.prototype.getTimeToPixelsMaxZoom = function() {
385
+ return this._options.zoomRange[1];
386
+ };
387
+
388
+ TimelineZoomView.prototype.setTimeToPixelsMaxZoom = function(value) {
389
+ this._options.zoomRange[1] = value;
390
+ if (value < this._timeToPixelsScale) {
391
+ this.setZoom(value);
392
+ }
393
+ };
394
+
395
+ TimelineZoomView.prototype.getTimeToPixelsMinScale = function() {
396
+ return this._timeToPixelsMinScale;
397
+ };
398
+
399
+ TimelineZoomView.prototype.getName = function() {
400
+ return 'zoomview';
401
+ };
402
+
403
+ TimelineZoomView.prototype._onTimeUpdate = function(time) {
404
+ if (this._mouseDragHandler.isDragging()) {
405
+ return;
406
+ }
407
+
408
+ this._syncPlayhead(time);
409
+ };
410
+
411
+ TimelineZoomView.prototype._onSeek = function(time) {
412
+ var frameIndex = this.timeToPixels(time);
413
+
414
+ this.updateTimeline(frameIndex - Math.floor(this._width / 2));
415
+ this._playheadLayer.updatePlayheadTime(time);
416
+ };
417
+
418
+ TimelineZoomView.prototype._onPlay = function(time) {
419
+ this._playheadLayer.updatePlayheadTime(time);
420
+ this.enableAutoScroll(true);
421
+ };
422
+
423
+ TimelineZoomView.prototype._onPause = function(time) {
424
+ this._playheadLayer.stop(time);
425
+ this.enableAutoScroll(true);
426
+ };
427
+
428
+ TimelineZoomView.prototype._onWindowResize = function() {
429
+ var self = this;
430
+
431
+ var width = self._container.clientWidth;
432
+
433
+ if (!self._zoomLevelAuto) {
434
+ self._width = width;
435
+ self._stage.width(width);
436
+ self.updateTimeline(self._frameOffset, self._frameOffsetY);
437
+ }
438
+ else {
439
+ if (self._resizeTimeoutId) {
440
+ clearTimeout(self._resizeTimeoutId);
441
+ self._resizeTimeoutId = null;
442
+ }
443
+
444
+ // Avoid resampling waveform data to zero width
445
+ if (width !== 0) {
446
+ self._width = width;
447
+ self._stage.width(width);
448
+
449
+ self._resizeTimeoutId = setTimeout(function() {
450
+ self._width = width;
451
+ // self._data = self._originalWaveformData.resample(width);
452
+ self._stage.width(width);
453
+
454
+ self.updateTimeline(self._frameOffset, self._frameOffsetY);
455
+ }, 500);
456
+ }
457
+ }
458
+ };
459
+
460
+ TimelineZoomView.prototype._onKeyboardLeft = function() {
461
+ if (this.isFocused()) {
462
+ this._keyboardScroll(-1, false);
463
+ }
464
+ };
465
+
466
+ TimelineZoomView.prototype._onKeyboardRight = function() {
467
+ if (this.isFocused()) {
468
+ this._keyboardScroll(1, false);
469
+ }
470
+ };
471
+
472
+ TimelineZoomView.prototype._onKeyboardShiftLeft = function() {
473
+ if (this.isFocused()) {
474
+ this._keyboardScroll(-1, true);
475
+ }
476
+ };
477
+
478
+ TimelineZoomView.prototype._onKeyboardShiftRight = function() {
479
+ if (this.isFocused()) {
480
+ this._keyboardScroll(1, true);
481
+ }
482
+ };
483
+
484
+ TimelineZoomView.prototype._onDefaultMode = function() {
485
+ this.preventWrappingChange(false);
486
+ this._modeLayer.setMode('default');
487
+ };
488
+
489
+ TimelineZoomView.prototype._onCutMode = function() {
490
+ this.preventWrappingChange(true);
491
+ this._modeLayer.setMode('cut');
492
+ };
493
+
494
+ TimelineZoomView.prototype.preventWrappingChange = function(bool) {
495
+ this._preventWrappingChange = bool;
496
+ };
497
+
498
+ TimelineZoomView.prototype.isPreventingWrappingChange = function() {
499
+ return this._preventWrappingChange;
500
+ };
501
+
502
+ TimelineZoomView.prototype.getHoveredElement = function() {
503
+ return this._hoveredElement;
504
+ };
505
+
506
+ TimelineZoomView.prototype.setHoveredElement = function(element) {
507
+ this._hoveredElement = element;
508
+ };
509
+
510
+ TimelineZoomView.prototype._keyboardScroll = function(direction, large) {
511
+ var increment;
512
+
513
+ if (large) {
514
+ increment = direction * this._width;
515
+ }
516
+ else {
517
+ increment = direction * this.timeToPixels(this._options.nudgeIncrement);
518
+ }
519
+
520
+ this.updateTimeline(this._frameOffset + increment);
521
+ };
522
+
523
+ TimelineZoomView.prototype._syncPlayhead = function(time) {
524
+ this._playheadLayer.updatePlayheadTime(time);
525
+
526
+ if (this._enableAutoScroll) {
527
+ // Check for the playhead reaching the right-hand side of the window.
528
+ var pixelIndex = this.timeToPixels(time);
529
+
530
+ var threshold = Math.round(0.1 * this._width);
531
+ var endThreshold = this._frameOffset + this._width - threshold;
532
+
533
+ if (pixelIndex >= endThreshold || pixelIndex < this._frameOffset) {
534
+ // Put the playhead at 100 pixels from the left edge
535
+ this.setFrameOffset(pixelIndex - threshold);
536
+
537
+ if (this._frameOffset < 0) {
538
+ this.setFrameOffset(0);
539
+ }
540
+
541
+ this.updateTimeline(this._frameOffset);
542
+ }
543
+ }
544
+ };
545
+
546
+ TimelineZoomView.prototype.showPlayhead = function() {
547
+ var newFrameOffset = this._playheadLayer.getPlayheadPixel() - Math.round(0.1 * this._width);
548
+
549
+ this.setFrameOffset(newFrameOffset);
550
+ this.updateTimeline(this._frameOffset);
551
+ this.enableAutoScroll(true);
552
+ };
553
+
554
+ /**
555
+ * Changes the zoom level.
556
+ *
557
+ * @param {Number} scale The new zoom level, in samples per pixel.
558
+ */
559
+
560
+ TimelineZoomView.prototype._getScale = function(duration) {
561
+ return duration * this._data.sample_rate / this._width;
562
+ };
563
+
564
+ TimelineZoomView.prototype.setZoom = function(newScale) {
565
+ newScale = Math.min(Math.max(this._options.zoomRange[0], newScale), this._options.zoomRange[1]);
566
+
567
+ var currentTime = this._peaks.player.getCurrentTime();
568
+ var apexTime;
569
+ var playheadOffsetPixels = this._playheadLayer.getPlayheadOffset();
570
+
571
+ if (playheadOffsetPixels >= 0 && playheadOffsetPixels < this._width) {
572
+ // Playhead is visible. Change the zoom level while keeping the
573
+ // playhead at the same position in the window.
574
+ apexTime = currentTime;
575
+ }
576
+ else {
577
+ // Playhead is not visible. Change the zoom level while keeping the
578
+ // centre of the window at the same position in the waveform.
579
+ playheadOffsetPixels = this._width / 2;
580
+ apexTime = this.pixelsToTime(this._frameOffset + playheadOffsetPixels);
581
+ }
582
+
583
+ var prevScale = this._timeToPixelsScale;
584
+
585
+ this._timeToPixelsScale = newScale;
586
+
587
+ var apexPixel = this.timeToPixels(apexTime);
588
+
589
+ this.setFrameOffset(apexPixel - playheadOffsetPixels);
590
+
591
+ this.updateTimeline(this._frameOffset);
592
+
593
+ this._playheadLayer.zoomLevelChanged();
594
+
595
+ // Update the playhead position after zooming.
596
+ this._playheadLayer.updatePlayheadTime(currentTime);
597
+
598
+ this._sourcesLayer.rescale();
599
+
600
+ this._peaks.emit('zoom.update', newScale, prevScale);
601
+
602
+ return true;
603
+ };
604
+
605
+ TimelineZoomView.prototype.getTimelineLength = function() {
606
+ return this._timelineLength;
607
+ };
608
+
609
+ TimelineZoomView.prototype.updateTimelineLength = function() {
610
+ this._timelineLength = this._sourcesLayer.getLength() + this._peaks.options.horizontalPadding;
611
+ };
612
+
613
+ TimelineZoomView.prototype.setTimelineLength = function(length) {
614
+ this._timelineLength = length;
615
+ };
616
+
617
+ TimelineZoomView.prototype.getPointerPosition = function() {
618
+ return this._stage.getPointerPosition();
619
+ };
620
+
621
+ TimelineZoomView.prototype.getStartTime = function() {
622
+ return this.pixelsToTime(this._frameOffset);
623
+ };
624
+
625
+ TimelineZoomView.prototype.getEndTime = function() {
626
+ return this.pixelsToTime(this._frameOffset + this._width);
627
+ };
628
+
629
+ TimelineZoomView.prototype.setStartTime = function(time) {
630
+ if (time < 0) {
631
+ time = 0;
632
+ }
633
+
634
+ if (this._zoomLevelAuto) {
635
+ time = 0;
636
+ }
637
+
638
+ this.updateTimeline(this.timeToPixels(time));
639
+ };
640
+
641
+ /**
642
+ * Returns the pixel index for a given time, for the current zoom level.
643
+ *
644
+ * @param {Number} time Time, in seconds.
645
+ * @returns {Number} Pixel index.
646
+ */
647
+
648
+ TimelineZoomView.prototype.timeToPixels = function(time) {
649
+ return Math.round(time * this._timeToPixelsScale);
650
+ };
651
+
652
+ /**
653
+ * Returns the time for a given pixel index, for the current zoom level.
654
+ *
655
+ * @param {Number} pixels Pixel index.
656
+ * @returns {Number} Time, in seconds.
657
+ */
658
+
659
+ TimelineZoomView.prototype.pixelsToTime = function(pixels) {
660
+ return Utils.roundTime(pixels / this._timeToPixelsScale);
661
+ };
662
+
663
+ /**
664
+ * @returns {Number} The start position of the waveform shown in the view,
665
+ * in pixels.
666
+ */
667
+
668
+ TimelineZoomView.prototype.getFrameOffset = function() {
669
+ return this._frameOffset;
670
+ };
671
+
672
+ TimelineZoomView.prototype.setFrameOffset = function(newFrameOffset) {
673
+ newFrameOffset = Math.max(0, newFrameOffset);
674
+ this._frameOffset = newFrameOffset;
675
+ this._timeOffset = this.pixelsToTime(this._frameOffset);
676
+ };
677
+
678
+ TimelineZoomView.prototype.getTimeOffset = function() {
679
+ return this._timeOffset;
680
+ };
681
+
682
+ TimelineZoomView.prototype.setTimeOffset = function(newTimeOffset) {
683
+ this._timeOffset = newTimeOffset;
684
+ this._frameOffset = this.timeToPixels(this._timeOffset);
685
+ };
686
+
687
+ /**
688
+ * @returns {Number} The offset on Y,
689
+ * in pixels.
690
+ */
691
+
692
+ TimelineZoomView.prototype.getFrameOffsetY = function() {
693
+ return this._frameOffsetY;
694
+ };
695
+
696
+ /**
697
+ * @returns {Number} The width of the stage, in pixels.
698
+ */
699
+
700
+ TimelineZoomView.prototype.getWidth = function() {
701
+ return this._width;
702
+ };
703
+
704
+ /**
705
+ * @returns {Number} The width of the whole view, in pixels.
706
+ */
707
+
708
+ TimelineZoomView.prototype.getOriginalWidth = function() {
709
+ return this._originalWidth;
710
+ };
711
+
712
+ /**
713
+ * @returns {Number} The height of the view, in pixels.
714
+ */
715
+
716
+ TimelineZoomView.prototype.getHeight = function() {
717
+ return this._height;
718
+ };
719
+
720
+ /**
721
+ * Adjusts the amplitude scale of waveform shown in the view, which allows
722
+ * users to zoom the waveform vertically.
723
+ *
724
+ * @param {Number} scale The new amplitude scale factor
725
+ */
726
+
727
+ TimelineZoomView.prototype.setAmplitudeScale = function(scale) {
728
+ if (!Utils.isNumber(scale) || !Number.isFinite(scale)) {
729
+ throw new Error('view.setAmplitudeScale(): Scale must be a valid number');
730
+ }
731
+
732
+ this._amplitudeScale = scale;
733
+ };
734
+
735
+ TimelineZoomView.prototype.getAmplitudeScale = function() {
736
+ return this._amplitudeScale;
737
+ };
738
+
739
+ /**
740
+ * Updates the region of waveform shown in the view.
741
+ *
742
+ * @param {Number} frameOffset The new frame offset, in pixels.
743
+ */
744
+
745
+ TimelineZoomView.prototype.updateTimeline = function(frameOffset, frameOffsetY, fixPlayhead) {
746
+ var frameStartTime = null;
747
+ var frameEndTime = null;
748
+
749
+ if (frameOffset !== undefined && frameOffset !== null) {
750
+ if (this._timelineLength < this._width) {
751
+ // Total waveform is shorter than viewport, so reset the offset to 0.
752
+ frameOffset = 0;
753
+ }
754
+
755
+ // frameOffset = Utils.clamp(frameOffset, 0, upperLimit);
756
+
757
+ this.setFrameOffset(frameOffset);
758
+
759
+ frameStartTime = this.pixelsToTime(this._frameOffset);
760
+ frameEndTime = this.pixelsToTime(this._frameOffset + this._width);
761
+
762
+ if (!fixPlayhead) {
763
+ // Display playhead if it is within the zoom frame width.
764
+ var playheadPixel = this._playheadLayer.getPlayheadPixel();
765
+
766
+ this._playheadLayer.updatePlayheadTime(this.pixelsToTime(playheadPixel));
767
+ }
768
+
769
+ this._axis.draw();
770
+
771
+ this._peaks.emit('zoomview.displaying', frameStartTime, frameEndTime);
772
+ }
773
+
774
+ if (frameOffsetY !== undefined && frameOffsetY !== null) {
775
+ this._frameOffsetY = frameOffsetY;
776
+ }
777
+
778
+ if (frameStartTime === null) {
779
+ frameStartTime = this.pixelsToTime(this._frameOffset);
780
+ }
781
+
782
+ if (frameEndTime === null) {
783
+ frameEndTime = this.pixelsToTime(this._frameOffset + this._width);
784
+ }
785
+
786
+ this._sourcesLayer.updateSources(frameStartTime, frameEndTime);
787
+ };
788
+
789
+ TimelineZoomView.prototype.toggleMainCursor = function(on, type) {
790
+ this._isMainCursorToggled = on;
791
+
792
+ this._stage.container().style.cursor = on ?
793
+ type :
794
+ this._nativeCursor;
795
+ };
796
+
797
+ TimelineZoomView.prototype.setCursor = function(type) {
798
+ this._nativeCursor = type;
799
+ if (!this._isMainCursorToggled) {
800
+ this._stage.container().style.cursor = type;
801
+ }
802
+ };
803
+
804
+ TimelineZoomView.prototype.getCursor = function() {
805
+ return this._stage.container().style.cursor;
806
+ };
807
+
808
+ TimelineZoomView.prototype.showPlayheadTime = function(show) {
809
+ this._playheadLayer.showPlayheadTime(show);
810
+ };
811
+
812
+ TimelineZoomView.prototype.enableAutoScroll = function(enable) {
813
+ this._enableAutoScroll = enable;
814
+ };
815
+
816
+ TimelineZoomView.prototype.fitToContainer = function() {
817
+ if (this._container.clientWidth === 0 && this._container.clientHeight === 0) {
818
+ return;
819
+ }
820
+
821
+ var updateTimeline = true;
822
+
823
+ if (this._container.clientWidth !== this._width) {
824
+ this._width = this._container.clientWidth;
825
+ this._stage.width(this._width);
826
+ }
827
+
828
+ this._height = this._container.clientHeight;
829
+ this._stage.height(this._height);
830
+
831
+ this._playheadLayer.fitToView();
832
+
833
+ if (updateTimeline) {
834
+ this.updateTimeline(this._frameOffset);
835
+ }
836
+
837
+ this._stage.draw();
838
+ };
839
+
840
+ TimelineZoomView.prototype.destroy = function() {
841
+ if (this._resizeTimeoutId) {
842
+ clearTimeout(this._resizeTimeoutId);
843
+ this._resizeTimeoutId = null;
844
+ }
845
+
846
+ // Unregister event handlers
847
+ this._peaks.off('player_time_update', this._onTimeUpdate);
848
+ this._peaks.off('user_seek', this._onSeek);
849
+ this._peaks.off('player_play', this._onPlay);
850
+ this._peaks.off('player_pause', this._onPause);
851
+ this._peaks.off('window_resize', this._onWindowResize);
852
+ this._peaks.off('keyboard.left', this._onKeyboardLeft);
853
+ this._peaks.off('keyboard.right', this._onKeyboardRight);
854
+ this._peaks.off('keyboard.shift_left', this._onKeyboardShiftLeft);
855
+ this._peaks.off('keyboard.shift_right', this._onKeyboardShiftRight);
856
+ this._peaks.off('default_mode', this._onDefaultMode);
857
+ this._peaks.off('cut_mode', this._onCutMode);
858
+
859
+ if (this._stage) {
860
+ this._stage.destroy();
861
+ this._stage = null;
862
+ }
863
+ };
864
+
865
+ return TimelineZoomView;
866
+ });