wavesurfer.js 6.2.0 → 6.4.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 (58) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +1 -10
  3. package/dist/plugin/wavesurfer.cursor.js +29 -49
  4. package/dist/plugin/wavesurfer.cursor.js.map +1 -1
  5. package/dist/plugin/wavesurfer.cursor.min.js +2 -2
  6. package/dist/plugin/wavesurfer.cursor.min.js.map +1 -1
  7. package/dist/plugin/wavesurfer.elan.js +19 -49
  8. package/dist/plugin/wavesurfer.elan.js.map +1 -1
  9. package/dist/plugin/wavesurfer.elan.min.js +1 -1
  10. package/dist/plugin/wavesurfer.elan.min.js.map +1 -1
  11. package/dist/plugin/wavesurfer.markers.js +87 -67
  12. package/dist/plugin/wavesurfer.markers.js.map +1 -1
  13. package/dist/plugin/wavesurfer.markers.min.js +2 -2
  14. package/dist/plugin/wavesurfer.markers.min.js.map +1 -1
  15. package/dist/plugin/wavesurfer.mediasession.js +5 -15
  16. package/dist/plugin/wavesurfer.mediasession.js.map +1 -1
  17. package/dist/plugin/wavesurfer.mediasession.min.js +1 -1
  18. package/dist/plugin/wavesurfer.mediasession.min.js.map +1 -1
  19. package/dist/plugin/wavesurfer.microphone.js +44 -62
  20. package/dist/plugin/wavesurfer.microphone.js.map +1 -1
  21. package/dist/plugin/wavesurfer.microphone.min.js +1 -1
  22. package/dist/plugin/wavesurfer.microphone.min.js.map +1 -1
  23. package/dist/plugin/wavesurfer.minimap.js +16 -68
  24. package/dist/plugin/wavesurfer.minimap.js.map +1 -1
  25. package/dist/plugin/wavesurfer.minimap.min.js +1 -1
  26. package/dist/plugin/wavesurfer.minimap.min.js.map +1 -1
  27. package/dist/plugin/wavesurfer.playhead.js +2 -29
  28. package/dist/plugin/wavesurfer.playhead.js.map +1 -1
  29. package/dist/plugin/wavesurfer.playhead.min.js +1 -1
  30. package/dist/plugin/wavesurfer.playhead.min.js.map +1 -1
  31. package/dist/plugin/wavesurfer.regions.js +99 -253
  32. package/dist/plugin/wavesurfer.regions.js.map +1 -1
  33. package/dist/plugin/wavesurfer.regions.min.js +2 -2
  34. package/dist/plugin/wavesurfer.regions.min.js.map +1 -1
  35. package/dist/plugin/wavesurfer.spectrogram.js +52 -147
  36. package/dist/plugin/wavesurfer.spectrogram.js.map +1 -1
  37. package/dist/plugin/wavesurfer.spectrogram.min.js +2 -2
  38. package/dist/plugin/wavesurfer.spectrogram.min.js.map +1 -1
  39. package/dist/plugin/wavesurfer.timeline.js +42 -85
  40. package/dist/plugin/wavesurfer.timeline.js.map +1 -1
  41. package/dist/plugin/wavesurfer.timeline.min.js +1 -1
  42. package/dist/plugin/wavesurfer.timeline.min.js.map +1 -1
  43. package/dist/wavesurfer-html-init.js +31 -53
  44. package/dist/wavesurfer-html-init.js.map +1 -1
  45. package/dist/wavesurfer-html-init.min.js +1 -1
  46. package/dist/wavesurfer-html-init.min.js.map +1 -1
  47. package/dist/wavesurfer.js +448 -1008
  48. package/dist/wavesurfer.js.map +1 -1
  49. package/dist/wavesurfer.min.js +2 -2
  50. package/dist/wavesurfer.min.js.map +1 -1
  51. package/package.json +18 -19
  52. package/src/drawer.multicanvas.js +4 -4
  53. package/src/plugin/cursor/index.js +15 -3
  54. package/src/plugin/markers/index.js +70 -5
  55. package/src/plugin/regions/index.js +1 -1
  56. package/src/plugin/spectrogram/index.js +1 -1
  57. package/src/wavesurfer.js +12 -9
  58. package/CHANGES.md +0 -474
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wavesurfer.js",
3
- "version": "6.2.0",
3
+ "version": "6.4.0",
4
4
  "description": "Interactive navigable audio visualization using Web Audio and Canvas",
