From b30563483960145b3fe2521ba4d27b00c5eced6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=B6=E8=BE=89?= <35290158+HoodyHuo@users.noreply.github.com> Date: Wed, 18 Oct 2023 22:46:56 +0800 Subject: [PATCH] feat add ZoomPlugin (#3276) * feat add ZoomPlugin * review comment resolved * add mouse wheel event prevent and zoom plugin example --- examples/zoom-plugin.js | 73 ++++++++++++++++++++++++++++++++++ index.html | 1 + src/plugins/zoom.ts | 86 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 160 insertions(+) create mode 100644 examples/zoom-plugin.js create mode 100644 src/plugins/zoom.ts diff --git a/examples/zoom-plugin.js b/examples/zoom-plugin.js new file mode 100644 index 000000000..d203e35fb --- /dev/null +++ b/examples/zoom-plugin.js @@ -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 +/* + +
+ minPxPerSec: 100 px/s +
+ +
+ + * + */ + + + + +// A few more controls +/* + + + + +

+ 📖 Zoom in or out on the waveform when scrolling the mouse wheel +

+ +*/ + +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) +} diff --git a/index.html b/index.html index 3a613155b..59d906b29 100644 --- a/index.html +++ b/index.html @@ -138,6 +138,7 @@

wavesurfer.js examples

  • Options
  • Events
  • Zoom
  • +
  • Zoom Plugin
  • Regions
  • Hover
  • Timeline
  • diff --git a/src/plugins/zoom.ts b/src/plugins/zoom.ts new file mode 100644 index 000000000..4655e915e --- /dev/null +++ b/src/plugins/zoom.ts @@ -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 { + 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