Files
ArtPlayer/packages/artplayer/src/input/gesture-controller.ts
T

95 lines
3.3 KiB
TypeScript

import type { Drag, GestureHost } from './gesture-types'
import { setCurrentTime } from '../control/progress/position'
import { getScope, isClosing } from '../lifecycle/instance'
import { captureSource } from '../source/operation'
import { clamp, secondToTime } from '../utils'
import { slideDirection } from './gesture-direction'
export function gestureController(art: GestureHost) {
let drag: Drag | undefined
const cancel = () => {
drag = undefined
}
const active = (current: Drag) => drag === current && !isClosing(art) && !art.isLock
&& !art.option.isLive && art.isRotate === current.rotated && current.sourceActive()
const onLock = (locked: boolean) => {
if (locked)
cancel()
}
art.on('document:touchend', cancel)
art.on('document:touchcancel', cancel)
art.on('lock', onLock)
getScope(art).add(() => {
cancel()
art.off('document:touchend', cancel)
art.off('document:touchcancel', cancel)
art.off('lock', onLock)
})
const start = (target: EventTarget, event: TouchEvent) => {
cancel()
const touch = event.touches[0]
if (isClosing(art) || art.isLock || art.option.isLive || event.touches.length !== 1 || !touch)
return
if (![touch.pageX, touch.pageY, touch.clientX, touch.clientY, art.currentTime].every(Number.isFinite))
return
const current: Drag = {
target,
identifier: touch.identifier,
x: touch.pageX,
y: touch.pageY,
time: art.currentTime,
rotated: art.isRotate,
sourceActive: captureSource(art),
}
drag = current
if (target === art.template.$progress) {
const size = art.isRotate ? art.height : art.template.$progress.clientWidth
if (!Number.isFinite(size) || size <= 0 || !Number.isFinite(art.duration) || art.duration <= 0) {
cancel()
return
}
try {
setCurrentTime(art, event, () => active(current))
}
catch (error) {
if (drag === current)
cancel()
throw error
}
if (active(current))
current.time = art.currentTime
}
}
const move = (event: TouchEvent) => {
const current = drag
const touch = event.touches[0]
if (!current)
return
if (!active(current) || event.touches.length !== 1 || !touch || touch.identifier !== current.identifier) {
cancel()
return
}
const size = current.rotated ? art.height : art.width
const multiplier = current.target === art.template.$video ? art.constructor.TOUCH_MOVE_RATIO : 1
if (![touch.pageX, touch.pageY, size, art.duration, multiplier].every(Number.isFinite) || size <= 0 || art.duration <= 0) {
cancel()
return
}
const direction = slideDirection(current.x, current.y, touch.pageX, touch.pageY)
if (!(current.rotated ? direction === 1 || direction === 2 : direction === 3 || direction === 4))
return
const distance = current.rotated ? touch.pageY - current.y : touch.pageX - current.x
const ratio = clamp(distance / size, -1, 1)
const time = clamp(current.time + art.duration * ratio * multiplier, 0, art.duration)
art.seek = time
if (!active(current))
return
art.emit('setBar', 'played', clamp(time / art.duration, 0, 1), event)
if (active(current))
art.notice.show = `${secondToTime(time)} / ${secondToTime(art.duration)}`
}
return { start, move, cancel }
}