221 lines
5.9 KiB
JavaScript
221 lines
5.9 KiB
JavaScript
(function(window, angular, undefined) {
|
|
|
|
'use strict';
|
|
|
|
/* global -ngSwipe */
|
|
|
|
var ngSwipe = angular.module('swipe', []);
|
|
|
|
ngSwipe.factory('swipe', [ function() {
|
|
|
|
var MOVE_BUFFER_RADIUS = 40;
|
|
var MAX_RATIO = 0.3;
|
|
|
|
var POINTER_EVENTS = {
|
|
'mouse': {
|
|
start: 'mousedown',
|
|
move: 'mousemove',
|
|
end: 'mouseup'
|
|
},
|
|
'touch': {
|
|
start: 'touchstart',
|
|
move: 'touchmove',
|
|
end: 'touchend',
|
|
cancel: 'touchcancel'
|
|
}
|
|
};
|
|
|
|
function getCoordinates(event) {
|
|
var originalEvent = event.originalEvent || event;
|
|
var touches = originalEvent.touches && originalEvent.touches.length ? originalEvent.touches : [originalEvent];
|
|
var e = (originalEvent.changedTouches && originalEvent.changedTouches[0]) || touches[0];
|
|
|
|
return {
|
|
x: e.clientX,
|
|
y: e.clientY
|
|
};
|
|
}
|
|
|
|
function getEvents(pointerTypes, eventType) {
|
|
var res = [];
|
|
angular.forEach(pointerTypes, function(pointerType) {
|
|
var eventName = POINTER_EVENTS[pointerType][eventType];
|
|
if (eventName) {
|
|
res.push(eventName);
|
|
}
|
|
});
|
|
return res.join(' ');
|
|
}
|
|
|
|
return {
|
|
|
|
bind: function(element, eventHandlers, pointerTypes) {
|
|
|
|
// Absolute total movement
|
|
var totalX, totalY;
|
|
// Coordinates of the start position.
|
|
var startCoords;
|
|
var lastPos;
|
|
// Whether a swipe is active.
|
|
var active = false;
|
|
// Decide where we are going
|
|
var isDecided = false;
|
|
var isVertical = true;
|
|
|
|
pointerTypes = pointerTypes || ['mouse', 'touch'];
|
|
|
|
element.on(getEvents(pointerTypes, 'start'), function(event) {
|
|
startCoords = getCoordinates(event);
|
|
active = true;
|
|
totalX = 0;
|
|
totalY = 0;
|
|
isDecided = false;
|
|
isVertical = true;
|
|
lastPos = startCoords;
|
|
eventHandlers['start'] && eventHandlers['start'](startCoords, event);
|
|
});
|
|
|
|
element.on(getEvents(pointerTypes, 'cancel'), function(event) {
|
|
active = false;
|
|
eventHandlers['cancel'] && eventHandlers['cancel'](event);
|
|
});
|
|
|
|
element.on(getEvents(pointerTypes, 'move'), function(event) {
|
|
|
|
if (! active) {
|
|
return;
|
|
}
|
|
|
|
if (! startCoords) {
|
|
return;
|
|
}
|
|
|
|
var coords = getCoordinates(event);
|
|
|
|
totalX += Math.abs(coords.x - lastPos.x);
|
|
totalY += Math.abs(coords.y - lastPos.y);
|
|
|
|
lastPos = coords;
|
|
|
|
if (totalX < MOVE_BUFFER_RADIUS && totalY < MOVE_BUFFER_RADIUS) {
|
|
return;
|
|
} else {
|
|
if (! isDecided){
|
|
|
|
var deltaX, deltaY, ratio;
|
|
|
|
deltaX = Math.abs(coords.x - startCoords.x);
|
|
deltaY = Math.abs(coords.y - startCoords.y);
|
|
|
|
ratio = deltaY / deltaX;
|
|
|
|
if (ratio < MAX_RATIO){
|
|
event.preventDefault();
|
|
isVertical = false;
|
|
} else {
|
|
isVertical = true;
|
|
}
|
|
|
|
isDecided = true;
|
|
}
|
|
}
|
|
|
|
event.isVertical = isVertical;
|
|
eventHandlers['move'] && eventHandlers['move'](coords, event);
|
|
});
|
|
|
|
element.on(getEvents(pointerTypes, 'end'), function(event) {
|
|
if (! active){
|
|
return;
|
|
}
|
|
event.isVertical = isVertical;
|
|
active = false;
|
|
eventHandlers['end'] && eventHandlers['end'](getCoordinates(event), event);
|
|
});
|
|
}
|
|
};
|
|
}]);
|
|
|
|
function makeSwipeDirective(directiveName, direction, axis, eventName) {
|
|
ngSwipe.directive(directiveName, ['$parse', 'swipe', function($parse, swipe) {
|
|
|
|
var MAX_OTHER_AXIS_DISTANCE = 75;
|
|
var MAX_RATIO = 0.3;
|
|
var MIN_DISTANCE = 30;
|
|
|
|
return function(scope, element, attr) {
|
|
|
|
var swipeHandler = $parse(attr[directiveName]);
|
|
|
|
var startCoords, valid;
|
|
|
|
function validSwipe(coords) {
|
|
|
|
if (! startCoords || ! valid){
|
|
return false;
|
|
}
|
|
|
|
var deltaY = (coords.y - startCoords.y) * direction;
|
|
var deltaX = (coords.x - startCoords.x) * direction;
|
|
|
|
if (! axis){ // horizontal swipe
|
|
return Math.abs(deltaY) < MAX_OTHER_AXIS_DISTANCE &&
|
|
deltaX > 0 &&
|
|
deltaX > MIN_DISTANCE &&
|
|
Math.abs(deltaY) / deltaX < MAX_RATIO;
|
|
} else { // vertical swipe
|
|
return Math.abs(deltaX) < MAX_OTHER_AXIS_DISTANCE &&
|
|
deltaY > 0 &&
|
|
deltaY > MIN_DISTANCE &&
|
|
Math.abs(deltaX) / deltaY < MAX_RATIO;
|
|
}
|
|
|
|
}
|
|
|
|
var pointerTypes = ['touch'];
|
|
|
|
if (!angular.isDefined(attr['ngSwipeDisableMouse'])) {
|
|
pointerTypes.push('mouse');
|
|
}
|
|
|
|
swipe.bind(element, {
|
|
'start': function(coords, event) {
|
|
var className = event.target.getAttribute('class');
|
|
if (axis && (! className || className && className.match('noPreventDefault') === null)) {
|
|
event.preventDefault();
|
|
}
|
|
startCoords = coords;
|
|
valid = true;
|
|
},
|
|
'cancel': function() {
|
|
valid = false;
|
|
},
|
|
'end': function(coords, event) {
|
|
if (validSwipe(coords)) {
|
|
scope.$apply(function() {
|
|
element.triggerHandler(eventName);
|
|
swipeHandler(scope, { $event: event });
|
|
});
|
|
}
|
|
}
|
|
}, pointerTypes);
|
|
};
|
|
}]);
|
|
}
|
|
|
|
// avoid conflicts with ngTouch module
|
|
|
|
try {
|
|
angular.module('ngTouch');
|
|
} catch(err) {
|
|
makeSwipeDirective('ngSwipeLeft', -1, false, 'swipeleft');
|
|
makeSwipeDirective('ngSwipeRight', 1, false, 'swiperight');
|
|
}
|
|
|
|
// left is negative x-coordinate, right is positive
|
|
|
|
makeSwipeDirective('ngSwipeUp', -1, true, 'swipeup');
|
|
makeSwipeDirective('ngSwipeDown', 1, true, 'swipedown');
|
|
|
|
})(window, window.angular);
|