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