wavesurfer.js 7.11.0 → 7.12.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.
- package/README.md +1 -1
- package/dist/__tests__/memory-leaks.test.d.ts +7 -0
- package/dist/__tests__/memory-leaks.test.js +184 -0
- package/dist/__tests__/player.test.js +107 -0
- package/dist/__tests__/renderer-utils.test.d.ts +1 -0
- package/dist/__tests__/renderer-utils.test.js +373 -0
- package/dist/decoder.js +12 -4
- package/dist/draggable.d.ts +4 -0
- package/dist/draggable.js +20 -5
- package/dist/fetcher.js +14 -23
- 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.d.ts +10 -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 +126 -0
- package/dist/renderer-utils.js +252 -0
- package/dist/renderer.d.ts +4 -4
- package/dist/renderer.js +133 -197
- 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 +167 -1
- package/dist/wavesurfer.cjs +1 -1
- package/dist/wavesurfer.d.ts +18 -0
- package/dist/wavesurfer.esm.js +1 -1
- package/dist/wavesurfer.js +46 -8
- package/dist/wavesurfer.min.js +1 -1
- package/dist/webaudio.js +4 -0
- package/package.json +6 -6
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import type { WaveSurferOptions } from './wavesurfer.js';
|
|
2
|
+
export type ChannelData = Array<Float32Array | number[]>;
|
|
3
|
+
export type BarSegment = {
|
|
4
|
+
x: number;
|
|
5
|
+
y: number;
|
|
6
|
+
width: number;
|
|
7
|
+
height: number;
|
|
8
|
+
};
|
|
9
|
+
export type LinePath = Array<{
|
|
10
|
+
x: number;
|
|
11
|
+
y: number;
|
|
12
|
+
}>;
|
|
13
|
+
export declare const DEFAULT_HEIGHT = 128;
|
|
14
|
+
export declare const MAX_CANVAS_WIDTH = 8000;
|
|
15
|
+
export declare const MAX_NODES = 10;
|
|
16
|
+
export declare function clampToUnit(value: number): number;
|
|
17
|
+
export declare function calculateBarRenderConfig({ width, height, length, options, pixelRatio, }: {
|
|
18
|
+
width: number;
|
|
19
|
+
height: number;
|
|
20
|
+
length: number;
|
|
21
|
+
options: WaveSurferOptions;
|
|
22
|
+
pixelRatio: number;
|
|
23
|
+
}): {
|
|
24
|
+
halfHeight: number;
|
|
25
|
+
barWidth: number;
|
|
26
|
+
barGap: number;
|
|
27
|
+
barRadius: number;
|
|
28
|
+
barMinHeight: number;
|
|
29
|
+
barIndexScale: number;
|
|
30
|
+
barSpacing: number;
|
|
31
|
+
};
|
|
32
|
+
export declare function calculateBarHeights({ maxTop, maxBottom, halfHeight, vScale, barMinHeight, barAlign, }: {
|
|
33
|
+
maxTop: number;
|
|
34
|
+
maxBottom: number;
|
|
35
|
+
halfHeight: number;
|
|
36
|
+
vScale: number;
|
|
37
|
+
barMinHeight?: number;
|
|
38
|
+
barAlign?: WaveSurferOptions['barAlign'];
|
|
39
|
+
}): {
|
|
40
|
+
topHeight: number;
|
|
41
|
+
totalHeight: number;
|
|
42
|
+
};
|
|
43
|
+
export declare function resolveBarYPosition({ barAlign, halfHeight, topHeight, totalHeight, canvasHeight, }: {
|
|
44
|
+
barAlign: WaveSurferOptions['barAlign'];
|
|
45
|
+
halfHeight: number;
|
|
46
|
+
topHeight: number;
|
|
47
|
+
totalHeight: number;
|
|
48
|
+
canvasHeight: number;
|
|
49
|
+
}): number;
|
|
50
|
+
export declare function calculateBarSegments({ channelData, barIndexScale, barSpacing, barWidth, halfHeight, vScale, canvasHeight, barAlign, barMinHeight, }: {
|
|
51
|
+
channelData: ChannelData;
|
|
52
|
+
barIndexScale: number;
|
|
53
|
+
barSpacing: number;
|
|
54
|
+
barWidth: number;
|
|
55
|
+
halfHeight: number;
|
|
56
|
+
vScale: number;
|
|
57
|
+
canvasHeight: number;
|
|
58
|
+
barAlign: WaveSurferOptions['barAlign'];
|
|
59
|
+
barMinHeight: number;
|
|
60
|
+
}): BarSegment[];
|
|
61
|
+
export declare function getRelativePointerPosition(rect: DOMRect, clientX: number, clientY: number): [number, number];
|
|
62
|
+
export declare function resolveChannelHeight({ optionsHeight, optionsSplitChannels, parentHeight, numberOfChannels, defaultHeight, }: {
|
|
63
|
+
optionsHeight?: WaveSurferOptions['height'];
|
|
64
|
+
optionsSplitChannels?: WaveSurferOptions['splitChannels'];
|
|
65
|
+
parentHeight: number;
|
|
66
|
+
numberOfChannels: number;
|
|
67
|
+
defaultHeight?: number;
|
|
68
|
+
}): number;
|
|
69
|
+
export declare function getPixelRatio(devicePixelRatio?: number): number;
|
|
70
|
+
export declare function shouldRenderBars(options: WaveSurferOptions): boolean;
|
|
71
|
+
export declare function resolveColorValue(color: WaveSurferOptions['waveColor'], devicePixelRatio: number): string | CanvasGradient;
|
|
72
|
+
export declare function calculateWaveformLayout({ duration, minPxPerSec, parentWidth, fillParent, pixelRatio, }: {
|
|
73
|
+
duration: number;
|
|
74
|
+
minPxPerSec?: number;
|
|
75
|
+
parentWidth: number;
|
|
76
|
+
fillParent?: boolean;
|
|
77
|
+
pixelRatio: number;
|
|
78
|
+
}): {
|
|
79
|
+
scrollWidth: number;
|
|
80
|
+
isScrollable: boolean;
|
|
81
|
+
useParentWidth: boolean;
|
|
82
|
+
width: number;
|
|
83
|
+
};
|
|
84
|
+
export declare function clampWidthToBarGrid(width: number, options: WaveSurferOptions): number;
|
|
85
|
+
export declare function calculateSingleCanvasWidth({ clientWidth, totalWidth, options, }: {
|
|
86
|
+
clientWidth: number;
|
|
87
|
+
totalWidth: number;
|
|
88
|
+
options: WaveSurferOptions;
|
|
89
|
+
}): number;
|
|
90
|
+
export declare function sliceChannelData({ channelData, offset, clampedWidth, totalWidth, }: {
|
|
91
|
+
channelData: ChannelData;
|
|
92
|
+
offset: number;
|
|
93
|
+
clampedWidth: number;
|
|
94
|
+
totalWidth: number;
|
|
95
|
+
}): ChannelData;
|
|
96
|
+
export declare function shouldClearCanvases(currentNodeCount: number): boolean;
|
|
97
|
+
export declare function getLazyRenderRange({ scrollLeft, totalWidth, numCanvases, }: {
|
|
98
|
+
scrollLeft: number;
|
|
99
|
+
totalWidth: number;
|
|
100
|
+
numCanvases: number;
|
|
101
|
+
}): number[];
|
|
102
|
+
export declare function calculateVerticalScale({ channelData, barHeight, normalize, maxPeak, }: {
|
|
103
|
+
channelData: ChannelData;
|
|
104
|
+
barHeight?: WaveSurferOptions['barHeight'];
|
|
105
|
+
normalize?: WaveSurferOptions['normalize'];
|
|
106
|
+
maxPeak?: WaveSurferOptions['maxPeak'];
|
|
107
|
+
}): number;
|
|
108
|
+
export declare function calculateLinePaths({ channelData, width, height, vScale, }: {
|
|
109
|
+
channelData: ChannelData;
|
|
110
|
+
width: number;
|
|
111
|
+
height: number;
|
|
112
|
+
vScale: number;
|
|
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
|
+
*/
|
|
118
|
+
export declare function calculateScrollPercentages({ scrollLeft, clientWidth, scrollWidth, }: {
|
|
119
|
+
scrollLeft: number;
|
|
120
|
+
clientWidth: number;
|
|
121
|
+
scrollWidth: number;
|
|
122
|
+
}): {
|
|
123
|
+
startX: number;
|
|
124
|
+
endX: number;
|
|
125
|
+
};
|
|
126
|
+
export declare function roundToHalfAwayFromZero(value: number): number;
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
export const DEFAULT_HEIGHT = 128;
|
|
2
|
+
export const MAX_CANVAS_WIDTH = 8000;
|
|
3
|
+
export const MAX_NODES = 10;
|
|
4
|
+
export function clampToUnit(value) {
|
|
5
|
+
if (value < 0)
|
|
6
|
+
return 0;
|
|
7
|
+
if (value > 1)
|
|
8
|
+
return 1;
|
|
9
|
+
return value;
|
|
10
|
+
}
|
|
11
|
+
export function calculateBarRenderConfig({ width, height, length, options, pixelRatio, }) {
|
|
12
|
+
const halfHeight = height / 2;
|
|
13
|
+
const barWidth = options.barWidth ? options.barWidth * pixelRatio : 1;
|
|
14
|
+
const barGap = options.barGap ? options.barGap * pixelRatio : options.barWidth ? barWidth / 2 : 0;
|
|
15
|
+
const barRadius = options.barRadius || 0;
|
|
16
|
+
const barMinHeight = options.barMinHeight ? options.barMinHeight * pixelRatio : 0;
|
|
17
|
+
const spacing = barWidth + barGap || 1;
|
|
18
|
+
const barIndexScale = length > 0 ? width / spacing / length : 0;
|
|
19
|
+
return {
|
|
20
|
+
halfHeight,
|
|
21
|
+
barWidth,
|
|
22
|
+
barGap,
|
|
23
|
+
barRadius,
|
|
24
|
+
barMinHeight,
|
|
25
|
+
barIndexScale,
|
|
26
|
+
barSpacing: spacing,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export function calculateBarHeights({ maxTop, maxBottom, halfHeight, vScale, barMinHeight = 0, barAlign, }) {
|
|
30
|
+
let topHeight = Math.round(maxTop * halfHeight * vScale);
|
|
31
|
+
const bottomHeight = Math.round(maxBottom * halfHeight * vScale);
|
|
32
|
+
let totalHeight = topHeight + bottomHeight || 1;
|
|
33
|
+
if (totalHeight < barMinHeight) {
|
|
34
|
+
totalHeight = barMinHeight;
|
|
35
|
+
if (!barAlign) {
|
|
36
|
+
topHeight = totalHeight / 2;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return { topHeight, totalHeight };
|
|
40
|
+
}
|
|
41
|
+
export function resolveBarYPosition({ barAlign, halfHeight, topHeight, totalHeight, canvasHeight, }) {
|
|
42
|
+
if (barAlign === 'top')
|
|
43
|
+
return 0;
|
|
44
|
+
if (barAlign === 'bottom')
|
|
45
|
+
return canvasHeight - totalHeight;
|
|
46
|
+
return halfHeight - topHeight;
|
|
47
|
+
}
|
|
48
|
+
export function calculateBarSegments({ channelData, barIndexScale, barSpacing, barWidth, halfHeight, vScale, canvasHeight, barAlign, barMinHeight, }) {
|
|
49
|
+
const topChannel = channelData[0] || [];
|
|
50
|
+
const bottomChannel = channelData[1] || topChannel;
|
|
51
|
+
const length = topChannel.length;
|
|
52
|
+
const segments = [];
|
|
53
|
+
let prevX = 0;
|
|
54
|
+
let maxTop = 0;
|
|
55
|
+
let maxBottom = 0;
|
|
56
|
+
for (let i = 0; i <= length; i++) {
|
|
57
|
+
const x = Math.round(i * barIndexScale);
|
|
58
|
+
if (x > prevX) {
|
|
59
|
+
const { topHeight, totalHeight } = calculateBarHeights({
|
|
60
|
+
maxTop,
|
|
61
|
+
maxBottom,
|
|
62
|
+
halfHeight,
|
|
63
|
+
vScale,
|
|
64
|
+
barMinHeight,
|
|
65
|
+
barAlign,
|
|
66
|
+
});
|
|
67
|
+
const y = resolveBarYPosition({
|
|
68
|
+
barAlign,
|
|
69
|
+
halfHeight,
|
|
70
|
+
topHeight,
|
|
71
|
+
totalHeight,
|
|
72
|
+
canvasHeight,
|
|
73
|
+
});
|
|
74
|
+
segments.push({
|
|
75
|
+
x: prevX * barSpacing,
|
|
76
|
+
y,
|
|
77
|
+
width: barWidth,
|
|
78
|
+
height: totalHeight,
|
|
79
|
+
});
|
|
80
|
+
prevX = x;
|
|
81
|
+
maxTop = 0;
|
|
82
|
+
maxBottom = 0;
|
|
83
|
+
}
|
|
84
|
+
const magnitudeTop = Math.abs(topChannel[i] || 0);
|
|
85
|
+
const magnitudeBottom = Math.abs(bottomChannel[i] || 0);
|
|
86
|
+
if (magnitudeTop > maxTop)
|
|
87
|
+
maxTop = magnitudeTop;
|
|
88
|
+
if (magnitudeBottom > maxBottom)
|
|
89
|
+
maxBottom = magnitudeBottom;
|
|
90
|
+
}
|
|
91
|
+
return segments;
|
|
92
|
+
}
|
|
93
|
+
export function getRelativePointerPosition(rect, clientX, clientY) {
|
|
94
|
+
const x = clientX - rect.left;
|
|
95
|
+
const y = clientY - rect.top;
|
|
96
|
+
const relativeX = x / rect.width;
|
|
97
|
+
const relativeY = y / rect.height;
|
|
98
|
+
return [relativeX, relativeY];
|
|
99
|
+
}
|
|
100
|
+
export function resolveChannelHeight({ optionsHeight, optionsSplitChannels, parentHeight, numberOfChannels, defaultHeight = DEFAULT_HEIGHT, }) {
|
|
101
|
+
if (optionsHeight == null)
|
|
102
|
+
return defaultHeight;
|
|
103
|
+
const numericHeight = Number(optionsHeight);
|
|
104
|
+
if (!isNaN(numericHeight))
|
|
105
|
+
return numericHeight;
|
|
106
|
+
if (optionsHeight === 'auto') {
|
|
107
|
+
const height = parentHeight || defaultHeight;
|
|
108
|
+
if (optionsSplitChannels === null || optionsSplitChannels === void 0 ? void 0 : optionsSplitChannels.every((channel) => !channel.overlay)) {
|
|
109
|
+
return height / numberOfChannels;
|
|
110
|
+
}
|
|
111
|
+
return height;
|
|
112
|
+
}
|
|
113
|
+
return defaultHeight;
|
|
114
|
+
}
|
|
115
|
+
export function getPixelRatio(devicePixelRatio) {
|
|
116
|
+
return Math.max(1, devicePixelRatio || 1);
|
|
117
|
+
}
|
|
118
|
+
export function shouldRenderBars(options) {
|
|
119
|
+
return Boolean(options.barWidth || options.barGap || options.barAlign);
|
|
120
|
+
}
|
|
121
|
+
export function resolveColorValue(color, devicePixelRatio) {
|
|
122
|
+
if (!Array.isArray(color))
|
|
123
|
+
return color || '';
|
|
124
|
+
if (color.length === 0)
|
|
125
|
+
return '#999';
|
|
126
|
+
if (color.length < 2)
|
|
127
|
+
return color[0] || '';
|
|
128
|
+
const canvasElement = document.createElement('canvas');
|
|
129
|
+
const ctx = canvasElement.getContext('2d');
|
|
130
|
+
const gradientHeight = canvasElement.height * devicePixelRatio;
|
|
131
|
+
const gradient = ctx.createLinearGradient(0, 0, 0, gradientHeight || devicePixelRatio);
|
|
132
|
+
const colorStopPercentage = 1 / (color.length - 1);
|
|
133
|
+
color.forEach((value, index) => {
|
|
134
|
+
gradient.addColorStop(index * colorStopPercentage, value);
|
|
135
|
+
});
|
|
136
|
+
return gradient;
|
|
137
|
+
}
|
|
138
|
+
export function calculateWaveformLayout({ duration, minPxPerSec = 0, parentWidth, fillParent, pixelRatio, }) {
|
|
139
|
+
const scrollWidth = Math.ceil(duration * minPxPerSec);
|
|
140
|
+
const isScrollable = scrollWidth > parentWidth;
|
|
141
|
+
const useParentWidth = Boolean(fillParent && !isScrollable);
|
|
142
|
+
const width = (useParentWidth ? parentWidth : scrollWidth) * pixelRatio;
|
|
143
|
+
return {
|
|
144
|
+
scrollWidth,
|
|
145
|
+
isScrollable,
|
|
146
|
+
useParentWidth,
|
|
147
|
+
width,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
export function clampWidthToBarGrid(width, options) {
|
|
151
|
+
if (!shouldRenderBars(options))
|
|
152
|
+
return width;
|
|
153
|
+
const barWidth = options.barWidth || 0.5;
|
|
154
|
+
const barGap = options.barGap || barWidth / 2;
|
|
155
|
+
const totalBarWidth = barWidth + barGap;
|
|
156
|
+
if (totalBarWidth === 0)
|
|
157
|
+
return width;
|
|
158
|
+
return Math.floor(width / totalBarWidth) * totalBarWidth;
|
|
159
|
+
}
|
|
160
|
+
export function calculateSingleCanvasWidth({ clientWidth, totalWidth, options, }) {
|
|
161
|
+
const baseWidth = Math.min(MAX_CANVAS_WIDTH, clientWidth, totalWidth);
|
|
162
|
+
return clampWidthToBarGrid(baseWidth, options);
|
|
163
|
+
}
|
|
164
|
+
export function sliceChannelData({ channelData, offset, clampedWidth, totalWidth, }) {
|
|
165
|
+
return channelData.map((channel) => {
|
|
166
|
+
const start = Math.floor((offset / totalWidth) * channel.length);
|
|
167
|
+
const end = Math.floor(((offset + clampedWidth) / totalWidth) * channel.length);
|
|
168
|
+
return channel.slice(start, end);
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
export function shouldClearCanvases(currentNodeCount) {
|
|
172
|
+
return currentNodeCount > MAX_NODES;
|
|
173
|
+
}
|
|
174
|
+
export function getLazyRenderRange({ scrollLeft, totalWidth, numCanvases, }) {
|
|
175
|
+
if (totalWidth === 0)
|
|
176
|
+
return [0];
|
|
177
|
+
const viewPosition = scrollLeft / totalWidth;
|
|
178
|
+
const startCanvas = Math.floor(viewPosition * numCanvases);
|
|
179
|
+
return [startCanvas - 1, startCanvas, startCanvas + 1];
|
|
180
|
+
}
|
|
181
|
+
export function calculateVerticalScale({ channelData, barHeight, normalize, maxPeak, }) {
|
|
182
|
+
var _a;
|
|
183
|
+
const baseScale = barHeight || 1;
|
|
184
|
+
if (!normalize)
|
|
185
|
+
return baseScale;
|
|
186
|
+
const firstChannel = channelData[0];
|
|
187
|
+
if (!firstChannel || firstChannel.length === 0)
|
|
188
|
+
return baseScale;
|
|
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
|
+
}
|
|
198
|
+
}
|
|
199
|
+
if (!max)
|
|
200
|
+
return baseScale;
|
|
201
|
+
return baseScale / max;
|
|
202
|
+
}
|
|
203
|
+
export function calculateLinePaths({ channelData, width, height, vScale, }) {
|
|
204
|
+
const halfHeight = height / 2;
|
|
205
|
+
const primaryChannel = channelData[0] || [];
|
|
206
|
+
const secondaryChannel = channelData[1] || primaryChannel;
|
|
207
|
+
const channels = [primaryChannel, secondaryChannel];
|
|
208
|
+
return channels.map((channel, index) => {
|
|
209
|
+
const length = channel.length;
|
|
210
|
+
const hScale = length ? width / length : 0;
|
|
211
|
+
const baseY = halfHeight;
|
|
212
|
+
const direction = index === 0 ? -1 : 1;
|
|
213
|
+
const path = [{ x: 0, y: baseY }];
|
|
214
|
+
let prevX = 0;
|
|
215
|
+
let max = 0;
|
|
216
|
+
for (let i = 0; i <= length; i++) {
|
|
217
|
+
const x = Math.round(i * hScale);
|
|
218
|
+
if (x > prevX) {
|
|
219
|
+
const heightDelta = Math.round(max * halfHeight * vScale) || 1;
|
|
220
|
+
const y = baseY + heightDelta * direction;
|
|
221
|
+
path.push({ x: prevX, y });
|
|
222
|
+
prevX = x;
|
|
223
|
+
max = 0;
|
|
224
|
+
}
|
|
225
|
+
const value = Math.abs(channel[i] || 0);
|
|
226
|
+
if (value > max)
|
|
227
|
+
max = value;
|
|
228
|
+
}
|
|
229
|
+
path.push({ x: prevX, y: baseY });
|
|
230
|
+
return path;
|
|
231
|
+
});
|
|
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
|
+
*/
|
|
237
|
+
export function calculateScrollPercentages({ scrollLeft, clientWidth, scrollWidth, }) {
|
|
238
|
+
if (scrollWidth === 0) {
|
|
239
|
+
return { startX: 0, endX: 1 };
|
|
240
|
+
}
|
|
241
|
+
const startX = scrollLeft / scrollWidth;
|
|
242
|
+
const endX = (scrollLeft + clientWidth) / scrollWidth;
|
|
243
|
+
return {
|
|
244
|
+
startX: Math.max(0, Math.min(1, startX)),
|
|
245
|
+
endX: Math.max(0, Math.min(1, endX)),
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
export function roundToHalfAwayFromZero(value) {
|
|
249
|
+
const scaled = value * 2;
|
|
250
|
+
const rounded = scaled < 0 ? Math.floor(scaled) : Math.ceil(scaled);
|
|
251
|
+
return rounded / 2;
|
|
252
|
+
}
|
package/dist/renderer.d.ts
CHANGED
|
@@ -9,10 +9,9 @@ type RendererEvents = {
|
|
|
9
9
|
scroll: [relativeStart: number, relativeEnd: number, scrollLeft: number, scrollRight: number];
|
|
10
10
|
render: [];
|
|
11
11
|
rendered: [];
|
|
12
|
+
resize: [];
|
|
12
13
|
};
|
|
13
14
|
declare class Renderer extends EventEmitter<RendererEvents> {
|
|
14
|
-
private static MAX_CANVAS_WIDTH;
|
|
15
|
-
private static MAX_NODES;
|
|
16
15
|
private options;
|
|
17
16
|
private parent;
|
|
18
17
|
private container;
|
|
@@ -29,13 +28,13 @@ declare class Renderer extends EventEmitter<RendererEvents> {
|
|
|
29
28
|
private isDragging;
|
|
30
29
|
private subscriptions;
|
|
31
30
|
private unsubscribeOnScroll;
|
|
32
|
-
private
|
|
31
|
+
private dragStream;
|
|
32
|
+
private scrollStream;
|
|
33
33
|
constructor(options: WaveSurferOptions, audioElement?: HTMLElement);
|
|
34
34
|
private parentFromOptionsContainer;
|
|
35
35
|
private initEvents;
|
|
36
36
|
private onContainerResize;
|
|
37
37
|
private initDrag;
|
|
38
|
-
private getHeight;
|
|
39
38
|
private initHtml;
|
|
40
39
|
/** Wavesurfer itself calls this method. Do not call it manually. */
|
|
41
40
|
setOptions(options: WaveSurferOptions): void;
|
|
@@ -46,6 +45,7 @@ declare class Renderer extends EventEmitter<RendererEvents> {
|
|
|
46
45
|
setScrollPercentage(percent: number): void;
|
|
47
46
|
destroy(): void;
|
|
48
47
|
private createDelay;
|
|
48
|
+
private getHeight;
|
|
49
49
|
private convertColorValues;
|
|
50
50
|
private getPixelRatio;
|
|
51
51
|
private renderBarWaveform;
|