This repository has been archived by the owner on Apr 12, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 27.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat($swipe): Refactor swipe logic from ngSwipe to $swipe service.
This new service is used by the ngSwipeLeft/Right directives, and by the separate ngCarousel and swipe-to-delete directives which are under development.
- Loading branch information
1 parent
05772e1
commit f4c6b2c
Showing
5 changed files
with
437 additions
and
79 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
'use strict'; | ||
|
||
/** | ||
* @ngdoc object | ||
* @name ngMobile.$swipe | ||
* | ||
* @description | ||
* The `$swipe` service is a service that abstracts the messier details of hold-and-drag swipe | ||
* behavior, to make implementing swipe-related directives more convenient. | ||
* | ||
* It is used by the `ngSwipeLeft` and `ngSwipeRight` directives in `ngMobile`, and by | ||
* `ngCarousel` in a separate component. | ||
* | ||
* # Usage | ||
* The `$swipe` service is an object with a single method: `bind`. `bind` takes an element | ||
* which is to be watched for swipes, and an object with four handler functions. See the | ||
* documentation for `bind` below. | ||
*/ | ||
|
||
ngMobile.factory('$swipe', [function() { | ||
// The total distance in any direction before we make the call on swipe vs. scroll. | ||
var MOVE_BUFFER_RADIUS = 10; | ||
|
||
function getCoordinates(event) { | ||
var touches = event.touches && event.touches.length ? event.touches : [event]; | ||
var e = (event.changedTouches && event.changedTouches[0]) || | ||
(event.originalEvent && event.originalEvent.changedTouches && | ||
event.originalEvent.changedTouches[0]) || | ||
touches[0].originalEvent || touches[0]; | ||
|
||
return { | ||
x: e.clientX, | ||
y: e.clientY | ||
}; | ||
} | ||
|
||
return { | ||
/** | ||
* @ngdoc method | ||
* @name ngMobile.$swipe#bind | ||
* @methodOf ngMobile.$swipe | ||
* | ||
* @description | ||
* The main method of `$swipe`. It takes an element to be watched for swipe motions, and an | ||
* object containing event handlers. | ||
* | ||
* The four events are `start`, `move`, `end`, and `cancel`. `start`, `move`, and `end` | ||
* receive as a parameter a coordinates object of the form `{ x: 150, y: 310 }`. | ||
* | ||
* `start` is called on either `mousedown` or `touchstart`. After this event, `$swipe` is | ||
* watching for `touchmove` or `mousemove` events. These events are ignored until the total | ||
* distance moved in either dimension exceeds a small threshold. | ||
* | ||
* Once this threshold is exceeded, either the horizontal or vertical delta is greater. | ||
* - If the horizontal distance is greater, this is a swipe and `move` and `end` events follow. | ||
* - If the vertical distance is greater, this is a scroll, and we let the browser take over. | ||
* A `cancel` event is sent. | ||
* | ||
* `move` is called on `mousemove` and `touchmove` after the above logic has determined that | ||
* a swipe is in progress. | ||
* | ||
* `end` is called when a swipe is successfully completed with a `touchend` or `mouseup`. | ||
* | ||
* `cancel` is called either on a `touchcancel` from the browser, or when we begin scrolling | ||
* as described above. | ||
* | ||
*/ | ||
bind: function(element, eventHandlers) { | ||
// Absolute total movement, used to control swipe vs. scroll. | ||
var totalX, totalY; | ||
// Coordinates of the start position. | ||
var startCoords; | ||
// Last event's position. | ||
var lastPos; | ||
// Whether a swipe is active. | ||
var active = false; | ||
|
||
element.bind('touchstart mousedown', function(event) { | ||
startCoords = getCoordinates(event); | ||
active = true; | ||
totalX = 0; | ||
totalY = 0; | ||
lastPos = startCoords; | ||
eventHandlers['start'] && eventHandlers['start'](startCoords); | ||
}); | ||
|
||
element.bind('touchcancel', function(event) { | ||
active = false; | ||
eventHandlers['cancel'] && eventHandlers['cancel'](); | ||
}); | ||
|
||
element.bind('touchmove mousemove', function(event) { | ||
if (!active) return; | ||
|
||
// Android will send a touchcancel if it thinks we're starting to scroll. | ||
// So when the total distance (+ or - or both) exceeds 10px in either direction, | ||
// we either: | ||
// - On totalX > totalY, we send preventDefault() and treat this as a swipe. | ||
// - On totalY > totalX, we let the browser handle it as a scroll. | ||
|
||
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; | ||
} | ||
|
||
// One of totalX or totalY has exceeded the buffer, so decide on swipe vs. scroll. | ||
if (totalY > totalX) { | ||
// Allow native scrolling to take over. | ||
active = false; | ||
eventHandlers['cancel'] && eventHandlers['cancel'](); | ||
return; | ||
} else { | ||
// Prevent the browser from scrolling. | ||
event.preventDefault(); | ||
|
||
eventHandlers['move'] && eventHandlers['move'](coords); | ||
} | ||
}); | ||
|
||
element.bind('touchend mouseup', function(event) { | ||
if (!active) return; | ||
active = false; | ||
eventHandlers['end'] && eventHandlers['end'](getCoordinates(event)); | ||
}); | ||
} | ||
}; | ||
}]); | ||
|
||
|
Oops, something went wrong.