5
5
  "main": "dist/wavesurfer.js",
6
6
  "directories": {
@@ -55,17 +55,16 @@
55
55
  "visualization"
56
56
  ],
57
57
  "devDependencies": {
58
- "@babel/core": "^7.17.8",
59
- "@babel/eslint-parser": "^7.17.0",
60
- "@babel/plugin-proposal-class-properties": "^7.16.7",
61
- "@babel/preset-env": "^7.16.11",
62
- "@babel/register": "^7.17.7",
63
- "@chiragrupani/karma-chromium-edge-launcher": "^2.2.1",
64
- "babel-loader": "^8.2.4",
58
+ "@babel/core": "^7.20.2",
59
+ "@babel/eslint-parser": "^7.19.1",
60
+ "@babel/plugin-proposal-class-properties": "^7.18.6",
61
+ "@babel/preset-env": "^7.20.2",
62
+ "@babel/register": "^7.18.9",
63
+ "@chiragrupani/karma-chromium-edge-launcher": "^2.2.2",
64
+ "babel-loader": "^9.1.0",
65
65
  "babel-plugin-add-module-exports": "^1.0.4",
66
66
  "babel-plugin-istanbul": "^6.1.1",
67
- "babel-plugin-proxy": "^1.1.0",
68
- "date-fns": "^2.28.0",
67
+ "date-fns": "^2.29.3",
69
68
  "debounce": "^1.2.1",
70
69
  "esdoc": "^1.1.0",
71
70
  "esdoc-accessor-plugin": "^1.0.0",
@@ -74,24 +73,24 @@
74
73
  "esdoc-ecmascript-proposal-plugin": "^1.0.0",
75
74
  "esdoc-integrate-test-plugin": "^1.0.0",
76
75
  "esdoc-standard-plugin": "^1.0.0",
77
- "eslint": "^8.11.0",
78
- "htmlhint": "^1.1.2",
76
+ "eslint": "^8.26.0",
77
+ "htmlhint": "^1.1.4",
79
78
  "in-publish": "^2.0.1",
80
- "jasmine-core": "^4.0.1",
81
- "karma": "^6.3.17",
79
+ "jasmine-core": "^4.5.0",
80
+ "karma": "^6.4.1",
82
81
  "karma-chrome-launcher": "3.1.1",
83
82
  "karma-coverage": "^2.2.0",
84
83
  "karma-firefox-launcher": "^2.1.2",
85
- "karma-jasmine": "4.0.1",
84
+ "karma-jasmine": "5.1.0",
86
85
  "karma-jasmine-matchers": "5.0.0",
87
86
  "karma-verbose-reporter": "0.0.8",
88
87
  "karma-webpack": "^5.0.0",
89
- "lint-staged": "^12.3.7",
88
+ "lint-staged": "^13.0.3",
90
89
  "load-script": "^2.0.0",
91
90
  "pre-commit": "^1.2.2",
92
- "webpack": "^5.70.0",
93
- "webpack-cli": "^4.9.2",
94
- "webpack-dev-server": "^4.7.4",
91
+ "webpack": "^5.74.0",
92
+ "webpack-cli": "^4.10.0",
93
+ "webpack-dev-server": "^4.11.1",
95
94
  "webpack-merge": "^5.8.0"
96
95
  },
97
96
  "homepage": "https://wavesurfer-js.org",
