Swipe gestures

This commit is contained in:
Max Lynch
2013-08-26 19:09:06 -05:00
parent 90ea2fd684
commit 2db29fb35b
5 changed files with 234 additions and 10 deletions

View File

@ -16,6 +16,7 @@
<a href="#" class="button button-success">Swipe me!</a> <a href="#" class="button button-success">Swipe me!</a>
<div id="event-log"></div> <div id="event-log"></div>
</div> </div>
<script src="../../js/framework/framework-utils.js"></script>
<script src="../../js/framework/framework-gestures.js"></script> <script src="../../js/framework/framework-gestures.js"></script>
<script src="../../js/framework/framework-events.js"></script> <script src="../../js/framework/framework-events.js"></script>
<script src="events.js"></script> <script src="events.js"></script>

View File

@ -19,3 +19,51 @@ window.FM.on('touch', function(e) {
event: e event: e
}); });
}); });
window.FM.on('release', function(e) {
console.log('GOT RELEASE', e);
logEvent({
type: 'release',
event: e
});
});
window.FM.on('swipe', function(e) {
console.log('GOT SWIPE', e);
logEvent({
type: 'swipe',
event: e
});
e.target.classList.add('swipeleft');
});
window.FM.on('swiperight', function(e) {
console.log('GOT SWIPE RIGHT', e);
logEvent({
type: 'swiperight',
event: e
});
e.target.classList.add('swiperight');
});
window.FM.on('swipeleft', function(e) {
console.log('GOT SWIPE LEFT', e);
logEvent({
type: 'swipeleft',
event: e
});
e.target.classList.add('swipeleft');
});
window.FM.on('swipeup', function(e) {
console.log('GOT SWIPE UP', e);
logEvent({
type: 'swipeup',
event: e
});
});
window.FM.on('swipedown', function(e) {
console.log('GOT SWIPE DOWN', e);
logEvent({
type: 'swipedown',
event: e
});
});

View File

