Skip to content

Commit

Permalink
Added exponential zooming and a few bugfixes
Browse files Browse the repository at this point in the history
  • Loading branch information
gustavso committed Nov 19, 2024
1 parent 5f480f3 commit 4332faf
Showing 1 changed file with 67 additions and 7 deletions.
74 changes: 67 additions & 7 deletions src/plugins/zoom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* @author HoodyHuo (https://github.com/HoodyHuo)
* @author Chris Morbitzer (https://github.com/cmorbitzer)
* @author Sam Hulick (https://github.com/ffxsam)
* @autor Gustav Sollenius (https://github.com/gustavsollenius)
*
* @example
* // ... initialising wavesurfer with the plugin
Expand Down Expand Up @@ -36,10 +37,28 @@ export type ZoomPluginOptions = {
* @default 5
*/
deltaThreshold?: number
/**
* Whether to zoom into the waveform using a consistent exponential factor instead of a linear scale.
* Exponential zooming ensures the zoom steps feel uniform regardless of scale.
* When disabled, the zooming is linear and influenced by the `scale` parameter.
*
* @default false
*/
exponentialZooming?: boolean
/**
* Number of steps required to zoom from the initial zoom level to `maxZoom`.
*
* @default 20
*/
iterations?: number


}
const defaultOptions = {
scale: 0.5,
deltaThreshold: 5,
exponentialZooming: false,
iterations: 20,
}

export type ZoomPluginEvents = BasePluginEvents
Expand All @@ -49,6 +68,14 @@ class ZoomPlugin extends BasePlugin<ZoomPluginEvents, ZoomPluginOptions> {
private wrapper: HTMLElement | undefined = undefined
private container: HTMLElement | null = null
private accumulatedDelta = 0
private pointerTime: number = 0;
private oldX: number = 0;
private endZoom: number = 0;
private startZoom: number = 0;

private preventScroll = (e: WheelEvent) => {
e.preventDefault();
};

constructor(options?: ZoomPluginOptions) {
super(options || {})
Expand All @@ -66,6 +93,15 @@ class ZoomPlugin extends BasePlugin<ZoomPluginEvents, ZoomPluginOptions> {
}
this.container = this.wrapper.parentElement as HTMLElement
this.wrapper.addEventListener('wheel', this.onWheel)

// Prevent native scrolling obstructing the zoom on this waveform
document.addEventListener('wheel', this.preventScroll, { passive: false });

if(typeof this.options.maxZoom === 'undefined'){
this.options.maxZoom = this.container.clientWidth
console.log("maxZoom", this.options.maxZoom)
}
this.endZoom = this.options.maxZoom
}

private onWheel = (e: WheelEvent) => {
Expand All @@ -78,14 +114,27 @@ class ZoomPlugin extends BasePlugin<ZoomPluginEvents, ZoomPluginOptions> {
// Update the accumulated delta...
this.accumulatedDelta += -e.deltaY

if (this.startZoom === 0 && this.options.exponentialZooming) {
this.startZoom = this.wavesurfer.getWrapper().clientWidth / this.wavesurfer.getDuration();
}

// ...and only scroll once we've hit our threshold
if (this.options.deltaThreshold === 0 || Math.abs(this.accumulatedDelta) >= this.options.deltaThreshold) {
const duration = this.wavesurfer.getDuration()
const oldMinPxPerSec = this.wavesurfer.options.minPxPerSec
const x = e.clientX
const oldMinPxPerSec =
this.wavesurfer.options.minPxPerSec === 0
? this.wavesurfer.getWrapper().scrollWidth / duration
: this.wavesurfer.options.minPxPerSec;
const x = e.clientX - this.container.getBoundingClientRect().left;
const width = this.container.clientWidth
const scrollX = this.wavesurfer.getScroll()
const pointerTime = (scrollX + x) / oldMinPxPerSec

// Update pointerTime only if the pointer position has changed. This prevents the waveform from drifting during fixed zooming.
if (x !== this.oldX || this.oldX === 0) {
this.pointerTime = (scrollX + x) / oldMinPxPerSec;
}
this.oldX = x;

const newMinPxPerSec = this.calculateNewZoom(oldMinPxPerSec, this.accumulatedDelta)
const newLeftSec = (width / newMinPxPerSec) * (x / width)

Expand All @@ -94,7 +143,7 @@ class ZoomPlugin extends BasePlugin<ZoomPluginEvents, ZoomPluginOptions> {
this.container.scrollLeft = 0
} else {
this.wavesurfer.zoom(newMinPxPerSec)
this.container.scrollLeft = (pointerTime - newLeftSec) * newMinPxPerSec
this.container.scrollLeft = (this.pointerTime - newLeftSec) * newMinPxPerSec
}

// Reset the accumulated delta
Expand All @@ -103,16 +152,27 @@ class ZoomPlugin extends BasePlugin<ZoomPluginEvents, ZoomPluginOptions> {
}

private calculateNewZoom = (oldZoom: number, delta: number) => {
const newZoom = Math.max(0, oldZoom + delta * this.options.scale)
return typeof this.options.maxZoom === 'undefined' ? newZoom : Math.min(newZoom, this.options.maxZoom)
let newZoom;
if (this.options.exponentialZooming) {
const zoomFactor =
delta > 0
? Math.pow(this.endZoom / this.startZoom, 1 / (this.options.iterations - 1))
: Math.pow(this.startZoom / this.endZoom, 1 / (this.options.iterations - 1));
newZoom = Math.max(0, oldZoom * zoomFactor);
} else {
// Default linear zooming
newZoom = Math.max(0, oldZoom + delta * this.options.scale)
}
return Math.min(newZoom, this.options.maxZoom!)
}

destroy() {
if (this.wrapper) {
this.wrapper.removeEventListener('wheel', this.onWheel)
}
document.removeEventListener('wheel', this.preventScroll)
super.destroy()
}
}

export default ZoomPlugin
export default ZoomPlugin

0 comments on commit 4332faf

Please sign in to comment.