Files
svelte-carousel/src/actions/swipeable/swipeable.js
2021-08-08 11:59:39 +03:00

93 lines
2.3 KiB
JavaScript

import { NEXT, PREV } from '../../direction'
import {
addStartEventListener,
removeStartEventListener,
addMoveEventListener,
removeMoveEventListener,
addEndEventListener,
removeEndEventListener,
} from './event'
import { createDispatcher } from '../../utils/event'
import { SWIPE_MIN_DURATION_MS, SWIPE_MIN_DISTANCE_PX } from '../../units'
function getCoords(event) {
if ('TouchEvent' in window && event instanceof TouchEvent) {
const touch = event.touches[0]
return {
x: touch ? touch.clientX : 0,
y: touch ? touch.clientY : 0,
}
}
return {
x: event.clientX,
y: event.clientY,
}
}
export function swipeable(node, { thresholdProvider }) {
const dispatch = createDispatcher(node)
let x
let y
let moved = 0
let swipeStartedAt
let isTouching = false
function isValidSwipe() {
const swipeDurationMs = Date.now() - swipeStartedAt
return swipeDurationMs >= SWIPE_MIN_DURATION_MS && Math.abs(moved) >= SWIPE_MIN_DISTANCE_PX
}
function handleDown(event) {
swipeStartedAt = Date.now()
moved = 0
isTouching = true
const coords = getCoords(event)
x = coords.x
y = coords.y
dispatch('swipeStart', { x, y })
addMoveEventListener(window, handleMove)
addEndEventListener(window, handleUp)
}
function handleMove(event) {
if (!isTouching) return
const coords = getCoords(event)
const dx = coords.x - x
const dy = coords.y - y
x = coords.x
y = coords.y
dispatch('swipeMove', { x, y, dx, dy })
if (dx !== 0 && Math.sign(dx) !== Math.sign(moved)) {
moved = 0
}
moved += dx
if (Math.abs(moved) > thresholdProvider()) {
dispatch('swipeThresholdReached', { direction: moved > 0 ? PREV : NEXT })
removeEndEventListener(window, handleUp)
removeMoveEventListener(window, handleMove)
}
}
function handleUp(event) {
removeEndEventListener(window, handleUp)
removeMoveEventListener(window, handleMove)
isTouching = false
if (!isValidSwipe()) {
dispatch('swipeFailed')
return
}
const coords = getCoords(event)
dispatch('swipeEnd', { x: coords.x, y: coords.y })
}
addStartEventListener(node, handleDown)
return {
destroy() {
removeStartEventListener(node, handleDown)
},
}
}