Skip to content

Commit

Permalink
Fix: draggable touch delay (#3616)
Browse files Browse the repository at this point in the history
* Refactor: draggable touch delay

* Restore cli-path
  • Loading branch information
katspaugh authored Mar 31, 2024
1 parent 5d71c4b commit 74308ba
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 72 deletions.
152 changes: 81 additions & 71 deletions src/draggable.ts
Original file line number Diff line number Diff line change
@@ -1,105 +1,115 @@
export function makeDraggable(
element: HTMLElement | null,
element: HTMLElement,
onDrag: (dx: number, dy: number, x: number, y: number) => void,
onStart?: (x: number, y: number) => void,
onEnd?: (x: number, y: number) => void,
threshold = 3,
mouseButton = 0,
): () => void {
touchDelay = 100,
) {
if (!element) return () => void 0

let unsubscribeDocument = () => void 0

const onPointerDown = (event: PointerEvent) => {
if (event.button !== mouseButton) return
let isPointerDown = false
let isDragging = false
let startX = 0
let startY = 0
let touchStart = 0
let rect: DOMRect
const isTouchDevice = matchMedia('(pointer: coarse)').matches

const onPointerDown = (e: PointerEvent) => {
if (e.button !== mouseButton) return
e.stopPropagation()

isPointerDown = true
isDragging = false
touchStart = Date.now()
rect = element.getBoundingClientRect()
startX = e.clientX - rect.left
startY = e.clientY - rect.top
}

event.preventDefault()
event.stopPropagation()
const onPointerUp = (e: PointerEvent) => {
isPointerDown = false
touchStart = 0

let startX = event.clientX
let startY = event.clientY
let isDragging = false
if (isDragging) {
e.preventDefault()
e.stopPropagation()

const onPointerMove = (event: PointerEvent) => {
event.preventDefault()
event.stopPropagation()
setTimeout(() => {
isDragging = false
}, 300)

const x = event.clientX
const y = event.clientY
const dx = x - startX
const dy = y - startY
const x = e.clientX - rect.left
const y = e.clientY - rect.top
onEnd?.(x, y)
}
}

if (isDragging || Math.abs(dx) > threshold || Math.abs(dy) > threshold) {
const rect = element.getBoundingClientRect()
const { left, top } = rect
const onPointerMove = (e: PointerEvent) => {
if (!isPointerDown) return
if (isTouchDevice && Date.now() - touchStart < touchDelay) return

if (!isDragging) {
onStart?.(startX - left, startY - top)
isDragging = true
}
e.preventDefault()
e.stopPropagation()

onDrag(dx, dy, x - left, y - top)
const x = e.clientX - rect.left
const y = e.clientY - rect.top
const dx = x - startX
const dy = y - startY

startX = x
startY = y
if (isDragging || Math.abs(dx) > threshold || Math.abs(dy) > threshold) {
if (!isDragging) {
onStart?.(startX, startY)
isDragging = true
}
}

const onPointerUp = (event: PointerEvent) => {
if (isDragging) {
const x = event.clientX
const y = event.clientY
const rect = element.getBoundingClientRect()
const { left, top } = rect

onEnd?.(x - left, y - top)
}
unsubscribeDocument()
}
onDrag(dx, dy, x, y)

const onPointerLeave = (e: PointerEvent) => {
// Listen to events only on the document and not on inner elements
if (!e.relatedTarget || e.relatedTarget === document.documentElement) {
onPointerUp(e)
}
startX = x
startY = y
}
}

const onClick = (event: MouseEvent) => {
if (isDragging) {
event.stopPropagation()
event.preventDefault()
}
const onPointerLeave = (e: PointerEvent) => {
// Listen to events only on the document and not on inner elements
if (!e.relatedTarget || e.relatedTarget === document.documentElement) {
onPointerUp(e)
}
}

const onTouchMove = (event: TouchEvent) => {
if (isDragging) {
event.preventDefault()
}
const onTouchMove = (e: TouchEvent) => {
if (isDragging) {
e.preventDefault()
}
}

document.addEventListener('pointermove', onPointerMove)
document.addEventListener('pointerup', onPointerUp)
document.addEventListener('pointerout', onPointerLeave)
document.addEventListener('pointercancel', onPointerLeave)
document.addEventListener('touchmove', onTouchMove, { passive: false })
document.addEventListener('click', onClick, { capture: true })

unsubscribeDocument = () => {
document.removeEventListener('pointermove', onPointerMove)
document.removeEventListener('pointerup', onPointerUp)
document.removeEventListener('pointerout', onPointerLeave)
document.removeEventListener('pointercancel', onPointerLeave)
document.removeEventListener('touchmove', onTouchMove)
setTimeout(() => {
document.removeEventListener('click', onClick, { capture: true })
}, 10)
// Prevent clicks after dragging
const onClick = (e: MouseEvent) => {
if (isDragging) {
e.stopPropagation()
e.preventDefault()
}
}

element.addEventListener('pointerdown', onPointerDown)
element.addEventListener('click', onClick, true)
document.addEventListener('click', onClick, true)
document.addEventListener('pointermove', onPointerMove)
document.addEventListener('touchmove', onTouchMove, { passive: false })
document.addEventListener('pointerup', onPointerUp)
document.addEventListener('pointerleave', onPointerLeave)
document.addEventListener('pointercancel', onPointerUp)

return () => {
unsubscribeDocument()
element.removeEventListener('pointerdown', onPointerDown)
element.removeEventListener('click', onClick, true)
document.removeEventListener('click', onClick, true)
document.removeEventListener('pointermove', onPointerMove)
document.removeEventListener('touchmove', onTouchMove)
document.removeEventListener('pointerup', onPointerUp)
document.removeEventListener('pointerleave', onPointerLeave)
document.removeEventListener('pointercancel', onPointerUp)
}
}
2 changes: 1 addition & 1 deletion src/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -709,7 +709,7 @@ class Renderer extends EventEmitter<RendererEvents> {
renderProgress(progress: number, isPlaying?: boolean) {
if (isNaN(progress)) return
const percents = progress * 100
//this.canvasWrapper.style.clipPath = `polygon(${percents}% 0, 100% 0, 100% 100%, ${percents}% 100%)`
this.canvasWrapper.style.clipPath = `polygon(${percents}% 0, 100% 0, 100% 100%, ${percents}% 100%)`
this.progressWrapper.style.width = `${percents}%`
this.cursor.style.left = `${percents}%`
this.cursor.style.transform = `translateX(-${Math.round(percents) === 100 ? this.options.cursorWidth : 0}px)`
Expand Down

0 comments on commit 74308ba

Please sign in to comment.