wavesurfer.js 6.5.1 → 7.0.0-alpha.1

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 (132) hide show
  1. package/.eslintrc.json +24 -0
  2. package/.prettierrc +8 -0
  3. package/README.md +26 -117
  4. package/dist/base-plugin.d.ts +10 -0
  5. package/dist/base-plugin.js +13 -0
  6. package/dist/decoder.d.ts +10 -0
  7. package/dist/decoder.js +43 -0
  8. package/dist/event-emitter.d.ts +11 -0
  9. package/dist/event-emitter.js +21 -0
  10. package/dist/fetcher.d.ts +4 -0
  11. package/dist/fetcher.js +17 -0
  12. package/dist/index.d.ts +92 -0
  13. package/dist/index.js +166 -0
  14. package/dist/player-webaudio.d.ts +8 -0
  15. package/dist/player-webaudio.js +31 -0
  16. package/dist/player.d.ts +16 -0
  17. package/dist/player.js +40 -0
  18. package/dist/plugins/regions.d.ts +48 -0
  19. package/dist/plugins/regions.js +183 -0
  20. package/dist/renderer.d.ts +34 -0
  21. package/dist/renderer.js +193 -0
  22. package/dist/timer.d.ts +10 -0
  23. package/dist/timer.js +17 -0
  24. package/examples/audio.ogg +0 -0
  25. package/examples/bars.js +19 -0
  26. package/examples/basic.js +8 -0
  27. package/examples/gradient.js +28 -0
  28. package/examples/regions.js +63 -0
  29. package/examples/video.js +19 -0
  30. package/examples/webaudio.js +14 -0
  31. package/package.json +19 -99
  32. package/src/base-plugin.ts +20 -0
  33. package/src/decoder.ts +41 -0
  34. package/src/event-emitter.ts +35 -0
  35. package/src/fetcher.ts +7 -0
  36. package/src/index.ts +252 -0
  37. package/src/player-webaudio.ts +34 -0
  38. package/src/player.ts +50 -0
  39. package/src/plugins/regions.ts +240 -0
  40. package/src/renderer.ts +250 -0
  41. package/src/timer.ts +27 -0
  42. package/tsconfig.json +105 -0
  43. package/tutorial/index.html +47 -0
  44. package/tutorial/src/editor.js +70 -0
  45. package/tutorial/src/init.js +66 -0
  46. package/tutorial/src/url.js +25 -0
  47. package/tutorial/style.css +211 -0
  48. package/yarn-error.log +1049 -0
  49. package/LICENSE +0 -29
  50. package/dist/plugin/wavesurfer.cursor.js +0 -418
  51. package/dist/plugin/wavesurfer.cursor.js.map +0 -1
  52. package/dist/plugin/wavesurfer.cursor.min.js +0 -7
  53. package/dist/plugin/wavesurfer.cursor.min.js.map +0 -1
  54. package/dist/plugin/wavesurfer.elan.js +0 -381
  55. package/dist/plugin/wavesurfer.elan.js.map +0 -1
  56. package/dist/plugin/wavesurfer.elan.min.js +0 -7
  57. package/dist/plugin/wavesurfer.elan.min.js.map +0 -1
  58. package/dist/plugin/wavesurfer.markers.js +0 -520
  59. package/dist/plugin/wavesurfer.markers.js.map +0 -1
  60. package/dist/plugin/wavesurfer.markers.min.js +0 -7
  61. package/dist/plugin/wavesurfer.markers.min.js.map +0 -1
  62. package/dist/plugin/wavesurfer.mediasession.js +0 -181
  63. package/dist/plugin/wavesurfer.mediasession.js.map +0 -1
  64. package/dist/plugin/wavesurfer.mediasession.min.js +0 -7
  65. package/dist/plugin/wavesurfer.mediasession.min.js.map +0 -1
  66. package/dist/plugin/wavesurfer.microphone.js +0 -466
  67. package/dist/plugin/wavesurfer.microphone.js.map +0 -1
  68. package/dist/plugin/wavesurfer.microphone.min.js +0 -7
  69. package/dist/plugin/wavesurfer.microphone.min.js.map +0 -1
  70. package/dist/plugin/wavesurfer.minimap.js +0 -440
  71. package/dist/plugin/wavesurfer.minimap.js.map +0 -1
  72. package/dist/plugin/wavesurfer.minimap.min.js +0 -7
  73. package/dist/plugin/wavesurfer.minimap.min.js.map +0 -1
  74. package/dist/plugin/wavesurfer.playhead.js +0 -300
  75. package/dist/plugin/wavesurfer.playhead.js.map +0 -1
  76. package/dist/plugin/wavesurfer.playhead.min.js +0 -7
  77. package/dist/plugin/wavesurfer.playhead.min.js.map +0 -1
  78. package/dist/plugin/wavesurfer.regions.js +0 -1335
  79. package/dist/plugin/wavesurfer.regions.js.map +0 -1
  80. package/dist/plugin/wavesurfer.regions.min.js +0 -7
  81. package/dist/plugin/wavesurfer.regions.min.js.map +0 -1
  82. package/dist/plugin/wavesurfer.spectrogram.js +0 -736
  83. package/dist/plugin/wavesurfer.spectrogram.js.map +0 -1
  84. package/dist/plugin/wavesurfer.spectrogram.min.js +0 -7
  85. package/dist/plugin/wavesurfer.spectrogram.min.js.map +0 -1
  86. package/dist/plugin/wavesurfer.timeline.js +0 -649
  87. package/dist/plugin/wavesurfer.timeline.js.map +0 -1
  88. package/dist/plugin/wavesurfer.timeline.min.js +0 -7
  89. package/dist/plugin/wavesurfer.timeline.min.js.map +0 -1
  90. package/dist/wavesurfer-html-init.js +0 -381
  91. package/dist/wavesurfer-html-init.js.map +0 -1
  92. package/dist/wavesurfer-html-init.min.js +0 -7
  93. package/dist/wavesurfer-html-init.min.js.map +0 -1
  94. package/dist/wavesurfer.js +0 -6145
  95. package/dist/wavesurfer.js.map +0 -1
  96. package/dist/wavesurfer.min.js +0 -7
  97. package/dist/wavesurfer.min.js.map +0 -1
  98. package/src/drawer.canvasentry.js +0 -427
  99. package/src/drawer.js +0 -413
  100. package/src/drawer.multicanvas.js +0 -617
  101. package/src/html-init.js +0 -241
  102. package/src/mediaelement-webaudio.js +0 -77
  103. package/src/mediaelement.js +0 -443
  104. package/src/peakcache.js +0 -127
  105. package/src/plugin/cursor/index.js +0 -350
  106. package/src/plugin/elan/index.js +0 -307
  107. package/src/plugin/markers/index.js +0 -436
  108. package/src/plugin/mediasession/index.js +0 -94
  109. package/src/plugin/microphone/index.js +0 -415
  110. package/src/plugin/minimap/index.js +0 -403
  111. package/src/plugin/playhead/index.js +0 -226
  112. package/src/plugin/regions/index.js +0 -478
  113. package/src/plugin/regions/region.js +0 -875
  114. package/src/plugin/spectrogram/fft.js +0 -222
  115. package/src/plugin/spectrogram/index.js +0 -522
  116. package/src/plugin/timeline/index.js +0 -600
  117. package/src/util/absMax.js +0 -16
  118. package/src/util/clamp.js +0 -11
  119. package/src/util/fetch.js +0 -222
  120. package/src/util/frame.js +0 -13
  121. package/src/util/get-id.js +0 -22
  122. package/src/util/index.js +0 -14
  123. package/src/util/max.js +0 -16
  124. package/src/util/min.js +0 -16
  125. package/src/util/observer.js +0 -144
  126. package/src/util/orientation.js +0 -98
  127. package/src/util/prevent-click.js +0 -19
  128. package/src/util/request-animation-frame.js +0 -15
  129. package/src/util/silence-mode.js +0 -42
  130. package/src/util/style.js +0 -16
  131. package/src/wavesurfer.js +0 -1797
  132. package/src/webaudio.js +0 -779
