wavesurfer.js 7.0.0-alpha.3 → 7.0.0-alpha.31

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 (50) hide show
  1. package/README.md +58 -26
  2. package/dist/base-plugin.d.ts +9 -5
  3. package/dist/base-plugin.js +11 -3
  4. package/dist/decoder.d.ts +2 -4
  5. package/dist/decoder.js +20 -31
  6. package/dist/event-emitter.d.ts +1 -1
  7. package/dist/event-emitter.js +4 -7
  8. package/dist/fetcher.js +2 -13
  9. package/dist/legacy-adapter.d.ts +7 -0
  10. package/dist/legacy-adapter.js +15 -0
  11. package/dist/player.d.ts +39 -9
  12. package/dist/player.js +90 -15
  13. package/dist/plugin/wavesurfer.envelope.min.js +1 -0
  14. package/dist/plugin/wavesurfer.minimap.min.js +1 -0
  15. package/dist/plugin/wavesurfer.multitrack.min.js +1 -0
  16. package/dist/plugin/wavesurfer.regions.min.js +1 -0
  17. package/dist/plugin/wavesurfer.timeline.min.js +1 -0
  18. package/dist/plugins/envelope.d.ts +60 -0
  19. package/dist/plugins/envelope.js +302 -0
  20. package/dist/plugins/envelope.min.js +1 -0
  21. package/dist/plugins/minimap.d.ts +27 -0
  22. package/dist/plugins/minimap.js +83 -0
  23. package/dist/plugins/minimap.min.js +1 -0
  24. package/dist/plugins/multitrack.d.ts +113 -0
  25. package/dist/plugins/multitrack.js +504 -0
  26. package/dist/plugins/multitrack.min.js +1 -0
  27. package/dist/plugins/record.d.ts +23 -0
  28. package/dist/plugins/record.js +119 -0
  29. package/dist/plugins/record.min.js +1 -0
  30. package/dist/plugins/regions.d.ts +68 -32
  31. package/dist/plugins/regions.js +291 -158
  32. package/dist/plugins/regions.min.js +1 -0
  33. package/dist/plugins/spectrogram.d.ts +24 -0
  34. package/dist/plugins/spectrogram.js +165 -0
  35. package/dist/plugins/timeline.d.ts +38 -0
  36. package/dist/plugins/timeline.js +134 -0
  37. package/dist/plugins/timeline.min.js +1 -0
  38. package/dist/renderer.d.ts +27 -12
  39. package/dist/renderer.js +223 -137
  40. package/dist/timer.d.ts +2 -1
  41. package/dist/timer.js +5 -3
  42. package/dist/wavesurfer.d.ts +132 -0
  43. package/dist/wavesurfer.js +220 -0
  44. package/dist/wavesurfer.min.js +1 -1
  45. package/package.json +51 -20
  46. package/dist/index.d.ts +0 -92
  47. package/dist/index.js +0 -166
  48. package/dist/player-webaudio.d.ts +0 -8
  49. package/dist/player-webaudio.js +0 -30
  50. package/dist/wavesurfer.Regions.min.js +0 -1
@@ -1,183 +1,316 @@
1
1
  import BasePlugin from '../base-plugin.js';