@@ -323,10 +323,10 @@ export default class MultiCanvas extends Drawer {
323
323
  // calculate the height of this bar according to the highest peak found
324
324
  let h = Math.round((peak / absmax) * halfH);
325
325
 
326
- // in case of silences, allow the user to specify that we
327
- // always draw *something* (normally a 1px high bar)
328
- if (h == 0 && this.params.barMinHeight) {
329
- h = this.params.barMinHeight;
326
+ // raise the bar height to the specified minimum height
327
+ // Math.max is used to replace any value smaller than barMinHeight (not just 0) with barMinHeight
328
+ if (this.params.barMinHeight) {
329
+ h = Math.max(h, this.params.barMinHeight);
330
330
  }
331
331
 
332
332
  this.fillRect(
@@ -17,6 +17,7 @@
17
17
  * the cursor follow the x and the y-position of the mouse. Use `false` to make the
18
18
  * it only follow the x-position of the mouse.
19
19
  * @property {function} formatTimeCallback Formats the timestamp on the cursor.
20
+ * @property {boolean} isDestroyCalled true if called destroy before the ready event fired
20
21
  */
21
22
 
22
23
  /**
@@ -140,11 +141,19 @@ export default class CursorPlugin {
140
141
  * @type {?HTMLElement}
141
142
  */
142
143
  this.displayTime = null;
144
+ /**
145
+ * true if call destory before ready event
146
+ * @type {boolean}
147
+ */
148
+ this.isDestroyCalled = false;
143
149
 
144
150
  this.params = Object.assign({}, this.defaultParams, params);
145
151
  }
146
152
 
147
153
  _onReady() {
154
+ if (this.isDestroyCalled) {
155
+ return;
156
+ }
148
157
  this.wrapper = this.wavesurfer.drawer.wrapper;
149
158
  this.cursor = this.util.withOrientation(this.wrapper.appendChild(
150
159
  document.createElement('cursor'),
@@ -237,10 +246,14 @@ export default class CursorPlugin {
237
246
  * Destroy the plugin (used by the Plugin API)
238
247
  */
239
248
  destroy() {
249
+ if (!this.cursorTime || !this.showTime){
250
+ this.isDestroyCalled = true;
251
+ return;
252
+ }
240
253
  if (this.params.showTime) {
241
- this.showTime.remove();
254
+ this.showTime && this.showTime.remove();
242
255
  }
243
- this.cursor.remove();
256
+ this.cursor && this.cursor.remove();
244
257
  this.wrapper.removeEventListener('mousemove', this._onMousemove);
245
258
  if (this.params.hideOnBlur) {
246
259
  this.wrapper.removeEventListener('mouseenter', this._onMouseenter);
@@ -323,7 +336,6 @@ export default class CursorPlugin {
323
336
  */
324
337
  formatTime(cursorTime) {
325
338
  cursorTime = isNaN(cursorTime) ? 0 : cursorTime;
326
-
327
339
  if (this.params.formatTimeCallback) {
328
340
  return this.params.formatTimeCallback(cursorTime);
329
341
  }
@@ -4,10 +4,13 @@
4
4
  * @example wavesurfer.addMarker(regionParams);
5
5
  * @property {number} time The time to set the marker at
6
6
  * @property {?label} string An optional marker label
7
+ * @property {?tooltip} string An optional marker tooltip
7
8
  * @property {?color} string Background color for marker
8
9
  * @property {?position} string "top" or "bottom", defaults to "bottom"
9
10
  * @property {?markerElement} element An HTML element to display instead of the default marker image
10
11
  * @property {?draggable} boolean Set marker as draggable, defaults to false
12
+ * @property {?boolean} preventContextMenu Determines whether the context menu
13
+ * is prevented from being opened, defaults to false
11
14
  */
12
15
 
13
16
 
@@ -157,9 +160,11 @@ export default class MarkersPlugin {
157
160
  let marker = {
158
161
  time: params.time,
159
162
  label: params.label,
163
+ tooltip: params.tooltip,
160
164
  color: params.color || DEFAULT_FILL_COLOR,
161
165
  position: params.position || DEFAULT_POSITION,
162
- draggable: !!params.draggable
166
+ draggable: !!params.draggable,
167
+ preventContextMenu: !!params.preventContextMenu
163
168
  };
164
169
 
165
170
  marker.el = this._createMarkerElement(marker, params.markerElement);
@@ -168,6 +173,8 @@ export default class MarkersPlugin {
168
173
  this.markers.push(marker);
169
174
  this._updateMarkerPositions();
170
175
 
176
+ this._registerEvents();
177
+
171
178
  return marker;
172
179
  }
173
180
 
@@ -181,9 +188,23 @@ export default class MarkersPlugin {
181
188
  if (!marker) {
182
189
  return;
183
190
  }
191
+ let label = marker.el.getElementsByClassName("marker-label")[0];
192
+ if (label) {
193
+ if (label._onContextMenu) {
194
+ label.removeEventListener("contextmenu", label._onContextMenu);
195
+ }
196
+ if (label._onClick) {
197
+ label.removeEventListener("click", label._onClick);
198
+ }
199
+ if (label._onMouseDown) {
200
+ label.removeEventListener("mousedown", label._onMouseDown);
201
+ }
202
+ }
184
203
 
185
204
  this.wrapper.removeChild(marker.el);
186
205
  this.markers.splice(index, 1);
206
+
207
+ this._unregisterEvents();
187
208
  }
188
209
 
189
210
  _createPointerSVG(color, position) {
@@ -216,6 +237,7 @@ export default class MarkersPlugin {
216
237
 
217
238
  _createMarkerElement(marker, markerElement) {
218
239
  let label = marker.label;
240
+ let tooltip = marker.tooltip;
219
241
 
220
242
  const el = document.createElement('marker');
221
243
  el.className = "wavesurfer-marker";
@@ -250,6 +272,7 @@ export default class MarkersPlugin {
250
272
  if ( label ) {
251
273
  const labelEl = document.createElement('span');
252
274
  labelEl.innerText = label;
275
+ labelEl.setAttribute('title', tooltip);
253
276
  this.style(labelEl, {
254
277
  "font-family": "monospace",
255
278
  "font-size": "90%"
@@ -262,10 +285,11 @@ export default class MarkersPlugin {
262
285
  "align-items": "center",
263
286
  cursor: "pointer"
264
287
  });
288
+ labelDiv.classList.add("marker-label");
265
289
 
266
290
  el.appendChild(labelDiv);
267
291
 
268
- labelDiv.addEventListener("click", e => {
292
+ labelDiv._onClick = (e) => {
269
293
  e.stopPropagation();
270
294
  // Click event is caught when the marker-drop event was dispatched.
271
295
  // Drop event was dispatched at this moment, but this.dragging
@@ -275,12 +299,22 @@ export default class MarkersPlugin {
275
299
  }
276
300
  this.wavesurfer.setCurrentTime(marker.time);
277
301
  this.wavesurfer.fireEvent("marker-click", marker, e);
278
- });
302
+ };
303
+ labelDiv.addEventListener("click", labelDiv._onClick);
304
+
305
+ labelDiv._onContextMenu = (e) => {
306
+ if (marker.preventContextMenu) {
307
+ e.preventDefault();
308
+ }
309
+ this.wavesurfer.fireEvent("marker-contextmenu", marker, e);
310
+ };
311
+ labelDiv.addEventListener("contextmenu", labelDiv._onContextMenu);
279
312
 
280
313
  if (marker.draggable) {
281
- labelDiv.addEventListener("mousedown", e => {
314
+ labelDiv._onMouseDown = () => {
282
315
  this.selectedMarker = marker;
283
- });
316
+ };
317
+ labelDiv.addEventListener("mousedown", labelDiv._onMouseDown);
284
318
  }
285
319
  return el;
286
320
  }
@@ -360,6 +394,37 @@ export default class MarkersPlugin {
360
394
  this.wavesurfer.fireEvent("marker-drop", this.selectedMarker, event);
361
395
  }
362
396
 
397
+ _registerEvents() {
398
+ if (!this.markers.find(marker => marker.draggable)) {
399
+ return;
400
+ }
401
+ //we have some draggable markers, check for listeners
402
+ if (!this.onMouseMove) {
403
+ this.onMouseMove = (e) => this._onMouseMove(e);
404
+ window.addEventListener('mousemove', this.onMouseMove);
405
+ }
406
+
407
+ if (!this.onMouseUp) {
408
+ this.onMouseUp = (e) => this._onMouseUp(e);
409
+ window.addEventListener("mouseup", this.onMouseUp);
410
+ }
411
+ }
412
+
413
+ _unregisterEvents() {
414
+ if (this.markers.find(marker => marker.draggable)) {
415
+ return;
416
+ }
417
+ //we don't have any draggable markers, unregister listeners
418
+ if (this.onMouseMove) {
419
+ window.removeEventListener('mousemove', this.onMouseMove);
420
+ this.onMouseMove = null;
421
+ }
422
+ if (this.onMouseUp) {
423
+ window.removeEventListener("mouseup", this.onMouseUp);
424
+ this.onMouseUp = null;
425
+ }
426
+ }
427
+
363
428
  /**
364
429
  * Remove all markers
365
430
  */
@@ -299,7 +299,7 @@ export default class RegionsPlugin {
299
299
  );
300
300
 
301
301
  // set the region channel index based on the clicked area
302
- if (this.wavesurfer.params.splitChannels) {
302
+ if (this.wavesurfer.params.splitChannels && this.wavesurfer.params.splitChannelsOptions.splitDragSelection) {
303
303
  const y = (e.touches ? e.touches[0].clientY : e.clientY) - wrapperRect.top;
304
304
  const channelCount = this.wavesurfer.backend.buffer != null ? this.wavesurfer.backend.buffer.numberOfChannels : 1;
305
305
  const channelHeight = this.wrapper.clientHeight / channelCount;
@@ -187,7 +187,7 @@ export default class SpectrogramPlugin {
187
187
  const labelsEl = (this.labelsEl = document.createElement('canvas'));
188
188
  labelsEl.classList.add('spec-labels');
189
189
  this.drawer.style(labelsEl, {
190
- position: 'fixed',
190
+ position: 'absolute',
191
191
  zIndex: 9,
192
192
  height: `${this.height * this.channels}px`,
193
193
  width: `55px`
package/src/wavesurfer.js CHANGED
@@ -174,6 +174,8 @@ import MediaElementWebAudio from './mediaelement-webaudio';
174
174
  * @property {boolean} relativeNormalization=false determines whether
175
175
  * normalization is done per channel or maintains proportionality between
176
176
  * channels. Only applied when normalize and splitChannels are both true.
177
+ * @property {boolean} splitDragSelection=false determines if drag selection in regions
178
+ * plugin works separately on each channel or only one selection for all channels
177
179
  * @since 4.3.0
178
180
  */
179
181
 
@@ -298,7 +300,8 @@ export default class WaveSurfer extends util.Observer {
298
300
  overlay: false,
299
301
  channelColors: {},
300
302
  filterChannels: [],
301
- relativeNormalization: false
303
+ relativeNormalization: false,
304
+ splitDragSelection: false
302
305
  },
303
306
  vertical: false,
304
307
  waveColor: '#999',
@@ -1684,19 +1687,19 @@ export default class WaveSurfer extends util.Observer {
1684
1687
  /**
1685
1688
  * Save waveform image as data URI.
1686
1689
  *
1687
- * The default format is `'image/png'`. Other supported types are
1688
- * `'image/jpeg'` and `'image/webp'`.
1690
+ * The default format is `image/png`. Other supported types are
1691
+ * `image/jpeg` and `image/webp`.
1689
1692
  *
1690
1693
  * @param {string} format='image/png' A string indicating the image format.
1691
- * The default format type is `'image/png'`.
1694
+ * The default format type is `image/png`.
1692
1695
  * @param {number} quality=1 A number between 0 and 1 indicating the image
1693
1696
  * quality to use for image formats that use lossy compression such as
1694
- * `'image/jpeg'`` and `'image/webp'`.
1695
- * @param {string} type Image data type to return. Either 'dataURL' (default)
1696
- * or 'blob'.
1697
- * @return {string|string[]|Promise} When using `'dataURL'` type this returns
1697
+ * `image/jpeg` and `image/webp`.
1698
+ * @param {string} type Image data type to return. Either `dataURL` (default)
1699
+ * or `blob`.
1700
+ * @return {string|string[]|Promise} When using `dataURL` type this returns
1698
1701
  * a single data URL or an array of data URLs, one for each canvas. When using
1699
- * `'blob'` type this returns a `Promise` resolving with an array of `Blob`
1702
+ * `blob` type this returns a `Promise` resolving with an array of `Blob`
1700
1703
  * instances, one for each canvas.
1701
1704
  */
1702
1705
  exportImage(format, quality, type) {