@@ -1,875 +0,0 @@
1
- /**
2
- * @since 4.0.0
3
- *
4
- * (Single) Region plugin class
5
- *
6
- * Must be turned into an observer before instantiating. This is done in
7
- * `RegionsPlugin` (main plugin class).
8
- *
9
- * @extends {Observer}
10
- */
11
- export class Region {
12
- constructor(params, regionsUtils, ws) {
13
- this.wavesurfer = ws;
14
- this.wrapper = ws.drawer.wrapper;
15
- this.util = ws.util;
16
- this.style = this.util.style;
17
- this.regionsUtil = regionsUtils;
18
- this.vertical = ws.drawer.params.vertical;
19
-
20
- this.id = params.id == null ? ws.util.getId() : params.id;
21
- this.start = Number(params.start) || 0;
22
- this.end =
23
- params.end == null
24
- ? // small marker-like region
25
- this.start +
26
- (4 / this.wrapper.scrollWidth) * this.wavesurfer.getDuration()
27
- : Number(params.end);
28
- this.resize =
29
- params.resize === undefined ? true : Boolean(params.resize);
30
- this.drag = params.drag === undefined ? true : Boolean(params.drag);
31
- this.contentEditable = Boolean(params.contentEditable);
32
- this.removeButton = Boolean(params.removeButton);
33
- // reflect resize and drag state of region for region-updated listener
34
- this.isResizing = false;
35
- this.isDragging = false;
36
- this.loop = Boolean(params.loop);
37
- this.color = params.color || 'rgba(0, 0, 0, 0.1)';
38
- // The left and right handleStyle properties can be set to 'none' for
39
- // no styling or can be assigned an object containing CSS properties.
40
- this.handleStyle = params.handleStyle || {
41
- left: {},
42
- right: {}
43
- };
44
- this.handleLeftEl = null;
45
- this.handleRightEl = null;
46
- this.data = params.data || {};
47
- this.attributes = params.attributes || {};
48
- this.showTooltip = params.showTooltip ?? true;
49
-
50
- this.maxLength = params.maxLength;
51
- // It assumes the minLength parameter value, or the regionsMinLength parameter value, if the first one not provided
52
- this.minLength = params.minLength;
53
- this._onRedraw = () => this.updateRender();
54
-
55
- this.scroll = params.scroll !== false && ws.params.scrollParent;
56
- this.scrollSpeed = params.scrollSpeed || 1;
57
- this.scrollThreshold = params.scrollThreshold || 10;
58
- // Determines whether the context menu is prevented from being opened.
59
- this.preventContextMenu =
60
- params.preventContextMenu === undefined
61
- ? false
62
- : Boolean(params.preventContextMenu);
63
-
64
- // select channel ID to set region
65
- let channelIdx =
66
- params.channelIdx == null ? -1 : parseInt(params.channelIdx);
67
- this.channelIdx = channelIdx;
68
- this.regionHeight = '100%';
69
- this.marginTop = '0px';
70
-
71
- if (channelIdx !== -1) {
72
- let channelCount =
73
- this.wavesurfer.backend.buffer != null
74
- ? this.wavesurfer.backend.buffer.numberOfChannels
75
- : -1;
76
- if (channelCount >= 0 && channelIdx < channelCount) {
77
- this.regionHeight = Math.floor((1 / channelCount) * 100) + '%';
78
- this.marginTop =
79
- this.wavesurfer.getHeight() * channelIdx + 'px';
80
- }
81
- }
82
-
83
- this.formatTimeCallback = params.formatTimeCallback;
84
- this.edgeScrollWidth = params.edgeScrollWidth;
85
- this.bindInOut();
86
- this.render();
87
- this.wavesurfer.on('zoom', this._onRedraw);
88
- this.wavesurfer.on('redraw', this._onRedraw);
89
- this.wavesurfer.fireEvent('region-created', this);
90
- }
91
-
92
- /* Update region params. */
93
- update(params, eventParams) {
94
- if (params.start != null) {
95
- this.start = Number(params.start);
96
- }
97
- if (params.end != null) {
98
- this.end = Number(params.end);
99
- }
100
- if (params.loop != null) {
101
- this.loop = Boolean(params.loop);
102
- }
103
- if (params.color != null) {
104
- this.color = params.color;
105
- }
106
- if (params.handleStyle != null) {
107
- this.handleStyle = params.handleStyle;
108
- }
109
- if (params.data != null) {
110
- this.data = params.data;
111
- }
112
- if (params.resize != null) {
113
- this.resize = Boolean(params.resize);
114
- this.updateHandlesResize(this.resize);
115
- }
116
- if (params.drag != null) {
117
- this.drag = Boolean(params.drag);
118
- }
119
- if (params.maxLength != null) {
120
- this.maxLength = Number(params.maxLength);
121
- }
122
- if (params.minLength != null) {
123
- this.minLength = Number(params.minLength);
124
- }
125
- if (params.attributes != null) {
126
- this.attributes = params.attributes;
127
- }
128
-
129
- this.updateRender();
130
- this.fireEvent('update');
131
- this.wavesurfer.fireEvent('region-updated', this, eventParams);
132
- }
133
-
134
- /* Remove a single region. */
135
- remove() {
136
- if (this.element) {
137
- this.element.remove();
138
- this.element = null;
139
- this.fireEvent('remove');
140
- this.wavesurfer.un('zoom', this._onRedraw);
141
- this.wavesurfer.un('redraw', this._onRedraw);
142
- this.wavesurfer.fireEvent('region-removed', this);
143
- }
144
- }
145
-
146
- /**
147
- * Play the audio region.
148
- * @param {number} start Optional offset to start playing at
149
- */
150
- play(start) {
151
- const s = start || this.start;
152
- this.wavesurfer.play(s, this.end);
153
- this.fireEvent('play');
154
- this.wavesurfer.fireEvent('region-play', this);
155
- }
156
-
157
- /**
158
- * Play the audio region in a loop.
159
- * @param {number} start Optional offset to start playing at
160
- * */
161
- playLoop(start) {
162
- this.loop = true;
163
- this.play(start);
164
- }
165
-
166
- /**
167
- * Set looping on/off.
168
- * @param {boolean} loop True if should play in loop
169
- */
170
- setLoop(loop) {
171
- this.loop = loop;
172
- }
173
-
174
- /* Render a region as a DOM element. */
175
- render() {
176
- this.element = this.util.withOrientation(
177
- this.wrapper.appendChild(document.createElement('region')),
178
- this.vertical
179
- );
180
-
181
- this.element.className = 'wavesurfer-region';
182
- if (this.showTooltip) {
183
- this.element.title = this.formatTime(this.start, this.end);
184
- }
185
- this.element.setAttribute('data-id', this.id);
186
-
187
- for (const attrname in this.attributes) {
188
- this.element.setAttribute(
189
- 'data-region-' + attrname,
190
- this.attributes[attrname]
191
- );
192
- }
193
-
194
- this.style(this.element, {
195
- position: 'absolute',
196
- zIndex: 3,
197
- height: this.regionHeight,
198
- top: this.marginTop
199
- });
200
-
201
- /* Button Remove Region */
202
- if (this.removeButton){
203
- const removeButtonEl = document.createElement('div');
204
- removeButtonEl.className = 'remove-region-button';
205
- removeButtonEl.textContent = '⨯';
206
- this.removeButtonEl = this.element.appendChild(removeButtonEl);
207
- const css = {
208
- zIndex: 4,
209
- position: 'absolute',
210
- bottom: 0,
211
- right: '4px',
212
- cursor:'pointer',
213
- fontSize: '20px',
214
- lineHeight: '21px',
215
- color: 'grey'
216
- };
217
- this.style(this.removeButtonEl, css);
218
- }
219
-
220
- /* Edit content */
221
- if (this.contentEditable){
222
- const contentEl = document.createElement('div');
223
- contentEl.className = 'region-content';
224
- contentEl.contentEditable = 'true';
225
- contentEl.innerText = this.data.text || '';
226
- this.contentEl = this.element.appendChild(contentEl);
227
- const css = {
228
- zIndex: 4,
229
- padding: '2px 5px',
230
- cursor:'text'};
231
- this.style(this.contentEl, css);
232
- }
233
-
234
- /* Resize handles */
235
- if (this.resize) {
236
- this.handleLeftEl = this.util.withOrientation(
237
- this.element.appendChild(document.createElement('handle')),
238
- this.vertical
239
- );
240
- this.handleRightEl = this.util.withOrientation(
241
- this.element.appendChild(document.createElement('handle')),
242
- this.vertical
243
- );
244
-
245
- this.handleLeftEl.className = 'wavesurfer-handle wavesurfer-handle-start';
246
- this.handleRightEl.className = 'wavesurfer-handle wavesurfer-handle-end';
247
-
248
- // Default CSS properties for both handles.
249
- const css = {
250
- cursor: this.vertical ? 'row-resize' : 'col-resize',
251
- position: 'absolute',
252
- top: '0px',
253
- width: '2px',
254
- height: '100%',
255
- backgroundColor: 'rgba(0, 0, 0, 1)'
256
- };
257
-
258
- // Merge CSS properties per handle.
259
- const handleLeftCss =
260
- this.handleStyle.left !== 'none'
261
- ? Object.assign(
262
- { left: '0px' },
263
- css,
264
- this.handleStyle.left
265
- )
266
- : null;
267
- const handleRightCss =
268
- this.handleStyle.right !== 'none'
269
- ? Object.assign(
270
- { right: '0px' },
271
- css,
272
- this.handleStyle.right
273
- )
274
- : null;
275
-
276
- if (handleLeftCss) {
277
- this.style(this.handleLeftEl, handleLeftCss);
278
- }
279
-
280
- if (handleRightCss) {
281
- this.style(this.handleRightEl, handleRightCss);
282
- }
283
- }
284
-
285
- this.updateRender();
286
- this.bindEvents();
287
- }
288
-
289
- formatTime(start, end) {
290
- if (this.formatTimeCallback) {
291
- return this.formatTimeCallback(start, end);
292
- }
293
- return (start == end ? [start] : [start, end])
294
- .map((time) =>
295
- [
296
- Math.floor((time % 3600) / 60), // minutes
297
- ('00' + Math.floor(time % 60)).slice(-2) // seconds
298
- ].join(':')
299
- )
300
- .join('-');
301
- }
302
-
303
- getWidth() {
304
- return this.wavesurfer.drawer.width / this.wavesurfer.params.pixelRatio;
305
- }
306
-
307
- /* Update element's position, width, color. */
308
- updateRender() {
309
- // duration varies during loading process, so don't overwrite important data
310
- const dur = this.wavesurfer.getDuration();
311
- const width = this.getWidth();
312
-
313
- let startLimited = this.start;
314
- let endLimited = this.end;
315
- if (startLimited < 0) {
316
- startLimited = 0;
317
- endLimited = endLimited - startLimited;
318
- }
319
- if (endLimited > dur) {
320
- endLimited = dur;
321
- startLimited = dur - (endLimited - startLimited);
322
- }
323
-
324
- if (this.minLength != null) {
325
- endLimited = Math.max(startLimited + this.minLength, endLimited);
326
- }
327
-
328
- if (this.maxLength != null) {
329
- endLimited = Math.min(startLimited + this.maxLength, endLimited);
330
- }
331
-
332
- if (this.element != null) {
333
- // Calculate the left and width values of the region such that
334
- // no gaps appear between regions.
335
- const left = Math.round((startLimited / dur) * width);
336
- const regionWidth = Math.round((endLimited / dur) * width) - left;
337
-
338
- this.style(this.element, {
339
- left: left + 'px',
340
- width: regionWidth + 'px',
341
- backgroundColor: this.color,
342
- cursor: this.drag ? 'move' : 'default'
343
- });
344
-
345
- for (const attrname in this.attributes) {
346
- this.element.setAttribute(
347
- 'data-region-' + attrname,
348
- this.attributes[attrname]
349
- );
350
- }
351
-
352
- if (this.showTooltip) {
353
- this.element.title = this.formatTime(this.start, this.end);
354
- }
355
- }
356
- }
357
-
358
- /* Bind audio events. */
359
- bindInOut() {
360
- this.firedIn = false;
361
- this.firedOut = false;
362
-
363
- const onProcess = (time) => {
364
- let start = Math.round(this.start * 10) / 10;
365
- let end = Math.round(this.end * 10) / 10;
366
- time = Math.round(time * 10) / 10;
367
-
368
- if (
369
- !this.firedOut &&
370
- this.firedIn &&
371
- (start > time || end <= time)
372
- ) {
373
- this.firedOut = true;
374
- this.firedIn = false;
375
- this.fireEvent('out');
376
- this.wavesurfer.fireEvent('region-out', this);
377
- }
378
- if (!this.firedIn && start <= time && end > time) {
379
- this.firedIn = true;
380
- this.firedOut = false;
381
- this.fireEvent('in');
382
- this.wavesurfer.fireEvent('region-in', this);
383
- }
384
- };
385
-
386
- this.wavesurfer.backend.on('audioprocess', onProcess);
387
-
388
- this.on('remove', () => {
389
- this.wavesurfer.backend.un('audioprocess', onProcess);
390
- });
391
-
392
- /* Loop playback. */
393
- this.on('out', () => {
394
- if (this.loop) {
395
- const realTime = this.wavesurfer.getCurrentTime();
396
- if (realTime >= this.start && realTime <= this.end) {
397
- this.wavesurfer.play(this.start);
398
- }
399
- }
400
- });
401
- }
402
-
403
- /* Bind DOM events. */
404
- bindEvents() {
405
- const preventContextMenu = this.preventContextMenu;
406
-
407
- this.element.addEventListener('mouseenter', (e) => {
408
- this.fireEvent('mouseenter', e);
409
- this.wavesurfer.fireEvent('region-mouseenter', this, e);
410
- });
411
-
412
- this.element.addEventListener('mouseleave', (e) => {
413
- this.fireEvent('mouseleave', e);
414
- this.wavesurfer.fireEvent('region-mouseleave', this, e);
415
- });
416
-
417
- this.element.addEventListener('click', (e) => {
418
- e.preventDefault();
419
- this.fireEvent('click', e);
420
- this.wavesurfer.fireEvent('region-click', this, e);
421
- });
422
-
423
- this.element.addEventListener('dblclick', (e) => {
424
- e.stopPropagation();
425
- e.preventDefault();
426
- this.fireEvent('dblclick', e);
427
- this.wavesurfer.fireEvent('region-dblclick', this, e);
428
- });
429
-
430
- this.element.addEventListener('contextmenu', (e) => {
431
- if (preventContextMenu) {
432
- e.preventDefault();
433
- }
434
- this.fireEvent('contextmenu', e);
435
- this.wavesurfer.fireEvent('region-contextmenu', this, e);
436
- });
437
-
438
- /* Drag or resize on mousemove. */
439
- if (this.drag || this.resize) {
440
- this.bindDragEvents();
441
- }
442
-
443
- /* Edit content */
444
- if (this.contentEditable){
445
- this.contentEl.addEventListener('blur', this.onContentBlur.bind(this));
446
- this.contentEl.addEventListener('click', this.onContentClick.bind(this));
447
- }
448
- /* Remove button */
449
- if (this.removeButton){
450
- this.removeButtonEl.addEventListener('click', this.onRemove.bind(this));
451
- }
452
- }
453
-
454
- bindDragEvents() {
455
- const container = this.wavesurfer.drawer.container;
456
- const scrollSpeed = this.scrollSpeed;
457
- let startTime;
458
- let touchId;
459
- let drag;
460
- let maxScroll;
461
- let resize;
462
- let updated = false;
463
- let scrollDirection;
464
- let wrapperRect;
465
- let regionLeftHalfTime;
466
- let regionRightHalfTime;
467
-
468
- // Scroll when the user is dragging within the threshold
469
- const edgeScroll = (event) => {
470
- let orientedEvent = this.util.withOrientation(event, this.vertical);
471
- const duration = this.wavesurfer.getDuration();
472
- if (!scrollDirection || (!drag && !resize)) {
473
- return;
474
- }
475
-
476
- const x = orientedEvent.clientX;
477
- let distanceBetweenCursorAndWrapperEdge = 0;
478
- let regionHalfTimeWidth = 0;
479
- let adjustment = 0;
480
-
481
- // Get the currently selected time according to the mouse position
482
- let time = this.regionsUtil.getRegionSnapToGridValue(
483
- this.wavesurfer.drawer.handleEvent(event) * duration
484
- );
485
-
486
- if (drag) {
487
- // Considering the point of contact with the region while edgescrolling
488
- if (scrollDirection === -1) {
489
- regionHalfTimeWidth = regionLeftHalfTime * this.wavesurfer.params.minPxPerSec;
490
- distanceBetweenCursorAndWrapperEdge = x - wrapperRect.left;
491
- } else {
492
- regionHalfTimeWidth = regionRightHalfTime * this.wavesurfer.params.minPxPerSec;
493
- distanceBetweenCursorAndWrapperEdge = wrapperRect.right - x;
494
- }
495
- } else {
496
- // Considering minLength while edgescroll
497
- let minLength = this.minLength;
498
- if (!minLength) {
499
- minLength = 0;
500
- }
501
-
502
- if (resize === 'start') {
503
- if (time > this.end - minLength) {
504
- time = this.end - minLength;
505
- adjustment = scrollSpeed * scrollDirection;
506
- }
507
-
508
- if (time < 0) {
509
- time = 0;
510
- }
511
- } else if (resize === 'end') {
512
- if (time < this.start + minLength) {
513
- time = this.start + minLength;
514
- adjustment = scrollSpeed * scrollDirection;
515
- }
516
-
517
- if (time > duration) {
518
- time = duration;
519
- }
520
- }
521
- }
522
-
523
- // Don't edgescroll if region has reached min or max limit
524
- const wrapperScrollLeft = this.wrapper.scrollLeft;
525
-
526
- if (scrollDirection === -1) {
527
- if (Math.round(wrapperScrollLeft) === 0) {
528
- return;
529
- }
530
-
531
- if (Math.round(wrapperScrollLeft - regionHalfTimeWidth + distanceBetweenCursorAndWrapperEdge) <= 0) {
532
- return;
533
- }
534
- } else {
535
- if (Math.round(wrapperScrollLeft) === maxScroll) {
536
- return;
537
- }
538
-
539
- if (Math.round(wrapperScrollLeft + regionHalfTimeWidth - distanceBetweenCursorAndWrapperEdge) >= maxScroll) {
540
- return;
541
- }
542
- }
543
-
544
- // Update scroll position
545
- let scrollLeft = wrapperScrollLeft - adjustment + scrollSpeed * scrollDirection;
546
-
547
- if (scrollDirection === -1) {
548
- const calculatedLeft = Math.max(0 + regionHalfTimeWidth - distanceBetweenCursorAndWrapperEdge, scrollLeft);
549
- this.wrapper.scrollLeft = scrollLeft = calculatedLeft;
550
- } else {
551
- const calculatedRight = Math.min(maxScroll - regionHalfTimeWidth + distanceBetweenCursorAndWrapperEdge, scrollLeft);
552
- this.wrapper.scrollLeft = scrollLeft = calculatedRight;
553
- }
554
-
555
- const delta = time - startTime;
556
- startTime = time;
557
-
558
- // Continue dragging or resizing
559
- drag ? this.onDrag(delta) : this.onResize(delta, resize);
560
-
561
- // Repeat
562
- window.requestAnimationFrame(() => {
563
- edgeScroll(event);
564
- });
565
- };
566
-
567
- const onDown = (event) => {
568
- const duration = this.wavesurfer.getDuration();
569
- if (event.touches && event.touches.length > 1) {
570
- return;
571
- }
572
- touchId = event.targetTouches ? event.targetTouches[0].identifier : null;
573
-
574
- // stop the event propagation, if this region is resizable or draggable
575
- // and the event is therefore handled here.
576
- if (this.drag || this.resize) {
577
- event.stopPropagation();
578
- }
579
-
580
- // Store the selected startTime we begun dragging or resizing
581
- startTime = this.regionsUtil.getRegionSnapToGridValue(
582
- this.wavesurfer.drawer.handleEvent(event, true) * duration
583
- );
584
-
585
- // Store the selected point of contact when we begin dragging
586
- regionLeftHalfTime = startTime - this.start;
587
- regionRightHalfTime = this.end - startTime;
588
-
589
- // Store for scroll calculations
590
- maxScroll = this.wrapper.scrollWidth - this.wrapper.clientWidth;
591
-
592
- wrapperRect = this.util.withOrientation(
593
- this.wrapper.getBoundingClientRect(),
594
- this.vertical
595
- );
596
-
597
- this.isResizing = false;
598
- this.isDragging = false;
599
- if (event.target.tagName.toLowerCase() === 'handle') {
600
- this.isResizing = true;
601
- resize = event.target.classList.contains('wavesurfer-handle-start')
602
- ? 'start'
603
- : 'end';
604
- } else {
605
- this.isDragging = true;
606
- drag = true;
607
- resize = false;
608
- }
609
- };
610
- const onUp = (event) => {
611
- if (event.touches && event.touches.length > 1) {
612
- return;
613
- }
614
-
615
- if (drag || resize) {
616
- this.isDragging = false;
617
- this.isResizing = false;
618
- drag = false;
619
- scrollDirection = null;
620
- resize = false;
621
- }
622
-
623
- if (updated) {
624
- updated = false;
625
- this.util.preventClick();
626
- this.fireEvent('update-end', event);
627
- this.wavesurfer.fireEvent('region-update-end', this, event);
628
- }
629
- };
630
- const onMove = (event) => {
631
- const duration = this.wavesurfer.getDuration();
632
- let orientedEvent = this.util.withOrientation(event, this.vertical);
633
- let delta = null;
634
-
635
- if (event.touches && event.touches.length > 1) {
636
- return;
637
- }
638
- if (event.targetTouches && event.targetTouches[0].identifier != touchId) {
639
- return;
640
- }
641
- if (!drag && !resize) {
642
- return;
643
- }
644
-
645
- const oldTime = startTime;
646
- let time = this.regionsUtil.getRegionSnapToGridValue(
647
- this.wavesurfer.drawer.handleEvent(event) * duration
648
- );
649
-
650
- if (drag) {
651
- // To maintain relative cursor start point while dragging
652
- const maxEnd = this.wavesurfer.getDuration();
653
- if (time > maxEnd - regionRightHalfTime) {
654
- time = maxEnd - regionRightHalfTime;
655
- }
656
-
657
- if (time - regionLeftHalfTime < 0) {
658
- time = regionLeftHalfTime;
659
- }
660
- }
661
-
662
- if (resize) {
663
- // To maintain relative cursor start point while resizing
664
- // we have to handle for minLength
665
- let minLength = this.minLength;
666
- if (!minLength) {
667
- minLength = 0;
668
- }
669
-
670
- if (resize === 'start') {
671
- if (time > this.end - minLength) {
672
- time = this.end - minLength;
673
- }
674
-
675
- if (time < 0) {
676
- time = 0;
677
- }
678
- } else if (resize === 'end') {
679
- if (time < this.start + minLength) {
680
- // Calculate the end time based on the min length of the region.
681
- time = this.start + minLength;
682
- delta = time - (this.end + (time - startTime));
683
- }
684
-
685
- if (time > duration) {
686
- time = duration;
687
- }
688
- }
689
- }
690
-
691
- if (!delta) {
692
- delta = time - startTime;
693
- }
694
-
695
- startTime = time;
696
-
697
- // Drag
698
- if (this.drag && drag) {
699
- updated = updated || !!delta;
700
- this.onDrag(delta);
701
- }
702
-
703
- // Resize
704
- if (this.resize && resize) {
705
- updated = updated || !!delta;
706
- this.onResize(delta, resize);
707
- }
708
-
709
- if (
710
- this.scroll && container.clientWidth < this.wrapper.scrollWidth
711
- ) {
712
- // Triggering edgescroll from within edgeScrollWidth
713
- let x = orientedEvent.clientX;
714
-
715
- // Check direction
716
- if (x < wrapperRect.left + this.edgeScrollWidth) {
717
- scrollDirection = -1;
718
- } else if (x > wrapperRect.right - this.edgeScrollWidth) {
719
- scrollDirection = 1;
720
- } else {
721
- scrollDirection = null;
722
- }
723
-
724
- if (scrollDirection) {
725
- edgeScroll(event);
726
- }
727
- }
728
- };
729
-
730
- this.element.addEventListener('mousedown', onDown);
731
- this.element.addEventListener('touchstart', onDown);
732
-
733
- document.body.addEventListener('mousemove', onMove);
734
- document.body.addEventListener('touchmove', onMove, {passive: false});
735
-
736
- document.addEventListener('mouseup', onUp);
737
- document.body.addEventListener('touchend', onUp);
738
-
739
- this.on('remove', () => {
740
- document.removeEventListener('mouseup', onUp);
741
- document.body.removeEventListener('touchend', onUp);
742
- document.body.removeEventListener('mousemove', onMove);
743
- document.body.removeEventListener('touchmove', onMove);
744
- });
745
-
746
- this.wavesurfer.on('destroy', () => {
747
- document.removeEventListener('mouseup', onUp);
748
- document.body.removeEventListener('touchend', onUp);
749
- });
750
- }
751
-
752
- onDrag(delta) {
753
- const maxEnd = this.wavesurfer.getDuration();
754
- if (this.end + delta > maxEnd) {
755
- delta = maxEnd - this.end;
756
- }
757
-
758
- if (this.start + delta < 0) {
759
- delta = this.start * -1;
760
- }
761
-
762
- const eventParams = {
763
- direction: this._getDragDirection(delta),
764
- action: 'drag'
765
- };
766
-
767
- this.update({
768
- start: this.start + delta,
769
- end: this.end + delta
770
- }, eventParams);
771
- }
772
-
773
- /**
774
- * Returns the direction of dragging region based on delta
775
- * Negative delta means region is moving to the left
776
- * Positive - to the right
777
- * For zero delta the direction is not defined
778
- * @param {number} delta Drag offset
779
- * @returns {string|null} Direction 'left', 'right' or null
780
- */
781
- _getDragDirection(delta) {
782
- if (delta < 0) {
783
- return 'left';
784
- }
785
- if (delta > 0) {
786
- return 'right';
787
- }
788
- return null;
789
- }
790
-
791
- /**
792
- * @example
793
- * onResize(-5, 'start') // Moves the start point 5 seconds back
794
- * onResize(0.5, 'end') // Moves the end point 0.5 seconds forward
795
- *
796
- * @param {number} delta How much to add or subtract, given in seconds
797
- * @param {string} direction 'start 'or 'end'
798
- */
799
- onResize(delta, direction) {
800
- const duration = this.wavesurfer.getDuration();
801
- const eventParams = {
802
- action: 'resize',
803
- direction: direction === 'start' ? 'left' : 'right'
804
- };
805
-
806
- if (direction === 'start') {
807
- // Check if changing the start by the given delta would result in the region being smaller than minLength
808
- if (delta > 0 && this.end - (this.start + delta) < this.minLength) {
809
- delta = this.end - this.minLength - this.start;
810
- }
811
-
812
- // Check if changing the start by the given delta would result in the region being larger than maxLength
813
- if (delta < 0 && this.end - (this.start + delta) > this.maxLength) {
814
- delta = this.end - this.start - this.maxLength;
815
- }
816
-
817
- if (delta < 0 && (this.start + delta) < 0) {
818
- delta = this.start * -1;
819
- }
820
-
821
- this.update({
822
- start: Math.min(this.start + delta, this.end),
823
- end: Math.max(this.start + delta, this.end)
824
- }, eventParams);
825
- } else {
826
- // Check if changing the end by the given delta would result in the region being smaller than minLength
827
- if (delta < 0 && this.end + delta - this.start < this.minLength) {
828
- delta = this.start + this.minLength - this.end;
829
- }
830
-
831
- // Check if changing the end by the given delta would result in the region being larger than maxLength
832
- if (delta > 0 && this.end + delta - this.start > this.maxLength) {
833
- delta = this.maxLength - (this.end - this.start);
834
- }
835
-
836
- if (delta > 0 && (this.end + delta) > duration) {
837
- delta = duration - this.end;
838
- }
839
-
840
- this.update({
841
- start: Math.min(this.end + delta, this.start),
842
- end: Math.max(this.end + delta, this.start)
843
- }, eventParams);
844
- }
845
- }
846
-
847
- onContentBlur(event){
848
- const {text: oldText} = this.data || {};
849
- const text = event.target.innerText;
850
- const data = {...this.data, text };
851
- const eventParams = {action: 'contentEdited', oldText, text};
852
- this.update({data}, eventParams);
853
- }
854
-
855
- onContentClick(event){
856
- event.stopPropagation();
857
- }
858
-
859
- onRemove(event){
860
- event.stopPropagation();
861
- this.remove();
862
- }
863
-
864
- updateHandlesResize(resize) {
865
- let cursorStyle;
866
- if (resize) {
867
- cursorStyle = this.vertical ? 'row-resize' : 'col-resize';
868
- } else {
869
- cursorStyle = 'auto';
870
- }
871
-
872
- this.handleLeftEl && this.style(this.handleLeftEl, { cursor: cursorStyle });
873
- this.handleRightEl && this.style(this.handleRightEl, { cursor: cursorStyle });
874
- }
875
- }