2
- const MIN_WIDTH = 10;
3
- class RegionsPlugin extends BasePlugin {
4
- /** Create an instance of RegionsPlugin */
5
- constructor(params) {
6
- super(params);
7
- this.dragStart = NaN;
8
- this.regions = [];
9
- this.createdRegion = null;
10
- this.modifiedRegion = null;
11
- this.isResizingLeft = false;
12
- this.isMoving = false;
13
- this.handleMouseDown = (e) => {
14
- this.dragStart = e.clientX - this.container.getBoundingClientRect().left;
2
+ import EventEmitter from '../event-emitter.js';
3
+ function makeDraggable(element, onStart, onMove, onEnd) {
4
+ if (!element)
5
+ return;
6
+ let preventClickPropagation = false;
7
+ element.addEventListener('click', (event) => {
8
+ preventClickPropagation && event.stopPropagation();
9
+ });
10
+ element.addEventListener('mousedown', (e) => {
11
+ e.stopPropagation();
12
+ let x = e.clientX;
13
+ onStart(x);
14
+ const onMouseMove = (e) => {
15
+ const newX = e.clientX;
16
+ const dx = newX - x;
17
+ x = newX;
18
+ preventClickPropagation = true;
19
+ onMove(dx);
15
20
  };
16
- this.handleMouseMove = (e) => {
17
- const dragEnd = e.clientX - this.container.getBoundingClientRect().left;
18
- if (this.modifiedRegion && this.isMoving) {
19
- this.moveRegion(this.modifiedRegion, dragEnd - this.dragStart);
20
- this.dragStart = dragEnd;
21
- return;
21
+ const onMouseUp = () => {
22
+ onEnd();
23
+ setTimeout(() => (preventClickPropagation = false), 10);
24
+ document.removeEventListener('mousemove', onMouseMove);
25
+ document.removeEventListener('mouseup', onMouseUp);
26
+ };
27
+ document.addEventListener('mousemove', onMouseMove);
28
+ document.addEventListener('mouseup', onMouseUp);
29
+ });
30
+ }
31
+ class Region extends EventEmitter {
32
+ totalDuration;
33
+ element;
34
+ id;
35
+ start;
36
+ end;
37
+ drag;
38
+ resize;
39
+ color;
40
+ content;
41
+ constructor(params, totalDuration) {
42
+ super();
43
+ this.totalDuration = totalDuration;
44
+ this.id = params.id || Math.random().toString(32).slice(2);
45
+ this.start = params.start;
46
+ this.end = params.end ?? params.start;
47
+ this.drag = params.drag ?? true;
48
+ this.resize = params.resize ?? true;
49
+ this.color = params.color ?? 'rgba(0, 0, 0, 0.1)';
50
+ this.element = this.initElement(params.content);
51
+ this.renderPosition();
52
+ this.initMouseEvents();
53
+ }
54
+ initElement(content) {
55
+ const element = document.createElement('div');
56
+ const isMarker = this.start === this.end;
57
+ element.id = this.id;
58
+ element.setAttribute('style', `
59
+ position: absolute;
60
+ height: 100%;
61
+ background-color: ${isMarker ? 'none' : this.color};
62
+ border-left: ${isMarker ? '2px solid ' + this.color : 'none'};
63
+ border-radius: 2px;
64
+ box-sizing: border-box;
65
+ transition: background-color 0.2s ease;
66
+ cursor: ${this.drag ? 'grab' : 'default'};
67
+ pointer-events: all;
68
+ padding: 0.2em ${isMarker ? 0.2 : 0.4}em;
69
+ pointer-events: all;
70
+ `);
71
+ // Init content
72
+ if (content) {
73
+ if (typeof content === 'string') {
74
+ this.content = document.createElement('div');
75
+ this.content.textContent = content;
22
76
  }
23
- if (this.modifiedRegion) {
24
- this.updateRegion(this.modifiedRegion, this.isResizingLeft ? dragEnd : undefined, this.isResizingLeft ? undefined : dragEnd);
25
- return;
77
+ else {
78
+ this.content = content;
26
79
  }
27
- if (!isNaN(this.dragStart)) {
28
- const dragEnd = e.clientX - this.container.getBoundingClientRect().left;
29
- if (dragEnd - this.dragStart >= MIN_WIDTH) {
30
- if (!this.createdRegion) {
31
- this.renderer.getContainer().style.pointerEvents = 'none';
32
- this.createdRegion = this.createRegion(this.dragStart, dragEnd);
33
- }
34
- else {
35
- this.updateRegion(this.createdRegion, this.dragStart, dragEnd);
36
- }
37
- }
80
+ element.appendChild(this.content);
81
+ }
82
+ // Add resize handles
83
+ if (!isMarker) {
84
+ const leftHandle = document.createElement('div');
85
+ leftHandle.setAttribute('data-resize', 'left');
86
+ leftHandle.setAttribute('style', `
87
+ position: absolute;
88
+ z-index: 2;
89
+ width: 6px;
90
+ height: 100%;
91
+ top: 0;
92
+ left: 0;
93
+ border-left: 2px solid rgba(0, 0, 0, 0.5);
94
+ border-radius: 2px 0 0 2px;
95
+ cursor: ${this.resize ? 'ew-resize' : 'default'};
96
+ word-break: keep-all;
97
+ `);
98
+ const rightHandle = leftHandle.cloneNode();
99
+ rightHandle.setAttribute('data-resize', 'right');
100
+ rightHandle.style.left = '';
101
+ rightHandle.style.right = '0';
102
+ rightHandle.style.borderRight = rightHandle.style.borderLeft;
103
+ rightHandle.style.borderLeft = '';
104
+ rightHandle.style.borderRadius = '0 2px 2px 0';
105
+ element.appendChild(leftHandle);
106
+ element.appendChild(rightHandle);
107
+ }
108
+ return element;
109
+ }
110
+ renderPosition() {
111
+ const start = this.start / this.totalDuration;
112
+ const end = this.end / this.totalDuration;
113
+ this.element.style.left = `${start * 100}%`;
114
+ this.element.style.width = `${(end - start) * 100}%`;
115
+ }
116
+ initMouseEvents() {
117
+ const { element } = this;
118
+ element.addEventListener('mouseenter', (event) => this.emit('over', { event }));
119
+ element.addEventListener('mouseleave', (event) => this.emit('leave', { event }));
120
+ element.addEventListener('click', (event) => this.emit('click', { event }));
121
+ element.addEventListener('dblclick', (event) => this.emit('dblclick', { event }));
122
+ // Drag
123
+ makeDraggable(element, () => this.onStartMoving(), (dx) => this.onMove(dx), () => this.onEndMoving());
124
+ // Resize
125
+ makeDraggable(element.querySelector('[data-resize="left"]'), () => null, (dx) => this.onResize(dx, 'start'), () => this.onEndResizing());
126
+ makeDraggable(element.querySelector('[data-resize="right"]'), () => null, (dx) => this.onResize(dx, 'end'), () => this.onEndResizing());
127
+ }
128
+ onStartMoving() {
129
+ if (!this.drag)
130
+ return;
131
+ this.element.style.cursor = 'grabbing';
132
+ }
133
+ onEndMoving() {
134
+ if (!this.drag)
135
+ return;
136
+ this.element.style.cursor = 'grab';
137
+ this.emit('update-end');
138
+ }
139
+ onUpdate(dx, sides) {
140
+ if (!this.element.parentElement)
141
+ return;
142
+ const deltaSeconds = (dx / this.element.parentElement.clientWidth) * this.totalDuration;
143
+ sides.forEach((side) => {
144
+ this[side] += deltaSeconds;
145
+ if (side === 'start') {
146
+ this.start = Math.max(0, Math.min(this.start, this.end));
38
147
  }
39
- };
40
- this.handleMouseUp = () => {
41
- if (this.createdRegion) {
42
- this.addRegion(this.createdRegion);
43
- this.createdRegion = null;
148
+ else {
149
+ this.end = Math.max(this.start, Math.min(this.end, this.totalDuration));
44
150
  }
45
- this.modifiedRegion = null;
46
- this.isMoving = false;
47
- this.dragStart = NaN;
48
- this.renderer.getContainer().style.pointerEvents = '';
49
- };
50
- this.container = this.initContainer();
51
- const unsubscribeReady = this.wavesurfer.on('ready', () => {
52
- const wrapper = this.renderer.getContainer();
53
- wrapper.appendChild(this.container);
54
- unsubscribeReady();
55
151
  });
56
- this.subscriptions.push(unsubscribeReady);
57
- const wsContainer = this.renderer.getContainer();
58
- wsContainer.addEventListener('mousedown', this.handleMouseDown);
59
- document.addEventListener('mousemove', this.handleMouseMove);
60
- document.addEventListener('mouseup', this.handleMouseUp);
152
+ this.renderPosition();
153
+ this.emit('update');
61
154
  }
62
- /** Unmounts the regions */
63
- destroy() {
64
- var _a;
65
- this.renderer.getContainer().removeEventListener('mousedown', this.handleMouseDown);
66
- document.removeEventListener('mousemove', this.handleMouseMove);
67
- document.removeEventListener('mouseup', this.handleMouseUp, true);
68
- (_a = this.container) === null || _a === void 0 ? void 0 : _a.remove();
69
- super.destroy();
155
+ onMove(dx) {
156
+ if (!this.drag)
157
+ return;
158
+ this.onUpdate(dx, ['start', 'end']);
159
+ }
160
+ onResize(dx, side) {
161
+ if (!this.resize)
162
+ return;
163
+ this.onUpdate(dx, [side]);
164
+ }
165
+ onEndResizing() {
166
+ if (!this.resize)
167
+ return;
168
+ this.emit('update-end');
169
+ }
170
+ // Play the region from start to end
171
+ play() {
172
+ this.emit('play');
173
+ }
174
+ setTotalDuration(totalDuration) {
175
+ this.totalDuration = totalDuration;
176
+ this.renderPosition();
177
+ }
178
+ // Remove the region
179
+ remove() {
180
+ this.emit('remove');
181
+ this.element.remove();
182
+ }
183
+ }
184
+ class RegionsPlugin extends BasePlugin {
185
+ regions = [];
186
+ regionsContainer;
187
+ /** Create an instance of RegionsPlugin */
188
+ constructor(options) {
189
+ super(options);
190
+ this.regionsContainer = this.initRegionsContainer();
70
191
  }
71
- initContainer() {
192
+ static create(options) {
193
+ return new RegionsPlugin(options);
194
+ }
195
+ init(params) {
196
+ super.init(params);
197
+ if (!this.wavesurfer || !this.wrapper) {
198
+ throw Error('WaveSurfer is not initialized');
199
+ }
200
+ this.wrapper.appendChild(this.regionsContainer);
201
+ }
202
+ initRegionsContainer() {
72
203
  const div = document.createElement('div');
73
- div.style.position = 'absolute';
74
- div.style.top = '0';
75
- div.style.left = '0';
76
- div.style.width = '100%';
77
- div.style.height = '100%';
78
- div.style.zIndex = '3';
79
- div.style.pointerEvents = 'none';
204
+ div.setAttribute('style', `
205
+ position: absolute;
206
+ top: 0;
207
+ left: 0;
208
+ width: 100%;
209
+ height: 100%;
210
+ z-index: 3;
211
+ pointer-events: none;
212
+ `);
80
213
  return div;
81
214
  }
82
- createRegionElement(start, end, title = '') {
83
- const el = document.createElement('div');
84
- el.style.position = 'absolute';
85
- el.style.left = `${start}px`;
86
- el.style.width = `${end - start}px`;
87
- el.style.height = '100%';
88
- el.style.backgroundColor = 'rgba(0, 0, 0, 0.1)';
89
- el.style.transition = 'background-color 0.2s ease';
90
- el.style.cursor = 'move';
91
- el.style.pointerEvents = 'all';
92
- el.title = title;
93
- const leftHandle = document.createElement('div');
94
- leftHandle.style.position = 'absolute';
95
- leftHandle.style.left = '0';
96
- leftHandle.style.width = '6px';
97
- leftHandle.style.height = '100%';
98
- leftHandle.style.borderLeft = '2px solid rgba(0, 0, 0, 0.5)';
99
- leftHandle.style.cursor = 'ew-resize';
100
- leftHandle.style.pointerEvents = 'all';
101
- el.appendChild(leftHandle);
102
- const rightHandle = document.createElement('div');
103
- rightHandle.style.position = 'absolute';
104
- rightHandle.style.right = '0';
105
- rightHandle.style.width = '6px';
106
- rightHandle.style.height = '100%';
107
- rightHandle.style.borderRight = '2px solid rgba(0, 0, 0, 0.5)';
108
- rightHandle.style.cursor = 'ew-resize';
109
- rightHandle.style.pointerEvents = 'all';
110
- el.appendChild(rightHandle);
111
- leftHandle.addEventListener('mousedown', (e) => {
112
- e.stopPropagation();
113
- this.modifiedRegion = this.regions.find((r) => r.element === el) || null;
114
- this.isResizingLeft = true;
115
- this.isMoving = false;
116
- });
117
- rightHandle.addEventListener('mousedown', (e) => {
118
- e.stopPropagation();
119
- this.modifiedRegion = this.regions.find((r) => r.element === el) || null;
120
- this.isResizingLeft = false;
121
- this.isMoving = false;
122
- });
123
- el.addEventListener('mousedown', () => {
124
- this.modifiedRegion = this.regions.find((r) => r.element === el) || null;
125
- this.isMoving = true;
126
- });
127
- el.addEventListener('click', () => {
128
- const region = this.regions.find((r) => r.element === el);
129
- if (region) {
130
- this.emit('region-clicked', { region });
131
- }
132
- });
133
- this.container.appendChild(el);
134
- return el;
215
+ getRegions() {
216
+ return this.regions;
135
217
  }
136
- createRegion(start, end, title = '') {
137
- const duration = this.wavesurfer.getDuration();
138
- const width = this.container.clientWidth;
139
- return {
140
- element: this.createRegionElement(start, end, title),
141
- start,
142
- end,
143
- startTime: (start / width) * duration,
144
- endTime: (end / width) * duration,
145
- title,
146
- };
218
+ avoidOverlapping(region) {
219
+ if (!region.content)
220
+ return;
221
+ // Check that the label doesn't overlap with other labels
222
+ // If it does, push it down until it doesn't
223
+ const div = region.content;
224
+ const labelLeft = div.getBoundingClientRect().left;
225
+ const labelWidth = region.element.scrollWidth;
226
+ const overlap = this.regions
227
+ .filter((reg) => {
228
+ if (reg === region || !reg.content)
229
+ return false;
230
+ const left = reg.content.getBoundingClientRect().left;
231
+ const width = reg.element.scrollWidth;
232
+ return labelLeft < left + width && left < labelLeft + labelWidth;
233
+ })
234
+ .map((reg) => reg.content?.getBoundingClientRect().height || 0)
235
+ .reduce((sum, val) => sum + val, 0);
236
+ div.style.marginTop = `${overlap}px`;
147
237
  }
148
- addRegion(region) {
238
+ saveRegion(region) {
239
+ this.regionsContainer.appendChild(region.element);
240
+ this.avoidOverlapping(region);
149
241
  this.regions.push(region);
150
242
  this.emit('region-created', { region });
243
+ this.subscriptions.push(region.on('update-end', () => {
244
+ this.avoidOverlapping(region);
245
+ this.emit('region-updated', { region });
246
+ }), region.on('play', () => {
247
+ this.wavesurfer?.play();
248
+ this.wavesurfer?.setTime(region.start);
249
+ }), region.on('click', () => {
250
+ this.emit('region-clicked', { region });
251
+ }));
151
252
  }
152
- updateRegion(region, start, end) {
153
- if (start != null) {
154
- region.start = start !== null && start !== void 0 ? start : region.start;
155
- region.element.style.left = `${region.start}px`;
156
- region.startTime = (start / this.container.clientWidth) * this.wavesurfer.getDuration();
253
+ addRegion(options) {
254
+ if (!this.wavesurfer) {
255
+ throw Error('WaveSurfer is not initialized');
157
256
  }
158
- if (end != null) {
159
- region.end = end;
160
- region.element.style.width = `${region.end - region.start}px`;
161
- region.endTime = (end / this.container.clientWidth) * this.wavesurfer.getDuration();
257
+ const duration = this.wavesurfer.getDuration();
258
+ const region = new Region(options, duration);
259
+ if (!duration) {
260
+ this.subscriptions.push(this.wavesurfer.once('canplay', ({ duration }) => {
261
+ region.setTotalDuration(duration);
262
+ this.saveRegion(region);
263
+ }));
264
+ }
265
+ else {
266
+ this.saveRegion(region);
162
267
  }
163
- this.emit('region-updated', { region });
268
+ return region;
164
269
  }
165
- moveRegion(region, delta) {
166
- this.updateRegion(region, region.start + delta, region.end + delta);
270
+ // The same as addRegion but with spread params
271
+ add(start, end, content, color) {
272
+ return this.addRegion({ start, end, content, color });
167
273
  }
168
- /** Create a region at a given start and end time, with an optional title */
169
- addRegionAtTime(startTime, endTime, title = '') {
170
- const duration = this.wavesurfer.getDuration();
171
- const width = this.container.clientWidth;
172
- const start = (startTime / duration) * width;
173
- const end = (endTime / duration) * width;
174
- const region = this.createRegion(start, end, title);
175
- this.addRegion(region);
176
- return region;
274
+ enableDragSelection(options) {
275
+ if (!this.wrapper)
276
+ return;
277
+ const minWidth = 5; // min 5 pixels
278
+ let region = null;
279
+ let startX = 0;
280
+ let sumDx = 0;
281
+ makeDraggable(this.wrapper,
282
+ // On mousedown
283
+ (x) => (startX = x),
284
+ // On mousemove
285
+ (dx) => {
286
+ sumDx += dx;
287
+ if (!this.wavesurfer || !this.wrapper)
288
+ return;
289
+ if (!region && sumDx > minWidth) {
290
+ const duration = this.wavesurfer.getDuration();
291
+ const box = this.wrapper.getBoundingClientRect();
292
+ const start = ((startX + sumDx - box.left) / box.width) * duration;
293
+ region = new Region({
294
+ ...options,
295
+ start,
296
+ end: start,
297
+ }, duration);
298
+ this.regionsContainer.appendChild(region.element);
299
+ }
300
+ if (region) {
301
+ const privateRegion = region;
302
+ privateRegion.onUpdate(dx, ['end']);
303
+ }
304
+ },
305
+ // On mouseup
306
+ () => region && this.saveRegion(region));
177
307
  }
178
- /** Set the background color of a region */
179
- setRegionColor(region, color) {
180
- region.element.style.backgroundColor = color;
308
+ clearRegions() {
309
+ this.regions.forEach((region) => region.remove());
310
+ }
311
+ destroy() {
312
+ this.clearRegions();
313
+ super.destroy();
181
314
  }
182
315
  }
183
316
  export default RegionsPlugin;
@@ -0,0 +1 @@
1
+ !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Regions=t():e.Regions=t()}(WaveSurfer,(()=>(()=>{"use strict";var e={284:(e,t,n)=>{n.d(t,{Z:()=>r});var i=n(139);class s extends i.Z{wavesurfer;container;wrapper;subscriptions=[];options;constructor(e){super(),this.options=e}init(e){this.wavesurfer=e.wavesurfer,this.container=e.container,this.wrapper=e.wrapper}destroy(){this.subscriptions.forEach((e=>e()))}}const r=s},139:(e,t,n)=>{n.d(t,{Z:()=>i});const i=class{eventTarget;constructor(){this.eventTarget=new EventTarget}emit(e,t){const n=new CustomEvent(String(e),{detail:t});this.eventTarget.dispatchEvent(n)}on(e,t,n){const i=e=>{e instanceof CustomEvent&&t(e.detail)},s=String(e);return this.eventTarget.addEventListener(s,i,{once:n}),()=>this.eventTarget.removeEventListener(s,i)}once(e,t){return this.on(e,t,!0)}}}},t={};function n(i){var s=t[i];if(void 0!==s)return s.exports;var r=t[i]={exports:{}};return e[i](r,r.exports,n),r.exports}n.d=(e,t)=>{for(var i in t)n.o(t,i)&&!n.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:t[i]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var i={};return(()=>{n.d(i,{default:()=>a});var e=n(284),t=n(139);function s(e,t,n,i){if(!e)return;let s=!1;e.addEventListener("click",(e=>{s&&e.stopPropagation()})),e.addEventListener("mousedown",(e=>{e.stopPropagation();let r=e.clientX;t(r);const o=e=>{const t=e.clientX,i=t-r;r=t,s=!0,n(i)},a=()=>{i(),setTimeout((()=>s=!1),10),document.removeEventListener("mousemove",o),document.removeEventListener("mouseup",a)};document.addEventListener("mousemove",o),document.addEventListener("mouseup",a)}))}class r extends t.Z{totalDuration;element;id;start;end;drag;resize;color;content;constructor(e,t){super(),this.totalDuration=t,this.id=e.id||Math.random().toString(32).slice(2),this.start=e.start,this.end=e.end??e.start,this.drag=e.drag??!0,this.resize=e.resize??!0,this.color=e.color??"rgba(0, 0, 0, 0.1)",this.element=this.initElement(e.content),this.renderPosition(),this.initMouseEvents()}initElement(e){const t=document.createElement("div"),n=this.start===this.end;if(t.id=this.id,t.setAttribute("style",`\n position: absolute;\n height: 100%;\n background-color: ${n?"none":this.color};\n border-left: ${n?"2px solid "+this.color:"none"};\n border-radius: 2px;\n box-sizing: border-box;\n transition: background-color 0.2s ease;\n cursor: ${this.drag?"grab":"default"};\n pointer-events: all;\n padding: 0.2em ${n?.2:.4}em;\n pointer-events: all;\n `),e&&("string"==typeof e?(this.content=document.createElement("div"),this.content.textContent=e):this.content=e,t.appendChild(this.content)),!n){const e=document.createElement("div");e.setAttribute("data-resize","left"),e.setAttribute("style",`\n position: absolute;\n z-index: 2;\n width: 6px;\n height: 100%;\n top: 0;\n left: 0;\n border-left: 2px solid rgba(0, 0, 0, 0.5);\n border-radius: 2px 0 0 2px;\n cursor: ${this.resize?"ew-resize":"default"};\n word-break: keep-all;\n `);const n=e.cloneNode();n.setAttribute("data-resize","right"),n.style.left="",n.style.right="0",n.style.borderRight=n.style.borderLeft,n.style.borderLeft="",n.style.borderRadius="0 2px 2px 0",t.appendChild(e),t.appendChild(n)}return t}renderPosition(){const e=this.start/this.totalDuration,t=this.end/this.totalDuration;this.element.style.left=100*e+"%",this.element.style.width=100*(t-e)+"%"}initMouseEvents(){const{element:e}=this;e.addEventListener("mouseenter",(e=>this.emit("over",{event:e}))),e.addEventListener("mouseleave",(e=>this.emit("leave",{event:e}))),e.addEventListener("click",(e=>this.emit("click",{event:e}))),e.addEventListener("dblclick",(e=>this.emit("dblclick",{event:e}))),s(e,(()=>this.onStartMoving()),(e=>this.onMove(e)),(()=>this.onEndMoving())),s(e.querySelector('[data-resize="left"]'),(()=>null),(e=>this.onResize(e,"start")),(()=>this.onEndResizing())),s(e.querySelector('[data-resize="right"]'),(()=>null),(e=>this.onResize(e,"end")),(()=>this.onEndResizing()))}onStartMoving(){this.drag&&(this.element.style.cursor="grabbing")}onEndMoving(){this.drag&&(this.element.style.cursor="grab",this.emit("update-end"))}onUpdate(e,t){if(!this.element.parentElement)return;const n=e/this.element.parentElement.clientWidth*this.totalDuration;t.forEach((e=>{this[e]+=n,"start"===e?this.start=Math.max(0,Math.min(this.start,this.end)):this.end=Math.max(this.start,Math.min(this.end,this.totalDuration))})),this.renderPosition(),this.emit("update")}onMove(e){this.drag&&this.onUpdate(e,["start","end"])}onResize(e,t){this.resize&&this.onUpdate(e,[t])}onEndResizing(){this.resize&&this.emit("update-end")}play(){this.emit("play")}setTotalDuration(e){this.totalDuration=e,this.renderPosition()}remove(){this.emit("remove"),this.element.remove()}}class o extends e.Z{regions=[];regionsContainer;constructor(e){super(e),this.regionsContainer=this.initRegionsContainer()}static create(e){return new o(e)}init(e){if(super.init(e),!this.wavesurfer||!this.wrapper)throw Error("WaveSurfer is not initialized");this.wrapper.appendChild(this.regionsContainer)}initRegionsContainer(){const e=document.createElement("div");return e.setAttribute("style","\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n z-index: 3;\n pointer-events: none;\n "),e}getRegions(){return this.regions}avoidOverlapping(e){if(!e.content)return;const t=e.content,n=t.getBoundingClientRect().left,i=e.element.scrollWidth,s=this.regions.filter((t=>{if(t===e||!t.content)return!1;const s=t.content.getBoundingClientRect().left,r=t.element.scrollWidth;return n<s+r&&s<n+i})).map((e=>e.content?.getBoundingClientRect().height||0)).reduce(((e,t)=>e+t),0);t.style.marginTop=`${s}px`}saveRegion(e){this.regionsContainer.appendChild(e.element),this.avoidOverlapping(e),this.regions.push(e),this.emit("region-created",{region:e}),this.subscriptions.push(e.on("update-end",(()=>{this.avoidOverlapping(e),this.emit("region-updated",{region:e})})),e.on("play",(()=>{this.wavesurfer?.play(),this.wavesurfer?.setTime(e.start)})),e.on("click",(()=>{this.emit("region-clicked",{region:e})})))}addRegion(e){if(!this.wavesurfer)throw Error("WaveSurfer is not initialized");const t=this.wavesurfer.getDuration(),n=new r(e,t);return t?this.saveRegion(n):this.subscriptions.push(this.wavesurfer.once("canplay",(({duration:e})=>{n.setTotalDuration(e),this.saveRegion(n)}))),n}add(e,t,n,i){return this.addRegion({start:e,end:t,content:n,color:i})}enableDragSelection(e){if(!this.wrapper)return;let t=null,n=0,i=0;s(this.wrapper,(e=>n=e),(s=>{if(i+=s,this.wavesurfer&&this.wrapper){if(!t&&i>5){const s=this.wavesurfer.getDuration(),o=this.wrapper.getBoundingClientRect(),a=(n+i-o.left)/o.width*s;t=new r({...e,start:a,end:a},s),this.regionsContainer.appendChild(t.element)}t&&t.onUpdate(s,["end"])}}),(()=>t&&this.saveRegion(t)))}clearRegions(){this.regions.forEach((e=>e.remove()))}destroy(){this.clearRegions(),super.destroy()}}const a=o})(),i.default})()));
@@ -0,0 +1,24 @@
1
+ import BasePlugin from '../base-plugin.js';
2
+ export type SpectrogramPluginOptions = {
3
+ waveColor?: string;
4
+ lineWidth?: number;
5
+ };
6
+ export type SpectrogramPluginEvents = {
7
+ startRecording: void;
8
+ stopRecording: void;
9
+ };
10
+ declare class SpectrogramPlugin extends BasePlugin<SpectrogramPluginEvents, SpectrogramPluginOptions> {
11
+ private mediaSpectrogramer;
12
+ private recordedUrl;
13
+ static create(options?: SpectrogramPluginOptions): SpectrogramPlugin;
14
+ private loadBlob;
15
+ private processFrequencyData;
16
+ render(stream: MediaStream): () => void;
17
+ private cleanUp;
18
+ startSpectrograming(): Promise<void>;
19
+ isSpectrograming(): boolean;
20
+ stopSpectrograming(): void;
21
+ getSpectrogramedUrl(): string;
22
+ destroy(): void;
23
+ }
24
+ export default SpectrogramPlugin;