@ -53,7 +53,7 @@
*/ */
handleTouchStart: function(e) { handleTouchStart: function(e) {
console.log("EVENT: touchstart", e); console.log("EVENT: touchstart", e);
framework.GestureController.detectGesture(e); framework.GestureController.startGesture(e);
}, },
/** /**

View File

@ -2,7 +2,7 @@
* Simple gesture controllers with some common gestures that emit * Simple gesture controllers with some common gestures that emit
* gesture events. * gesture events.
* *
* Much adapted from github.com/EightMedia/Hammer.js * Much adapted from github.com/EightMedia/Hammer.js - thanks!
*/ */
(function(window, document, framework) { (function(window, document, framework) {
// Gesture support // Gesture support
@ -55,27 +55,180 @@
} }
}; };
// A swipe-left gesture that emits the 'swipeleft' event when a left swipe // The gesture is over, trigger a release event
// is performed framework.Gesture.Release = {
framework.Gesture.SwipeLeft = {
handle: function(e) { handle: function(e) {
if(e.type === 'touchend') {
framework.EventController.trigger('release', {
cancelable: true,
bubbles: true
});
}
} }
}; };
// A swipe gesture that emits the 'swipe' event when a left swipe happens
framework.Gesture.Swipe = {
swipe_velocity: 0.7,
handle: function(e) {
if(e.type == 'touchend') {
if(e.velocityX > this.swipe_velocity ||
e.velocityY > this.swipe_velocity) {
// trigger swipe events, both a general swipe,
// and a directional swipe
framework.EventController.trigger('swipe', {
gesture: e,
cancelable: true,
bubbles: true
});
framework.EventController.trigger('swipe' + e.direction, {
gesture: e,
cancelable: true,
bubbles: true
});
}
}
}
};
framework.GestureController = { framework.GestureController = {
gestures: [ gestures: [
framework.Gesture.Touch, framework.Gesture.Touch,
framework.Gesture.Tap framework.Gesture.Tap,
framework.Gesture.Swipe
], ],
_annotateGestureEvent: function(e) {
// If this doesn't have touches, we need to grab the last set that did
var touches = e.touches;
if((!touches || !touches.length) && this._lastMoveEvent) {
touches = this._lastMoveEvent.touches;
}
e.center = this.getCenter(touches);
var startEv = this.currentGesture.startEvent;
var delta_time = e.timeStamp - startEv.timeStamp;
var delta_x = e.center.pageX - startEv.center.pageX;
var delta_y = e.center.pageY - startEv.center.pageY;
var velocity = this.getVelocity(delta_time, delta_x, delta_y);
framework.Utils.extend(e, {
touches : touches,
deltaTime : delta_time,
deltaX : delta_x,
deltaY : delta_y,
velocityX : velocity.x,
velocityY : velocity.y,
distance : this.getDistance(startEv.center, e.center),
angle : this.getAngle(startEv.center, e.center),
//interimAngle : this.current.lastEvent && Hammer.utils.getAngle(this.current.lastEvent.center, e.center),
direction : this.getDirection(startEv.center, e.center),
//interimDirection: this.current.lastEvent && Hammer.utils.getDirection(this.current.lastEvent.center, e.center),
scale : this.getScale(startEv.touches, touches),
rotation : this.getRotation(startEv.touches, touches),
startEvent : startEv
});
return e;
},
_getFakeEvent: function(e) {
return {
center : this.getCenter(e.touches),
timeStamp : new Date().getTime(),
target : e.target,
touches : e.touches,
eventType : e.type,
srcEvent : e,
/*
// prevent the browser default actions
// mostly used to disable scrolling of the browser
preventDefault: function() {
if(this.srcEvent.preventManipulation) {
this.srcEvent.preventManipulation();
}
if(this.srcEvent.preventDefault) {
this.srcEvent.preventDefault();
}
},
*/
/**
* stop bubbling the event up to its parents
*/
stopPropagation: function() {
this.srcEvent.stopPropagation();
},
//immediately stop gesture detection
//might be useful after a swipe was detected
//@return {*}
stopDetect: function() {
return Hammer.detection.stopDetect();
}
};
},
startGesture: function(e) {
console.log('START GESTURE');
// We only want to process one gesture at a time
if(this.currentGesture) {
return;
}
e = this._getFakeEvent(e);
this.currentGesture = e;
this.currentGesture.startEvent = framework.Utils.extend({}, e);
if((e.touches && e.touches.length) || !this._lastMoveEvent) {
this._lastMoveEvent = e;
}
this.detectGesture(e);
},
detectGesture: function(e) { detectGesture: function(e) {
var i; var i;
if(e.touches && e.touches.length) {
this._lastMoveEvent = e;
}
var eventData = this._annotateGestureEvent(e);
console.log("Event velocity:", eventData.velocityX, eventData.velocityY);
for(i = 0; i < this.gestures.length; i++) { for(i = 0; i < this.gestures.length; i++) {
if(this.gestures[i].handle(e)) { if(this.gestures[i].handle(eventData) == false) {
console.log('GESTURECONTROLLER: Gesture handled'); console.log('GESTURECONTROLLER: Gesture handled and stopped.');
this.endGesture(eventData);
return; return;
} }
} }
if(this.currentGesture) {
// Store this event so we can access it again later
this.currentGesture.lastEvent = eventData;
}
// It's over!
if(e.type === 'touchend' || e.type === 'touchcancel') {
this.endGesture(eventData);
}
},
endGesture: function(e) {
this.currentGesture = null;
this._lastMoveEvent = null;
}, },
/** /**
@ -155,10 +308,10 @@
y = Math.abs(touch1.pageY - touch2.pageY); y = Math.abs(touch1.pageY - touch2.pageY);
if(x >= y) { if(x >= y) {
return touch1.pageX - touch2.pageX > 0 ? Hammer.DIRECTION_LEFT : Hammer.DIRECTION_RIGHT; return touch1.pageX - touch2.pageX > 0 ? 'left' : 'right';
} }
else { else {
return touch1.pageY - touch2.pageY > 0 ? Hammer.DIRECTION_UP : Hammer.DIRECTION_DOWN; return touch1.pageY - touch2.pageY > 0 ? 'up': 'down';
} }
}, },

View File

@ -0,0 +1,22 @@
(function(window, document, framework) {
framework.Utils = {
/**
* extend method,
* also used for cloning when dest is an empty object
* @param {Object} dest
* @param {Object} src
* @parm {Boolean} merge do a merge
* @returns {Object} dest
*/
extend: function extend(dest, src, merge) {
for (var key in src) {
if(dest[key] !== undefined && merge) {
continue;
}
dest[key] = src[key];
}
return dest;
},
}
})(this, document, FM = this.FM || {});