Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F85824174
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Authored By
Unknown
Size
6 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/services/gesture_service/gesture_service.js b/src/services/gesture_service/gesture_service.js
index 2e39003c8c..efc0ca78f7 100644
--- a/src/services/gesture_service/gesture_service.js
+++ b/src/services/gesture_service/gesture_service.js
@@ -1,71 +1,74 @@
const DIRECTION_LEFT = [-1, 0]
const DIRECTION_RIGHT = [1, 0]
const DIRECTION_UP = [0, -1]
const DIRECTION_DOWN = [0, 1]
const deltaCoord = (oldCoord, newCoord) => [newCoord[0] - oldCoord[0], newCoord[1] - oldCoord[1]]
const touchEventCoord = e => ([e.touches[0].screenX, e.touches[0].screenY])
const vectorLength = v => Math.sqrt(v[0] * v[0] + v[1] * v[1])
-const perpendicular = v => [v[1], v[0]]
+const perpendicular = v => [v[1], -v[0]]
const dotProduct = (v1, v2) => v1[0] * v2[0] + v1[1] * v2[1]
-const vectorFlatten = (v1, v2) => [v1[0] * v2[0], v1[1] * v2[1]]
+const project = (v1, v2) => {
+ const scalar = (dotProduct(v1, v2) / dotProduct(v2, v2))
+ return [scalar * v2[0], scalar * v2[1]]
+}
// direction: either use the constants above or an arbitrary 2d vector.
// threshold: how many Px to move from touch origin before checking if the
// callback should be called.
// divergentTolerance: a scalr for much of divergent direction we tolerate when
// above threshold. for example, with 1.0 we only call the callback if
// divergent component of delta is < 1.0 * direction component of delta.
const swipeGesture = (direction, onSwipe, threshold = 30, perpendicularTolerance = 1.0) => {
return {
direction,
onSwipe,
threshold,
perpendicularTolerance,
_startPos: [0, 0],
_swiping: false
}
}
const beginSwipe = (event, gesture) => {
gesture._startPos = touchEventCoord(event)
gesture._swiping = true
}
const updateSwipe = (event, gesture) => {
if (!gesture._swiping) return
// movement too small
const delta = deltaCoord(gesture._startPos, touchEventCoord(event))
if (vectorLength(delta) < gesture.threshold) return
// movement is opposite from direction
if (dotProduct(delta, gesture.direction) < 0) return
// movement perpendicular to direction is too much
- const towardsDir = vectorFlatten(gesture.direction, delta)
+ const towardsDir = project(delta, gesture.direction)
const perpendicularDir = perpendicular(gesture.direction)
- const towardsPerpendicular = vectorFlatten(perpendicularDir, delta)
+ const towardsPerpendicular = project(delta, perpendicularDir)
if (
- vectorLength(towardsDir) <
- gesture.perpendicularTolerance * vectorLength(towardsPerpendicular)
+ vectorLength(towardsDir) * gesture.perpendicularTolerance <
+ vectorLength(towardsPerpendicular)
) return
gesture.onSwipe()
gesture._swiping = false
}
const GestureService = {
DIRECTION_LEFT,
DIRECTION_RIGHT,
DIRECTION_UP,
DIRECTION_DOWN,
swipeGesture,
beginSwipe,
updateSwipe
}
export default GestureService
diff --git a/test/unit/specs/services/gesture_service/gesture_service.spec.js b/test/unit/specs/services/gesture_service/gesture_service.spec.js
new file mode 100644
index 0000000000..4a1b009a25
--- /dev/null
+++ b/test/unit/specs/services/gesture_service/gesture_service.spec.js
@@ -0,0 +1,120 @@
+import GestureService from 'src/services/gesture_service/gesture_service.js'
+
+const mockTouchEvent = (x, y) => ({
+ touches: [
+ {
+ screenX: x,
+ screenY: y
+ }
+ ]
+})
+
+describe.only('GestureService', () => {
+ describe('swipeGesture', () => {
+ it('calls the callback on a successful swipe', () => {
+ let swiped = false
+ const callback = () => { swiped = true }
+ const gesture = GestureService.swipeGesture(
+ GestureService.DIRECTION_RIGHT,
+ callback
+ )
+
+ GestureService.beginSwipe(mockTouchEvent(100, 100), gesture)
+ GestureService.updateSwipe(mockTouchEvent(200, 100), gesture)
+
+ expect(swiped).to.eql(true)
+ })
+
+ it('calls the callback only once per begin', () => {
+ let hits = 0
+ const callback = () => { hits += 1 }
+ const gesture = GestureService.swipeGesture(
+ GestureService.DIRECTION_RIGHT,
+ callback
+ )
+
+ GestureService.beginSwipe(mockTouchEvent(100, 100), gesture)
+ GestureService.updateSwipe(mockTouchEvent(150, 100), gesture)
+ GestureService.updateSwipe(mockTouchEvent(200, 100), gesture)
+
+ expect(hits).to.eql(1)
+ })
+
+ it('doesn\'t call the callback on an opposite swipe', () => {
+ let swiped = false
+ const callback = () => { swiped = true }
+ const gesture = GestureService.swipeGesture(
+ GestureService.DIRECTION_RIGHT,
+ callback
+ )
+
+ GestureService.beginSwipe(mockTouchEvent(100, 100), gesture)
+ GestureService.updateSwipe(mockTouchEvent(0, 100), gesture)
+
+ expect(swiped).to.eql(false)
+ })
+
+ it('doesn\'t call the callback on a swipe below threshold', () => {
+ let swiped = false
+ const callback = () => { swiped = true }
+ const gesture = GestureService.swipeGesture(
+ GestureService.DIRECTION_RIGHT,
+ callback,
+ 100
+ )
+
+ GestureService.beginSwipe(mockTouchEvent(100, 100), gesture)
+ GestureService.updateSwipe(mockTouchEvent(150, 100), gesture)
+
+ expect(swiped).to.eql(false)
+ })
+
+ it('doesn\'t call the callback on a perpendicular swipe', () => {
+ let swiped = false
+ const callback = () => { swiped = true }
+ const gesture = GestureService.swipeGesture(
+ GestureService.DIRECTION_RIGHT,
+ callback,
+ 30,
+ 0.5
+ )
+
+ GestureService.beginSwipe(mockTouchEvent(100, 100), gesture)
+ GestureService.updateSwipe(mockTouchEvent(150, 200), gesture)
+
+ expect(swiped).to.eql(false)
+ })
+
+ it('calls the callback on perpendicular swipe if within tolerance', () => {
+ let swiped = false
+ const callback = () => { swiped = true }
+ const gesture = GestureService.swipeGesture(
+ GestureService.DIRECTION_RIGHT,
+ callback,
+ 30,
+ 2.0
+ )
+
+ GestureService.beginSwipe(mockTouchEvent(100, 100), gesture)
+ GestureService.updateSwipe(mockTouchEvent(150, 150), gesture)
+
+ expect(swiped).to.eql(true)
+ })
+
+ it('works with any arbitrary 2d directions', () => {
+ let swiped = false
+ const callback = () => { swiped = true }
+ const gesture = GestureService.swipeGesture(
+ [-1, -1],
+ callback,
+ 30,
+ 0.1
+ )
+
+ GestureService.beginSwipe(mockTouchEvent(100, 100), gesture)
+ GestureService.updateSwipe(mockTouchEvent(60, 60), gesture)
+
+ expect(swiped).to.eql(true)
+ })
+ })
+})
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Oct 29, 12:36 PM (1 d, 2 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1798098
Default Alt Text
(6 KB)
Attached To
Mode
rPUFE pleroma-fe-upstream
Attached
Detach File
Event Timeline