wavesurfer.js 7.11.1 → 7.12.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.
- package/README.md +1 -1
- package/dist/__tests__/memory-leaks.test.d.ts +7 -0
- package/dist/__tests__/memory-leaks.test.js +281 -0
- package/dist/__tests__/player.test.js +107 -0
- package/dist/__tests__/renderer-utils.test.js +55 -2
- package/dist/draggable.d.ts +4 -0
- package/dist/draggable.js +4 -0
- package/dist/player.d.ts +21 -0
- package/dist/player.js +86 -0
- package/dist/plugins/envelope.cjs +1 -1
- package/dist/plugins/envelope.esm.js +1 -1
- package/dist/plugins/envelope.js +1 -1
- package/dist/plugins/envelope.min.js +1 -1
- package/dist/plugins/hover.cjs +1 -1
- package/dist/plugins/hover.d.ts +0 -3
- package/dist/plugins/hover.esm.js +1 -1
- package/dist/plugins/hover.js +1 -1
- package/dist/plugins/hover.min.js +1 -1
- package/dist/plugins/minimap.cjs +1 -1
- package/dist/plugins/minimap.esm.js +1 -1
- package/dist/plugins/minimap.js +1 -1
- package/dist/plugins/minimap.min.js +1 -1
- package/dist/plugins/record.cjs +1 -1
- package/dist/plugins/record.esm.js +1 -1
- package/dist/plugins/record.js +1 -1
- package/dist/plugins/record.min.js +1 -1
- package/dist/plugins/regions.cjs +1 -1
- package/dist/plugins/regions.esm.js +1 -1
- package/dist/plugins/regions.js +1 -1
- package/dist/plugins/regions.min.js +1 -1
- package/dist/plugins/timeline.cjs +1 -1
- package/dist/plugins/timeline.d.ts +1 -1
- package/dist/plugins/timeline.esm.js +1 -1
- package/dist/plugins/timeline.js +1 -1
- package/dist/plugins/timeline.min.js +1 -1
- package/dist/plugins/zoom.cjs +1 -1
- package/dist/plugins/zoom.esm.js +1 -1
- package/dist/plugins/zoom.js +1 -1
- package/dist/plugins/zoom.min.js +1 -1
- package/dist/reactive/__tests__/drag-stream.test.d.ts +1 -0
- package/dist/reactive/__tests__/drag-stream.test.js +199 -0
- package/dist/reactive/__tests__/event-stream-emitter.test.d.ts +1 -0
- package/dist/reactive/__tests__/event-stream-emitter.test.js +230 -0
- package/dist/reactive/__tests__/event-streams.test.d.ts +1 -0
- package/dist/reactive/__tests__/event-streams.test.js +278 -0
- package/dist/reactive/__tests__/media-event-bridge.test.d.ts +1 -0
- package/dist/reactive/__tests__/media-event-bridge.test.js +202 -0
- package/dist/reactive/__tests__/render-scheduler.test.d.ts +1 -0
- package/dist/reactive/__tests__/render-scheduler.test.js +216 -0
- package/dist/reactive/__tests__/scroll-stream.test.d.ts +1 -0
- package/dist/reactive/__tests__/scroll-stream.test.js +191 -0
- package/dist/reactive/__tests__/state-event-emitter.test.d.ts +1 -0
- package/dist/reactive/__tests__/state-event-emitter.test.js +234 -0
- package/dist/reactive/__tests__/store.test.d.ts +1 -0
- package/dist/reactive/__tests__/store.test.js +271 -0
- package/dist/reactive/drag-stream.d.ts +48 -0
- package/dist/reactive/drag-stream.js +146 -0
- package/dist/reactive/event-stream-emitter.d.ts +104 -0
- package/dist/reactive/event-stream-emitter.js +151 -0
- package/dist/reactive/event-streams.d.ts +65 -0
- package/dist/reactive/event-streams.js +146 -0
- package/dist/reactive/media-event-bridge.d.ts +51 -0
- package/dist/reactive/media-event-bridge.js +152 -0
- package/dist/reactive/render-scheduler.d.ts +43 -0
- package/dist/reactive/render-scheduler.js +75 -0
- package/dist/reactive/scroll-stream.d.ts +93 -0
- package/dist/reactive/scroll-stream.js +131 -0
- package/dist/reactive/state-event-emitter.d.ts +105 -0
- package/dist/reactive/state-event-emitter.js +213 -0
- package/dist/reactive/store.d.ts +66 -0
- package/dist/reactive/store.js +115 -0
- package/dist/renderer-utils.d.ts +13 -4
- package/dist/renderer-utils.js +35 -15
- package/dist/renderer.d.ts +2 -1
- package/dist/renderer.js +51 -48
- package/dist/state/__tests__/wavesurfer-state.test.d.ts +1 -0
- package/dist/state/__tests__/wavesurfer-state.test.js +268 -0
- package/dist/state/wavesurfer-state.d.ts +90 -0
- package/dist/state/wavesurfer-state.js +124 -0
- package/dist/types.d.ts +165 -1
- package/dist/wavesurfer.cjs +1 -1
- package/dist/wavesurfer.d.ts +16 -0
- package/dist/wavesurfer.esm.js +1 -1
- package/dist/wavesurfer.js +32 -0
- package/dist/wavesurfer.min.js +1 -1
- package/package.json +2 -3
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reactive primitives for managing state in WaveSurfer
|
|
3
|
+
*
|
|
4
|
+
* This module provides signal-based reactivity similar to SolidJS signals.
|
|
5
|
+
* Signals are reactive values that notify subscribers when they change.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Create a reactive signal that notifies subscribers when its value changes
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* const count = signal(0)
|
|
13
|
+
* count.subscribe(val => console.log('Count:', val))
|
|
14
|
+
* count.set(5) // Logs: Count: 5
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export function signal(initialValue) {
|
|
18
|
+
let _value = initialValue;
|
|
19
|
+
const subscribers = new Set();
|
|
20
|
+
return {
|
|
21
|
+
get value() {
|
|
22
|
+
return _value;
|
|
23
|
+
},
|
|
24
|
+
set(newValue) {
|
|
25
|
+
// Only update and notify if value actually changed
|
|
26
|
+
if (!Object.is(_value, newValue)) {
|
|
27
|
+
_value = newValue;
|
|
28
|
+
subscribers.forEach((fn) => fn(_value));
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
update(fn) {
|
|
32
|
+
this.set(fn(_value));
|
|
33
|
+
},
|
|
34
|
+
subscribe(callback) {
|
|
35
|
+
subscribers.add(callback);
|
|
36
|
+
return () => subscribers.delete(callback);
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Create a computed value that automatically updates when its dependencies change
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* const count = signal(0)
|
|
46
|
+
* const doubled = computed(() => count.value * 2, [count])
|
|
47
|
+
* console.log(doubled.value) // 0
|
|
48
|
+
* count.set(5)
|
|
49
|
+
* console.log(doubled.value) // 10
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export function computed(fn, dependencies) {
|
|
53
|
+
const result = signal(fn());
|
|
54
|
+
// Subscribe to all dependencies immediately
|
|
55
|
+
// This ensures the computed value stays in sync even if no one is subscribed to it
|
|
56
|
+
dependencies.forEach((dep) => dep.subscribe(() => {
|
|
57
|
+
const newValue = fn();
|
|
58
|
+
// Update the result signal, which will notify our subscribers if value changed
|
|
59
|
+
if (!Object.is(result.value, newValue)) {
|
|
60
|
+
;
|
|
61
|
+
result.set(newValue);
|
|
62
|
+
}
|
|
63
|
+
}));
|
|
64
|
+
// Return a read-only signal that proxies the result
|
|
65
|
+
return {
|
|
66
|
+
get value() {
|
|
67
|
+
return result.value;
|
|
68
|
+
},
|
|
69
|
+
subscribe(callback) {
|
|
70
|
+
// Just subscribe to result changes
|
|
71
|
+
return result.subscribe(callback);
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Run a side effect automatically when dependencies change
|
|
77
|
+
*
|
|
78
|
+
* @param fn - Effect function. Can return a cleanup function.
|
|
79
|
+
* @param dependencies - Signals that trigger the effect when they change
|
|
80
|
+
* @returns Unsubscribe function that stops the effect and runs cleanup
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```typescript
|
|
84
|
+
* const count = signal(0)
|
|
85
|
+
* effect(() => {
|
|
86
|
+
* console.log('Count is:', count.value)
|
|
87
|
+
* return () => console.log('Cleanup')
|
|
88
|
+
* }, [count])
|
|
89
|
+
* count.set(5) // Logs: Cleanup, Count is: 5
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
export function effect(fn, dependencies) {
|
|
93
|
+
let cleanup;
|
|
94
|
+
const run = () => {
|
|
95
|
+
// Run cleanup from previous execution
|
|
96
|
+
if (cleanup) {
|
|
97
|
+
cleanup();
|
|
98
|
+
cleanup = undefined;
|
|
99
|
+
}
|
|
100
|
+
// Run effect and capture new cleanup
|
|
101
|
+
cleanup = fn();
|
|
102
|
+
};
|
|
103
|
+
// Subscribe to all dependencies
|
|
104
|
+
const unsubscribes = dependencies.map((dep) => dep.subscribe(run));
|
|
105
|
+
// Run effect immediately
|
|
106
|
+
run();
|
|
107
|
+
// Return function that unsubscribes and runs cleanup
|
|
108
|
+
return () => {
|
|
109
|
+
if (cleanup) {
|
|
110
|
+
cleanup();
|
|
111
|
+
cleanup = undefined;
|
|
112
|
+
}
|
|
113
|
+
unsubscribes.forEach((unsub) => unsub());
|
|
114
|
+
};
|
|
115
|
+
}
|
package/dist/renderer-utils.d.ts
CHANGED
|
@@ -25,14 +25,17 @@ export declare function calculateBarRenderConfig({ width, height, length, option
|
|
|
25
25
|
barWidth: number;
|
|
26
26
|
barGap: number;
|
|
27
27
|
barRadius: number;
|
|
28
|
+
barMinHeight: number;
|
|
28
29
|
barIndexScale: number;
|
|
29
30
|
barSpacing: number;
|
|
30
31
|
};
|
|
31
|
-
export declare function calculateBarHeights({ maxTop, maxBottom, halfHeight, vScale, }: {
|
|
32
|
+
export declare function calculateBarHeights({ maxTop, maxBottom, halfHeight, vScale, barMinHeight, barAlign, }: {
|
|
32
33
|
maxTop: number;
|
|
33
34
|
maxBottom: number;
|
|
34
35
|
halfHeight: number;
|
|
35
36
|
vScale: number;
|
|
37
|
+
barMinHeight?: number;
|
|
38
|
+
barAlign?: WaveSurferOptions['barAlign'];
|
|
36
39
|
}): {
|
|
37
40
|
topHeight: number;
|
|
38
41
|
totalHeight: number;
|
|
@@ -44,7 +47,7 @@ export declare function resolveBarYPosition({ barAlign, halfHeight, topHeight, t
|
|
|
44
47
|
totalHeight: number;
|
|
45
48
|
canvasHeight: number;
|
|
46
49
|
}): number;
|
|
47
|
-
export declare function calculateBarSegments({ channelData, barIndexScale, barSpacing, barWidth, halfHeight, vScale, canvasHeight, barAlign, }: {
|
|
50
|
+
export declare function calculateBarSegments({ channelData, barIndexScale, barSpacing, barWidth, halfHeight, vScale, canvasHeight, barAlign, barMinHeight, }: {
|
|
48
51
|
channelData: ChannelData;
|
|
49
52
|
barIndexScale: number;
|
|
50
53
|
barSpacing: number;
|
|
@@ -53,6 +56,7 @@ export declare function calculateBarSegments({ channelData, barIndexScale, barSp
|
|
|
53
56
|
vScale: number;
|
|
54
57
|
canvasHeight: number;
|
|
55
58
|
barAlign: WaveSurferOptions['barAlign'];
|
|
59
|
+
barMinHeight: number;
|
|
56
60
|
}): BarSegment[];
|
|
57
61
|
export declare function getRelativePointerPosition(rect: DOMRect, clientX: number, clientY: number): [number, number];
|
|
58
62
|
export declare function resolveChannelHeight({ optionsHeight, optionsSplitChannels, parentHeight, numberOfChannels, defaultHeight, }: {
|
|
@@ -64,7 +68,7 @@ export declare function resolveChannelHeight({ optionsHeight, optionsSplitChanne
|
|
|
64
68
|
}): number;
|
|
65
69
|
export declare function getPixelRatio(devicePixelRatio?: number): number;
|
|
66
70
|
export declare function shouldRenderBars(options: WaveSurferOptions): boolean;
|
|
67
|
-
export declare function resolveColorValue(color: WaveSurferOptions['waveColor'], devicePixelRatio: number): string | CanvasGradient;
|
|
71
|
+
export declare function resolveColorValue(color: WaveSurferOptions['waveColor'], devicePixelRatio: number, canvasHeight?: number): string | CanvasGradient;
|
|
68
72
|
export declare function calculateWaveformLayout({ duration, minPxPerSec, parentWidth, fillParent, pixelRatio, }: {
|
|
69
73
|
duration: number;
|
|
70
74
|
minPxPerSec?: number;
|
|
@@ -95,10 +99,11 @@ export declare function getLazyRenderRange({ scrollLeft, totalWidth, numCanvases
|
|
|
95
99
|
totalWidth: number;
|
|
96
100
|
numCanvases: number;
|
|
97
101
|
}): number[];
|
|
98
|
-
export declare function calculateVerticalScale({ channelData, barHeight, normalize, }: {
|
|
102
|
+
export declare function calculateVerticalScale({ channelData, barHeight, normalize, maxPeak, }: {
|
|
99
103
|
channelData: ChannelData;
|
|
100
104
|
barHeight?: WaveSurferOptions['barHeight'];
|
|
101
105
|
normalize?: WaveSurferOptions['normalize'];
|
|
106
|
+
maxPeak?: WaveSurferOptions['maxPeak'];
|
|
102
107
|
}): number;
|
|
103
108
|
export declare function calculateLinePaths({ channelData, width, height, vScale, }: {
|
|
104
109
|
channelData: ChannelData;
|
|
@@ -106,6 +111,10 @@ export declare function calculateLinePaths({ channelData, width, height, vScale,
|
|
|
106
111
|
height: number;
|
|
107
112
|
vScale: number;
|
|
108
113
|
}): LinePath[];
|
|
114
|
+
/**
|
|
115
|
+
* @deprecated Use calculateScrollPercentages from './reactive/scroll-stream.js' instead.
|
|
116
|
+
* This function is maintained for backward compatibility but will be removed in a future version.
|
|
117
|
+
*/
|
|
109
118
|
export declare function calculateScrollPercentages({ scrollLeft, clientWidth, scrollWidth, }: {
|
|
110
119
|
scrollLeft: number;
|
|
111
120
|
clientWidth: number;
|
package/dist/renderer-utils.js
CHANGED
|
@@ -13,6 +13,7 @@ export function calculateBarRenderConfig({ width, height, length, options, pixel
|
|
|
13
13
|
const barWidth = options.barWidth ? options.barWidth * pixelRatio : 1;
|
|
14
14
|
const barGap = options.barGap ? options.barGap * pixelRatio : options.barWidth ? barWidth / 2 : 0;
|
|
15
15
|
const barRadius = options.barRadius || 0;
|
|
16
|
+
const barMinHeight = options.barMinHeight ? options.barMinHeight * pixelRatio : 0;
|
|
16
17
|
const spacing = barWidth + barGap || 1;
|
|
17
18
|
const barIndexScale = length > 0 ? width / spacing / length : 0;
|
|
18
19
|
return {
|
|
@@ -20,14 +21,21 @@ export function calculateBarRenderConfig({ width, height, length, options, pixel
|
|
|
20
21
|
barWidth,
|
|
21
22
|
barGap,
|
|
22
23
|
barRadius,
|
|
24
|
+
barMinHeight,
|
|
23
25
|
barIndexScale,
|
|
24
26
|
barSpacing: spacing,
|
|
25
27
|
};
|
|
26
28
|
}
|
|
27
|
-
export function calculateBarHeights({ maxTop, maxBottom, halfHeight, vScale, }) {
|
|
28
|
-
|
|
29
|
+
export function calculateBarHeights({ maxTop, maxBottom, halfHeight, vScale, barMinHeight = 0, barAlign, }) {
|
|
30
|
+
let topHeight = Math.round(maxTop * halfHeight * vScale);
|
|
29
31
|
const bottomHeight = Math.round(maxBottom * halfHeight * vScale);
|
|
30
|
-
|
|
32
|
+
let totalHeight = topHeight + bottomHeight || 1;
|
|
33
|
+
if (totalHeight < barMinHeight) {
|
|
34
|
+
totalHeight = barMinHeight;
|
|
35
|
+
if (!barAlign) {
|
|
36
|
+
topHeight = totalHeight / 2;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
31
39
|
return { topHeight, totalHeight };
|
|
32
40
|
}
|
|
33
41
|
export function resolveBarYPosition({ barAlign, halfHeight, topHeight, totalHeight, canvasHeight, }) {
|
|
@@ -37,7 +45,7 @@ export function resolveBarYPosition({ barAlign, halfHeight, topHeight, totalHeig
|
|
|
37
45
|
return canvasHeight - totalHeight;
|
|
38
46
|
return halfHeight - topHeight;
|
|
39
47
|
}
|
|
40
|
-
export function calculateBarSegments({ channelData, barIndexScale, barSpacing, barWidth, halfHeight, vScale, canvasHeight, barAlign, }) {
|
|
48
|
+
export function calculateBarSegments({ channelData, barIndexScale, barSpacing, barWidth, halfHeight, vScale, canvasHeight, barAlign, barMinHeight, }) {
|
|
41
49
|
const topChannel = channelData[0] || [];
|
|
42
50
|
const bottomChannel = channelData[1] || topChannel;
|
|
43
51
|
const length = topChannel.length;
|
|
@@ -53,6 +61,8 @@ export function calculateBarSegments({ channelData, barIndexScale, barSpacing, b
|
|
|
53
61
|
maxBottom,
|
|
54
62
|
halfHeight,
|
|
55
63
|
vScale,
|
|
64
|
+
barMinHeight,
|
|
65
|
+
barAlign,
|
|
56
66
|
});
|
|
57
67
|
const y = resolveBarYPosition({
|
|
58
68
|
barAlign,
|
|
@@ -108,7 +118,7 @@ export function getPixelRatio(devicePixelRatio) {
|
|
|
108
118
|
export function shouldRenderBars(options) {
|
|
109
119
|
return Boolean(options.barWidth || options.barGap || options.barAlign);
|
|
110
120
|
}
|
|
111
|
-
export function resolveColorValue(color, devicePixelRatio) {
|
|
121
|
+
export function resolveColorValue(color, devicePixelRatio, canvasHeight) {
|
|
112
122
|
if (!Array.isArray(color))
|
|
113
123
|
return color || '';
|
|
114
124
|
if (color.length === 0)
|
|
@@ -117,7 +127,7 @@ export function resolveColorValue(color, devicePixelRatio) {
|
|
|
117
127
|
return color[0] || '';
|
|
118
128
|
const canvasElement = document.createElement('canvas');
|
|
119
129
|
const ctx = canvasElement.getContext('2d');
|
|
120
|
-
const gradientHeight = canvasElement.height * devicePixelRatio;
|
|
130
|
+
const gradientHeight = canvasHeight !== null && canvasHeight !== void 0 ? canvasHeight : canvasElement.height * devicePixelRatio;
|
|
121
131
|
const gradient = ctx.createLinearGradient(0, 0, 0, gradientHeight || devicePixelRatio);
|
|
122
132
|
const colorStopPercentage = 1 / (color.length - 1);
|
|
123
133
|
color.forEach((value, index) => {
|
|
@@ -168,7 +178,7 @@ export function getLazyRenderRange({ scrollLeft, totalWidth, numCanvases, }) {
|
|
|
168
178
|
const startCanvas = Math.floor(viewPosition * numCanvases);
|
|
169
179
|
return [startCanvas - 1, startCanvas, startCanvas + 1];
|
|
170
180
|
}
|
|
171
|
-
export function calculateVerticalScale({ channelData, barHeight, normalize, }) {
|
|
181
|
+
export function calculateVerticalScale({ channelData, barHeight, normalize, maxPeak, }) {
|
|
172
182
|
var _a;
|
|
173
183
|
const baseScale = barHeight || 1;
|
|
174
184
|
if (!normalize)
|
|
@@ -176,12 +186,15 @@ export function calculateVerticalScale({ channelData, barHeight, normalize, }) {
|
|
|
176
186
|
const firstChannel = channelData[0];
|
|
177
187
|
if (!firstChannel || firstChannel.length === 0)
|
|
178
188
|
return baseScale;
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
189
|
+
// Use fixed max peak if provided, otherwise calculate from data
|
|
190
|
+
let max = maxPeak !== null && maxPeak !== void 0 ? maxPeak : 0;
|
|
191
|
+
if (!maxPeak) {
|
|
192
|
+
for (let i = 0; i < firstChannel.length; i++) {
|
|
193
|
+
const value = (_a = firstChannel[i]) !== null && _a !== void 0 ? _a : 0;
|
|
194
|
+
const magnitude = Math.abs(value);
|
|
195
|
+
if (magnitude > max)
|
|
196
|
+
max = magnitude;
|
|
197
|
+
}
|
|
185
198
|
}
|
|
186
199
|
if (!max)
|
|
187
200
|
return baseScale;
|
|
@@ -217,13 +230,20 @@ export function calculateLinePaths({ channelData, width, height, vScale, }) {
|
|
|
217
230
|
return path;
|
|
218
231
|
});
|
|
219
232
|
}
|
|
233
|
+
/**
|
|
234
|
+
* @deprecated Use calculateScrollPercentages from './reactive/scroll-stream.js' instead.
|
|
235
|
+
* This function is maintained for backward compatibility but will be removed in a future version.
|
|
236
|
+
*/
|
|
220
237
|
export function calculateScrollPercentages({ scrollLeft, clientWidth, scrollWidth, }) {
|
|
221
238
|
if (scrollWidth === 0) {
|
|
222
|
-
return { startX: 0, endX:
|
|
239
|
+
return { startX: 0, endX: 1 };
|
|
223
240
|
}
|
|
224
241
|
const startX = scrollLeft / scrollWidth;
|
|
225
242
|
const endX = (scrollLeft + clientWidth) / scrollWidth;
|
|
226
|
-
return {
|
|
243
|
+
return {
|
|
244
|
+
startX: Math.max(0, Math.min(1, startX)),
|
|
245
|
+
endX: Math.max(0, Math.min(1, endX)),
|
|
246
|
+
};
|
|
227
247
|
}
|
|
228
248
|
export function roundToHalfAwayFromZero(value) {
|
|
229
249
|
const scaled = value * 2;
|
package/dist/renderer.d.ts
CHANGED
|
@@ -28,7 +28,8 @@ declare class Renderer extends EventEmitter<RendererEvents> {
|
|
|
28
28
|
private isDragging;
|
|
29
29
|
private subscriptions;
|
|
30
30
|
private unsubscribeOnScroll;
|
|
31
|
-
private
|
|
31
|
+
private dragStream;
|
|
32
|
+
private scrollStream;
|
|
32
33
|
constructor(options: WaveSurferOptions, audioElement?: HTMLElement);
|
|
33
34
|
private parentFromOptionsContainer;
|
|
34
35
|
private initEvents;
|
package/dist/renderer.js
CHANGED
|
@@ -18,9 +18,11 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
18
18
|
}
|
|
19
19
|
return t;
|
|
20
20
|
};
|
|
21
|
-
import { makeDraggable } from './draggable.js';
|
|
22
21
|
import EventEmitter from './event-emitter.js';
|
|
23
22
|
import * as utils from './renderer-utils.js';
|
|
23
|
+
import { createDragStream } from './reactive/drag-stream.js';
|
|
24
|
+
import { createScrollStream } from './reactive/scroll-stream.js';
|
|
25
|
+
import { effect } from './reactive/store.js';
|
|
24
26
|
class Renderer extends EventEmitter {
|
|
25
27
|
constructor(options, audioElement) {
|
|
26
28
|
super();
|
|
@@ -32,7 +34,8 @@ class Renderer extends EventEmitter {
|
|
|
32
34
|
this.isDragging = false;
|
|
33
35
|
this.subscriptions = [];
|
|
34
36
|
this.unsubscribeOnScroll = [];
|
|
35
|
-
this.
|
|
37
|
+
this.dragStream = null;
|
|
38
|
+
this.scrollStream = null;
|
|
36
39
|
this.subscriptions = [];
|
|
37
40
|
this.options = options;
|
|
38
41
|
const parent = this.parentFromOptionsContainer(options.container);
|
|
@@ -80,16 +83,14 @@ class Renderer extends EventEmitter {
|
|
|
80
83
|
if (this.options.dragToSeek === true || typeof this.options.dragToSeek === 'object') {
|
|
81
84
|
this.initDrag();
|
|
82
85
|
}
|
|
83
|
-
// Add a scroll listener
|
|
84
|
-
this.
|
|
85
|
-
|
|
86
|
-
const { startX, endX } =
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
this.emit('scroll', startX, endX, scrollLeft, scrollLeft + clientWidth);
|
|
92
|
-
});
|
|
86
|
+
// Add a scroll listener using reactive stream
|
|
87
|
+
this.scrollStream = createScrollStream(this.scrollContainer);
|
|
88
|
+
const unsubscribeScroll = effect(() => {
|
|
89
|
+
const { startX, endX } = this.scrollStream.percentages.value;
|
|
90
|
+
const { left, right } = this.scrollStream.bounds.value;
|
|
91
|
+
this.emit('scroll', startX, endX, left, right);
|
|
92
|
+
}, [this.scrollStream.percentages, this.scrollStream.bounds]);
|
|
93
|
+
this.subscriptions.push(unsubscribeScroll);
|
|
93
94
|
// Re-render the waveform on container resize
|
|
94
95
|
if (typeof ResizeObserver === 'function') {
|
|
95
96
|
const delay = this.createDelay(100);
|
|
@@ -111,27 +112,28 @@ class Renderer extends EventEmitter {
|
|
|
111
112
|
}
|
|
112
113
|
initDrag() {
|
|
113
114
|
// Don't initialize drag if it's already set up
|
|
114
|
-
if (this.
|
|
115
|
+
if (this.dragStream)
|
|
115
116
|
return;
|
|
116
|
-
this.
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
},
|
|
122
|
-
// On start drag
|
|
123
|
-
(x) => {
|
|
124
|
-
this.isDragging = true;
|
|
125
|
-
const width = this.wrapper.getBoundingClientRect().width;
|
|
126
|
-
this.emit('dragstart', utils.clampToUnit(x / width));
|
|
127
|
-
},
|
|
128
|
-
// On end drag
|
|
129
|
-
(x) => {
|
|
130
|
-
this.isDragging = false;
|
|
117
|
+
this.dragStream = createDragStream(this.wrapper);
|
|
118
|
+
const unsubscribeDrag = effect(() => {
|
|
119
|
+
const drag = this.dragStream.signal.value;
|
|
120
|
+
if (!drag)
|
|
121
|
+
return;
|
|
131
122
|
const width = this.wrapper.getBoundingClientRect().width;
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
123
|
+
const relX = utils.clampToUnit(drag.x / width);
|
|
124
|
+
if (drag.type === 'start') {
|
|
125
|
+
this.isDragging = true;
|
|
126
|
+
this.emit('dragstart', relX);
|
|
127
|
+
}
|
|
128
|
+
else if (drag.type === 'move') {
|
|
129
|
+
this.emit('drag', relX);
|
|
130
|
+
}
|
|
131
|
+
else if (drag.type === 'end') {
|
|
132
|
+
this.isDragging = false;
|
|
133
|
+
this.emit('dragend', relX);
|
|
134
|
+
}
|
|
135
|
+
}, [this.dragStream.signal]);
|
|
136
|
+
this.subscriptions.push(unsubscribeDrag);
|
|
135
137
|
}
|
|
136
138
|
initHtml() {
|
|
137
139
|
const div = document.createElement('div');
|
|
@@ -254,6 +256,14 @@ class Renderer extends EventEmitter {
|
|
|
254
256
|
}
|
|
255
257
|
(_a = this.unsubscribeOnScroll) === null || _a === void 0 ? void 0 : _a.forEach((unsubscribe) => unsubscribe());
|
|
256
258
|
this.unsubscribeOnScroll = [];
|
|
259
|
+
if (this.dragStream) {
|
|
260
|
+
this.dragStream.cleanup();
|
|
261
|
+
this.dragStream = null;
|
|
262
|
+
}
|
|
263
|
+
if (this.scrollStream) {
|
|
264
|
+
this.scrollStream.cleanup();
|
|
265
|
+
this.scrollStream = null;
|
|
266
|
+
}
|
|
257
267
|
}
|
|
258
268
|
createDelay(delayMs = 10) {
|
|
259
269
|
let timeout;
|
|
@@ -295,15 +305,15 @@ class Renderer extends EventEmitter {
|
|
|
295
305
|
defaultHeight: utils.DEFAULT_HEIGHT,
|
|
296
306
|
});
|
|
297
307
|
}
|
|
298
|
-
convertColorValues(color) {
|
|
299
|
-
return utils.resolveColorValue(color, this.getPixelRatio());
|
|
308
|
+
convertColorValues(color, ctx) {
|
|
309
|
+
return utils.resolveColorValue(color, this.getPixelRatio(), ctx === null || ctx === void 0 ? void 0 : ctx.canvas.height);
|
|
300
310
|
}
|
|
301
311
|
getPixelRatio() {
|
|
302
312
|
return utils.getPixelRatio(window.devicePixelRatio);
|
|
303
313
|
}
|
|
304
314
|
renderBarWaveform(channelData, options, ctx, vScale) {
|
|
305
315
|
const { width, height } = ctx.canvas;
|
|
306
|
-
const { halfHeight, barWidth, barRadius, barIndexScale, barSpacing } = utils.calculateBarRenderConfig({
|
|
316
|
+
const { halfHeight, barWidth, barRadius, barIndexScale, barSpacing, barMinHeight } = utils.calculateBarRenderConfig({
|
|
307
317
|
width,
|
|
308
318
|
height,
|
|
309
319
|
length: (channelData[0] || []).length,
|
|
@@ -319,6 +329,7 @@ class Renderer extends EventEmitter {
|
|
|
319
329
|
vScale,
|
|
320
330
|
canvasHeight: height,
|
|
321
331
|
barAlign: options.barAlign,
|
|
332
|
+
barMinHeight,
|
|
322
333
|
});
|
|
323
334
|
ctx.beginPath();
|
|
324
335
|
for (const segment of segments) {
|
|
@@ -350,7 +361,7 @@ class Renderer extends EventEmitter {
|
|
|
350
361
|
ctx.closePath();
|
|
351
362
|
}
|
|
352
363
|
renderWaveform(channelData, options, ctx) {
|
|
353
|
-
ctx.fillStyle = this.convertColorValues(options.waveColor);
|
|
364
|
+
ctx.fillStyle = this.convertColorValues(options.waveColor, ctx);
|
|
354
365
|
if (options.renderFunction) {
|
|
355
366
|
options.renderFunction(channelData, ctx);
|
|
356
367
|
return;
|
|
@@ -359,6 +370,7 @@ class Renderer extends EventEmitter {
|
|
|
359
370
|
channelData,
|
|
360
371
|
barHeight: options.barHeight,
|
|
361
372
|
normalize: options.normalize,
|
|
373
|
+
maxPeak: options.maxPeak,
|
|
362
374
|
});
|
|
363
375
|
if (utils.shouldRenderBars(options)) {
|
|
364
376
|
this.renderBarWaveform(channelData, options, ctx, vScale);
|
|
@@ -377,7 +389,7 @@ class Renderer extends EventEmitter {
|
|
|
377
389
|
canvasContainer.appendChild(canvas);
|
|
378
390
|
const ctx = canvas.getContext('2d');
|
|
379
391
|
if (options.renderFunction) {
|
|
380
|
-
ctx.fillStyle = this.convertColorValues(options.waveColor);
|
|
392
|
+
ctx.fillStyle = this.convertColorValues(options.waveColor, ctx);
|
|
381
393
|
options.renderFunction(data, ctx);
|
|
382
394
|
}
|
|
383
395
|
else {
|
|
@@ -390,7 +402,7 @@ class Renderer extends EventEmitter {
|
|
|
390
402
|
progressCtx.drawImage(canvas, 0, 0);
|
|
391
403
|
// Set the composition method to draw only where the waveform is drawn
|
|
392
404
|
progressCtx.globalCompositeOperation = 'source-in';
|
|
393
|
-
progressCtx.fillStyle = this.convertColorValues(options.progressColor);
|
|
405
|
+
progressCtx.fillStyle = this.convertColorValues(options.progressColor, progressCtx);
|
|
394
406
|
// This rectangle acts as a mask thanks to the composition method
|
|
395
407
|
progressCtx.fillRect(0, 0, canvas.width, canvas.height);
|
|
396
408
|
progressContainer.appendChild(progressCanvas);
|
|
@@ -574,16 +586,6 @@ class Renderer extends EventEmitter {
|
|
|
574
586
|
this.scrollContainer.scrollLeft += center;
|
|
575
587
|
}
|
|
576
588
|
}
|
|
577
|
-
// Emit the scroll event
|
|
578
|
-
{
|
|
579
|
-
const newScroll = this.scrollContainer.scrollLeft;
|
|
580
|
-
const { startX, endX } = utils.calculateScrollPercentages({
|
|
581
|
-
scrollLeft: newScroll,
|
|
582
|
-
scrollWidth,
|
|
583
|
-
clientWidth,
|
|
584
|
-
});
|
|
585
|
-
this.emit('scroll', startX, endX, newScroll, newScroll + clientWidth);
|
|
586
|
-
}
|
|
587
589
|
}
|
|
588
590
|
renderProgress(progress, isPlaying) {
|
|
589
591
|
if (isNaN(progress))
|
|
@@ -595,7 +597,8 @@ class Renderer extends EventEmitter {
|
|
|
595
597
|
this.cursor.style.transform = this.options.cursorWidth
|
|
596
598
|
? `translateX(-${progress * this.options.cursorWidth}px)`
|
|
597
599
|
: '';
|
|
598
|
-
if
|
|
600
|
+
// Only scroll if we have valid audio data to prevent race conditions during loading
|
|
601
|
+
if (this.isScrollable && this.options.autoScroll && this.audioData && this.audioData.duration > 0) {
|
|
599
602
|
this.scrollIntoView(progress, isPlaying);
|
|
600
603
|
}
|
|
601
604
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|