mirror of
https://github.com/scratchfoundation/Gestouch.git
synced 2024-11-27 01:35:40 -05:00
Swipe gesture algorithm rewritten for better recognition and failing
This commit is contained in:
parent
9edcd04878
commit
7cdec34be4
1 changed files with 58 additions and 34 deletions
|
@ -6,7 +6,6 @@ package org.gestouch.gestures
|
||||||
|
|
||||||
import flash.display.InteractiveObject;
|
import flash.display.InteractiveObject;
|
||||||
import flash.geom.Point;
|
import flash.geom.Point;
|
||||||
import flash.system.Capabilities;
|
|
||||||
|
|
||||||
[Event(name="gestureSwipe", type="org.gestouch.events.SwipeGestureEvent")]
|
[Event(name="gestureSwipe", type="org.gestouch.events.SwipeGestureEvent")]
|
||||||
/**
|
/**
|
||||||
|
@ -17,16 +16,19 @@ package org.gestouch.gestures
|
||||||
*/
|
*/
|
||||||
public class SwipeGesture extends Gesture
|
public class SwipeGesture extends Gesture
|
||||||
{
|
{
|
||||||
|
public var slop:Number = Gesture.DEFAULT_SLOP;
|
||||||
public var numTouchesRequired:uint = 1;
|
public var numTouchesRequired:uint = 1;
|
||||||
public var velocityThreshold:Number = 0.1;
|
public var minVelocity:Number = 0.8;
|
||||||
public var minVelocity:Number = 1.5;
|
public var minOffset:Number = Gesture.DEFAULT_SLOP;
|
||||||
public var minDistance:Number = Capabilities.screenDPI * 0.5;
|
|
||||||
|
|
||||||
public var direction:uint = SwipeGestureDirection.ORTHOGONAL;
|
public var direction:uint = SwipeGestureDirection.ORTHOGONAL;
|
||||||
|
public var maxDirectionalOffset:Number = Gesture.DEFAULT_SLOP << 1;
|
||||||
|
|
||||||
protected var _offset:Point = new Point();
|
protected var _offset:Point = new Point();
|
||||||
protected var _startTime:int;
|
protected var _startTime:int;
|
||||||
protected var _noDirection:Boolean;
|
protected var _noDirection:Boolean;
|
||||||
|
protected var _avrgVel:Point = new Point();
|
||||||
|
protected var _prevAvrgVel:Point = new Point();
|
||||||
|
protected var _decelerationCounter:uint = 0;
|
||||||
|
|
||||||
|
|
||||||
public function SwipeGesture(target:InteractiveObject = null)
|
public function SwipeGesture(target:InteractiveObject = null)
|
||||||
|
@ -54,6 +56,7 @@ package org.gestouch.gestures
|
||||||
_startTime = 0;
|
_startTime = 0;
|
||||||
_offset.x = 0;
|
_offset.x = 0;
|
||||||
_offset.y = 0;
|
_offset.y = 0;
|
||||||
|
_decelerationCounter = 0;
|
||||||
|
|
||||||
super.reset();
|
super.reset();
|
||||||
}
|
}
|
||||||
|
@ -66,7 +69,7 @@ package org.gestouch.gestures
|
||||||
// Protected methods
|
// Protected methods
|
||||||
//
|
//
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
override protected function onTouchBegin(touch:Touch):void
|
override protected function onTouchBegin(touch:Touch):void
|
||||||
{
|
{
|
||||||
if (touchesCount > numTouchesRequired)
|
if (touchesCount > numTouchesRequired)
|
||||||
|
@ -84,6 +87,7 @@ package org.gestouch.gestures
|
||||||
if (touchesCount == numTouchesRequired)
|
if (touchesCount == numTouchesRequired)
|
||||||
{
|
{
|
||||||
updateLocation();
|
updateLocation();
|
||||||
|
_avrgVel.x = _avrgVel.y = 0;
|
||||||
|
|
||||||
// cache direction condition for performance
|
// cache direction condition for performance
|
||||||
_noDirection = (SwipeGestureDirection.ORTHOGONAL & direction) == 0;
|
_noDirection = (SwipeGestureDirection.ORTHOGONAL & direction) == 0;
|
||||||
|
@ -96,33 +100,46 @@ package org.gestouch.gestures
|
||||||
if (touchesCount < numTouchesRequired)
|
if (touchesCount < numTouchesRequired)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
var prevCentralPointX:Number = _centralPoint.x;
|
||||||
|
var prevCentralPointY:Number = _centralPoint.y;
|
||||||
updateCentralPoint();
|
updateCentralPoint();
|
||||||
|
|
||||||
_offset.x = _centralPoint.x - _location.x;
|
_offset.x = _centralPoint.x - _location.x;
|
||||||
_offset.y = _centralPoint.y - _location.y;
|
_offset.y = _centralPoint.y - _location.y;
|
||||||
var offsetLength:Number = _offset.length;
|
var offsetLength:Number = _offset.length;
|
||||||
var timeDelta:int = touch.time - _startTime;
|
|
||||||
var vel:Number = offsetLength / timeDelta;
|
if (offsetLength < slop)
|
||||||
var absVel:Number = vel > 0 ? vel : -vel;//faster Math.abs()
|
|
||||||
|
|
||||||
if (offsetLength < Gesture.DEFAULT_SLOP)
|
|
||||||
{
|
{
|
||||||
// no need in processing - we're in the very beginning of movement
|
// no need in processing - we're in the very beginning of movement
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (absVel < velocityThreshold)
|
|
||||||
|
// average velocity (total offset to total duration)
|
||||||
|
_prevAvrgVel.x = _avrgVel.x;
|
||||||
|
_prevAvrgVel.y = _avrgVel.y;
|
||||||
|
var absPrevAvrgVel:Number = _prevAvrgVel.length;
|
||||||
|
var totalTime:int = touch.time - _startTime;
|
||||||
|
_avrgVel.x = _offset.x / totalTime;
|
||||||
|
_avrgVel.y = _offset.y / totalTime;
|
||||||
|
var avrgVel:Number = _avrgVel.length;
|
||||||
|
|
||||||
|
|
||||||
|
if (avrgVel * 0.95 < absPrevAvrgVel)
|
||||||
|
{
|
||||||
|
_decelerationCounter++;
|
||||||
|
}
|
||||||
|
if (_decelerationCounter > 5 || avrgVel < 0.1)
|
||||||
{
|
{
|
||||||
setState(GestureState.FAILED);
|
setState(GestureState.FAILED);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var velX:Number = _offset.x / timeDelta;
|
|
||||||
var velY:Number = _offset.y / timeDelta;
|
|
||||||
|
|
||||||
|
|
||||||
if (_noDirection)
|
if (_noDirection)
|
||||||
{
|
{
|
||||||
if (absVel >= minVelocity || (minDistance != minDistance || offsetLength >= minDistance))
|
// We should quickly fail if we have noticable deceleration
|
||||||
|
// or first movement happend way later after touch
|
||||||
|
|
||||||
|
if (avrgVel >= minVelocity && (minOffset != minOffset || offsetLength >= minOffset))
|
||||||
{
|
{
|
||||||
if (setState(GestureState.RECOGNIZED) && hasEventListener(SwipeGestureEvent.GESTURE_SWIPE))
|
if (setState(GestureState.RECOGNIZED) && hasEventListener(SwipeGestureEvent.GESTURE_SWIPE))
|
||||||
{
|
{
|
||||||
|
@ -134,28 +151,30 @@ package org.gestouch.gestures
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
var recentOffsetX:Number = _centralPoint.x - prevCentralPointX;
|
||||||
|
var recentOffsetY:Number = _centralPoint.y - prevCentralPointY;
|
||||||
//faster Math.abs()
|
//faster Math.abs()
|
||||||
var absVelX:Number = velX > 0 ? velX : -velX;
|
var absVelX:Number = _avrgVel.x > 0 ? _avrgVel.x : -_avrgVel.x;
|
||||||
var absVelY:Number = velY > 0 ? velY : -velY;
|
var absVelY:Number = _avrgVel.y > 0 ? _avrgVel.y : -_avrgVel.y;
|
||||||
var absOffsetX:Number = _offset.x > 0 ? _offset.x : -_offset.x;
|
|
||||||
var absOffsetY:Number = _offset.y > 0 ? _offset.y : -_offset.y;
|
|
||||||
|
|
||||||
if (absVelX > absVelY)
|
if (absVelX > absVelY)
|
||||||
{
|
{
|
||||||
|
var absOffsetX:Number = _offset.x > 0 ? _offset.x : -_offset.x;
|
||||||
|
|
||||||
if ((SwipeGestureDirection.HORIZONTAL & direction) == 0)
|
if ((SwipeGestureDirection.HORIZONTAL & direction) == 0)
|
||||||
{
|
{
|
||||||
// horizontal velocity is greater then vertical, but we're not interested in any horizontal direction
|
// horizontal velocity is greater then vertical, but we're not interested in any horizontal direction
|
||||||
setState(GestureState.FAILED);
|
setState(GestureState.FAILED);
|
||||||
}
|
}
|
||||||
else if (velX < 0 && (direction & SwipeGestureDirection.LEFT) == 0)
|
else if (recentOffsetX < 0 && (direction & SwipeGestureDirection.LEFT) == 0 ||
|
||||||
|
recentOffsetX > 0 && (direction & SwipeGestureDirection.RIGHT) == 0 ||
|
||||||
|
Math.abs(_offset.y) > maxDirectionalOffset)
|
||||||
{
|
{
|
||||||
|
// movement in opposite direction
|
||||||
|
// or too much diagonally
|
||||||
setState(GestureState.FAILED);
|
setState(GestureState.FAILED);
|
||||||
}
|
}
|
||||||
else if (velX > 0 && (direction & SwipeGestureDirection.RIGHT) == 0)
|
else if (absVelX >= minVelocity && (minOffset != minOffset || absOffsetX >= minOffset))
|
||||||
{
|
|
||||||
setState(GestureState.FAILED);
|
|
||||||
}
|
|
||||||
else if (absVelX >= minVelocity || (minDistance != minDistance || absOffsetX >= minDistance))
|
|
||||||
{
|
{
|
||||||
if (setState(GestureState.RECOGNIZED) && hasEventListener(SwipeGestureEvent.GESTURE_SWIPE))
|
if (setState(GestureState.RECOGNIZED) && hasEventListener(SwipeGestureEvent.GESTURE_SWIPE))
|
||||||
{
|
{
|
||||||
|
@ -167,20 +186,22 @@ package org.gestouch.gestures
|
||||||
}
|
}
|
||||||
else if (absVelY > absVelX)
|
else if (absVelY > absVelX)
|
||||||
{
|
{
|
||||||
|
var absOffsetY:Number = _offset.y > 0 ? _offset.y : -_offset.y;
|
||||||
|
|
||||||
if ((SwipeGestureDirection.VERTICAL & direction) == 0)
|
if ((SwipeGestureDirection.VERTICAL & direction) == 0)
|
||||||
{
|
{
|
||||||
// horizontal velocity is greater then vertical, but we're not interested in any horizontal direction
|
// horizontal velocity is greater then vertical, but we're not interested in any horizontal direction
|
||||||
setState(GestureState.FAILED);
|
setState(GestureState.FAILED);
|
||||||
}
|
}
|
||||||
else if (velY < 0 && (direction & SwipeGestureDirection.UP) == 0)
|
else if (recentOffsetY < 0 && (direction & SwipeGestureDirection.UP) == 0 ||
|
||||||
|
recentOffsetY > 0 && (direction & SwipeGestureDirection.DOWN) == 0 ||
|
||||||
|
Math.abs(_offset.x) > maxDirectionalOffset)
|
||||||
{
|
{
|
||||||
|
// movement in opposite direction
|
||||||
|
// or too much diagonally
|
||||||
setState(GestureState.FAILED);
|
setState(GestureState.FAILED);
|
||||||
}
|
}
|
||||||
else if (velY > 0 && (direction & SwipeGestureDirection.DOWN) == 0)
|
else if (absVelY >= minVelocity && (minOffset != minOffset || absOffsetY >= minOffset))
|
||||||
{
|
|
||||||
setState(GestureState.FAILED);
|
|
||||||
}
|
|
||||||
else if (absVelY >= minVelocity || (minDistance != minDistance || absOffsetY >= minDistance))
|
|
||||||
{
|
{
|
||||||
if (setState(GestureState.RECOGNIZED) && hasEventListener(SwipeGestureEvent.GESTURE_SWIPE))
|
if (setState(GestureState.RECOGNIZED) && hasEventListener(SwipeGestureEvent.GESTURE_SWIPE))
|
||||||
{
|
{
|
||||||
|
@ -200,7 +221,10 @@ package org.gestouch.gestures
|
||||||
|
|
||||||
override protected function onTouchEnd(touch:Touch):void
|
override protected function onTouchEnd(touch:Touch):void
|
||||||
{
|
{
|
||||||
setState(GestureState.FAILED);
|
if (touchesCount < numTouchesRequired)
|
||||||
|
{
|
||||||
|
setState(GestureState.FAILED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue