From 50239b41db13f675421c35eaa58fc9d801ce86d2 Mon Sep 17 00:00:00 2001
From: Brian Byassee <brianbyassee@brians-mbp-2.lan>
Date: Wed, 21 Feb 2024 17:51:02 -0700
Subject: [PATCH] Feat: dragstart and dragend events for drag to seek

---
 src/draggable.ts  | 13 +++++++++----
 src/renderer.ts   | 14 +++++++++++---
 src/wavesurfer.ts | 14 ++++++++++++++
 3 files changed, 34 insertions(+), 7 deletions(-)

diff --git a/src/draggable.ts b/src/draggable.ts
index 0f8c0feaa..b37840a10 100644
--- a/src/draggable.ts
+++ b/src/draggable.ts
@@ -2,7 +2,7 @@ export function makeDraggable(
   element: HTMLElement | null,
   onDrag: (dx: number, dy: number, x: number, y: number) => void,
   onStart?: (x: number, y: number) => void,
-  onEnd?: () => void,
+  onEnd?: (x: number, y: number) => void,
   threshold = 3,
   mouseButton = 0,
 ): () => void {
@@ -45,9 +45,14 @@ export function makeDraggable(
       }
     }
 
-    const onPointerUp = () => {
+    const onPointerUp = (event: PointerEvent) => {
       if (isDragging) {
-        onEnd?.()
+        const x = event.clientX
+        const y = event.clientY
+        const rect = element.getBoundingClientRect()
+        const { left, top } = rect
+
+        onEnd?.(x - left, y - top)
       }
       unsubscribeDocument()
     }
@@ -55,7 +60,7 @@ export function makeDraggable(
     const onPointerLeave = (e: PointerEvent) => {
       // Listen to events only on the document and not on inner elements
       if (!e.relatedTarget || e.relatedTarget === document.documentElement) {
-        onPointerUp()
+        onPointerUp(e)
       }
     }
 
diff --git a/src/renderer.ts b/src/renderer.ts
index 3e684d29d..c1ce5a674 100644
--- a/src/renderer.ts
+++ b/src/renderer.ts
@@ -6,6 +6,8 @@ type RendererEvents = {
   click: [relativeX: number, relativeY: number]
   dblclick: [relativeX: number, relativeY: number]
   drag: [relativeX: number]
+  dragstart: [relativeX: number]
+  dragend: [relativeX: number]
   scroll: [relativeStart: number, relativeEnd: number]
   render: []
   rendered: []
@@ -127,9 +129,15 @@ class Renderer extends EventEmitter<RendererEvents> {
         this.emit('drag', Math.max(0, Math.min(1, x / this.wrapper.getBoundingClientRect().width)))
       },
       // On start drag
-      () => (this.isDragging = true),
+      (x) => {
+        this.isDragging = true
+        this.emit('dragstart', Math.max(0, Math.min(1, x / this.wrapper.getBoundingClientRect().width)))
+      },
       // On end drag
-      () => (this.isDragging = false),
+      (x) => {
+        this.isDragging = false
+        this.emit('dragend', Math.max(0, Math.min(1, x / this.wrapper.getBoundingClientRect().width)))
+      },
     )
   }
 
@@ -255,7 +263,7 @@ class Renderer extends EventEmitter<RendererEvents> {
 
   setScrollPercentage(percent: number) {
     const { scrollWidth } = this.scrollContainer
-    const scrollStart =  scrollWidth * percent
+    const scrollStart = scrollWidth * percent
     this.setScroll(scrollStart)
   }
 
diff --git a/src/wavesurfer.ts b/src/wavesurfer.ts
index 407a81a19..fec658eaf 100644
--- a/src/wavesurfer.ts
+++ b/src/wavesurfer.ts
@@ -124,6 +124,10 @@ export type WaveSurferEvents = {
   dblclick: [relativeX: number, relativeY: number]
   /** When the user drags the cursor */
   drag: [relativeX: number]
+  /** When the user starts dragging the cursor */
+  dragstart: [relativeX: number]
+  /** When the user ends dragging the cursor */
+  dragend: [relativeX: number]
   /** When the waveform is scrolled (panned) */
   scroll: [visibleStartTime: number, visibleEndTime: number]
   /** When the zoom level changes */
@@ -271,6 +275,16 @@ class WaveSurfer extends Player<WaveSurferEvents> {
       this.renderer.on('rendered', () => {
         this.emit('redrawcomplete')
       }),
+
+      // DragStart
+      this.renderer.on('dragstart', (relativeX) => {
+        this.emit('dragstart', relativeX)
+      }),
+
+      // DragEnd
+      this.renderer.on('dragend', (relativeX) => {
+        this.emit('dragend', relativeX)
+      }),
     )
 
     // Drag