Make media modal be aware of multi-touch actions

Originally the media viewer would think every touch is a swipe (one-finger
touch event), so we would encounter the case where a two-finger scale event
would incorrectly change the current media. This is now fixed.
This commit is contained in:
Tusooa Zhu 2021-08-01 13:39:56 -04:00
parent 51b14cc615
commit f96e5882d1
No known key found for this signature in database
GPG key ID: 7B467EDE43A08224
3 changed files with 93 additions and 16 deletions

View file

@ -4,9 +4,17 @@ const DIRECTION_RIGHT = [1, 0]
const DIRECTION_UP = [0, -1]
const DIRECTION_DOWN = [0, 1]
const isSwipeEvent = e => (e.touches.length === 1)
const isSwipeEventEnd = e => (e.changedTouches.length === 1)
const isScaleEvent = e => (e.targetTouches.length === 2)
// const isScaleEventEnd = e => (e.changedTouches.length === 2)
const deltaCoord = (oldCoord, newCoord) => [newCoord[0] - oldCoord[0], newCoord[1] - oldCoord[1]]
const touchEventCoord = e => ([e.touches[0].screenX, e.touches[0].screenY])
const touchCoord = touch => [touch.screenX, touch.screenY]
const touchEventCoord = e => touchCoord(e.touches[0])
const vectorLength = v => Math.sqrt(v[0] * v[0] + v[1] * v[1])
@ -61,6 +69,76 @@ const updateSwipe = (event, gesture) => {
gesture._swiping = false
}
class SwipeAndScaleGesture {
constructor ({
direction, callbackPositive, callbackNegative,
previewCallback, threshold = 30, perpendicularTolerance = 1.0
}) {
this.direction = direction
this.previewCallback = previewCallback
this.callbackPositive = callbackPositive
this.callbackNegative = callbackNegative
this.threshold = threshold
this.perpendicularTolerance = perpendicularTolerance
this._startPos = [0, 0]
this._swiping = false
}
start (event) {
console.log('start() called', event)
if (isSwipeEvent(event)) {
this._startPos = touchEventCoord(event)
console.log('start pos:', this._startPos)
this._swiping = true
} else if (isScaleEvent(event)) {
this._scalePoints = [...event.targetTouches]
this._swiping = false
}
}
move (event) {
if (isScaleEvent(event)) {
}
}
end (event) {
console.log('end() called', event)
if (!isSwipeEventEnd(event)) {
console.log('not swipe event')
return
}
if (!this._swiping) {
console.log('not swiping')
return
}
this.swiping = false
console.log('is swipe event')
// movement too small
const touch = event.changedTouches[0]
const delta = deltaCoord(this._startPos, touchCoord(touch))
if (vectorLength(delta) < this.threshold) return
// movement is opposite from direction
const isPositive = dotProduct(delta, this.direction) > 0
// movement perpendicular to direction is too much
const towardsDir = project(delta, this.direction)
const perpendicularDir = perpendicular(this.direction)
const towardsPerpendicular = project(delta, perpendicularDir)
if (
vectorLength(towardsDir) * this.perpendicularTolerance <
vectorLength(towardsPerpendicular)
) return
if (isPositive) {
this.callbackPositive()
} else {
this.callbackNegative()
}
}
}
const GestureService = {
DIRECTION_LEFT,
DIRECTION_RIGHT,
@ -68,7 +146,8 @@ const GestureService = {
DIRECTION_DOWN,
swipeGesture,
beginSwipe,
updateSwipe
updateSwipe,
SwipeAndScaleGesture
}
export default GestureService