Skip to content

Commit

Permalink
feat add ZoomPlugin (#3276)
Browse files Browse the repository at this point in the history
* feat add ZoomPlugin

* review comment resolved

* add mouse wheel event prevent and zoom plugin example
  • Loading branch information
HoodyHuo authored Oct 18, 2023
1 parent 9b624fb commit b305634
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 0 deletions.
73 changes: 73 additions & 0 deletions examples/zoom-plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/**
* Zoom plugin
*
* Zoom in or out on the waveform when scrolling the mouse wheel
*/

import WaveSurfer from 'https://unpkg.com/wavesurfer.js@7/dist/wavesurfer.esm.js'
import ZoomPlugin from 'https://unpkg.com/wavesurfer.js@7/dist/plugins/zoom.esm.js'

// Create an instance of WaveSurfer
const wavesurfer = WaveSurfer.create({
container: '#waveform',
waveColor: 'rgb(200, 0, 200)',
progressColor: 'rgb(100, 0, 100)',
url: '/examples/audio/audio.wav',
minPxPerSec: 100,
})

// Initialize the Zoom plugin
wavesurfer.registerPlugin(ZoomPlugin.create({
// the amount of zoom per wheel step, e.g. 0.1 means a 10% magnification per scroll
scale : 0.2
}))

// show the current minPxPerSec value
const minPxPerSecSpan = document.querySelector('#minPxPerSec')
wavesurfer.on('zoom', (minPxPerSec) => {
minPxPerSecSpan.textContent = `${Math.round(minPxPerSec)}`
})

// Create a minPxPerSec display and waveform container
/*
<html>
<div>
minPxPerSec: <span id="minPxPerSec">100</span> px/s
</div>
<div id="waveform"></div>
</html>
*
*/




// A few more controls
/*
<html>
<button id="play">Play/Pause</button>
<button id="backward">Backward 5s</button>
<button id="forward">Forward 5s</button>
<p>
📖 Zoom in or out on the waveform when scrolling the mouse wheel
</p>
</html>
*/

const playButton = document.querySelector('#play')
const forwardButton = document.querySelector('#forward')
const backButton = document.querySelector('#backward')


playButton.onclick = () => {
wavesurfer.playPause()
}

forwardButton.onclick = () => {
wavesurfer.skip(5)
}

backButton.onclick = () => {
wavesurfer.skip(-5)
}
1 change: 1 addition & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ <h1>wavesurfer.js examples</h1>
<li><a href="#all-options.js">Options</a></li>
<li><a href="#events.js">Events</a></li>
<li><a href="#zoom.js">Zoom</a></li>
<li><a href="#zoom-plugin.js">Zoom Plugin</a></li>
<li><a href="#regions.js">Regions</a></li>
<li><a href="#hover.js">Hover</a></li>
<li><a href="#timeline.js">Timeline</a></li>
Expand Down
86 changes: 86 additions & 0 deletions src/plugins/zoom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/**
* Zoom plugin
*
* Zoom in or out on the waveform when scrolling the mouse wheel
*
* @author HoodyHuo (https://github.com/HoodyHuo)
*
* @example
* // ... initialising wavesurfer with the plugin
* var wavesurfer = WaveSurfer.create({
* // wavesurfer options ...
* plugins: [
* ZoomPlugin.create({
* // plugin options ...
* })
* ]
* });
*/

import { BasePlugin, BasePluginEvents } from '../base-plugin.js'

export type ZoomPluginOptions = {
scale?: number // the amount of zoom per wheel step, e.g. 0.1 means a 10% magnification per scroll
}
const defaultOptions = {
scale: 0.2,
}

export type ZoomPluginEvents = BasePluginEvents

class ZoomPlugin extends BasePlugin<ZoomPluginEvents, ZoomPluginOptions> {
protected options: ZoomPluginOptions & typeof defaultOptions
private wrapper: HTMLElement | undefined = undefined
private container: HTMLElement | null = null

constructor(options?: ZoomPluginOptions) {
super(options || {})
this.options = Object.assign({}, defaultOptions, options)
}

public static create(options?: ZoomPluginOptions) {
return new ZoomPlugin(options)
}

onInit() {
this.wrapper = this.wavesurfer?.getWrapper()
if (!this.wrapper) {
return
}
this.container = this.wrapper.parentElement as HTMLElement
this.wrapper.addEventListener('wheel', this.onWheel)
}

private onWheel = (e: WheelEvent) => {
if (!this.wavesurfer?.options.minPxPerSec || !this.container) {
return
}
// prevent scrolling the sidebar while zooming
e.preventDefault()

const duration = this.wavesurfer.getDuration()
const oldMinPxPerSec = this.wavesurfer.options.minPxPerSec
const x = e.clientX
const width = this.container.clientWidth
const scrollX = this.wavesurfer.getScroll()
const pointerTime = (scrollX + x) / oldMinPxPerSec
const newMinPxPerSec = oldMinPxPerSec * (e.deltaY > 0 ? 1 - this.options.scale : 1 + this.options.scale)
const newLeftSec = (width / newMinPxPerSec) * (x / width)
if (newMinPxPerSec * duration < width) {
this.wavesurfer.zoom(width / duration)
this.container.scrollLeft = 0
} else {
this.wavesurfer.zoom(newMinPxPerSec)
this.container.scrollLeft = (pointerTime - newLeftSec) * newMinPxPerSec
}
}

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

export default ZoomPlugin

0 comments on commit b305634

Please sign in to comment.