This repository has been archived by the owner on Feb 22, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 248
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: New touch module including ng-swipe-left/ng-swipe-right directives
Support swipe gesture for touch enabled devices. Closes #1403
- Loading branch information
Showing
5 changed files
with
222 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
/** | ||
* Touch related functionality for AngularDart apps. | ||
* | ||
* To use, install the TouchModule into your main module: | ||
* | ||
* var module = new Module() | ||
* ..install(new TouchModule()); | ||
* | ||
* Once the module is installed, you can use decorators such | ||
* as ng-swipe-left or ng-swipe right | ||
*/ | ||
|
||
library angular.touch; | ||
|
||
import 'dart:html' as dom; | ||
import 'package:di/di.dart'; | ||
import 'package:angular/core/annotation.dart'; | ||
|
||
part 'ng_swipe.dart'; | ||
|
||
class TouchModule extends Module { | ||
TouchModule() { | ||
bind(NgSwipeLeft, toValue: null); | ||
bind(NgSwipeRight, toValue: null); | ||
} | ||
} | ||
|
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,106 @@ | ||
part of angular.touch; | ||
|
||
/** | ||
* Base class for Swipe Gesture. Decides whether a swipe is performed | ||
* and gives the x, y direction of the swipe. | ||
*/ | ||
abstract class _SwipeGesture { | ||
static const int NO_SWIPE = -1; | ||
static const int DOWN = 0; | ||
static const int UP = 1; | ||
static const int LEFT = 2; | ||
static const int RIGHT = 3; | ||
|
||
// Less than 100 pixels of move in each direction does not count. | ||
static const int _POS_TOLERANCE = 100; | ||
// If swipe lasts more than 1s, it is not a swipe. | ||
static const int _TIME_TOLERANCE = 1000; | ||
|
||
// Function to be called on swipe. | ||
Function fn; | ||
|
||
// Subclasses decide on swipe direction whether to call fn or not. | ||
bool get shouldFire; | ||
|
||
int _startX; | ||
int _startY; | ||
int _startTime; | ||
int xDirection; | ||
int yDirection; | ||
|
||
_SwipeGesture(dom.Element target) { | ||
target.onTouchStart.listen(_handleTouchStartEvent); | ||
target.onTouchEnd.listen(_handleTouchEndEvent); | ||
} | ||
|
||
void handleTouchStart(int x, int y, int timestamp) { | ||
// Reset values every time swipe starts | ||
xDirection = NO_SWIPE; | ||
yDirection = NO_SWIPE; | ||
_startX = x; | ||
_startY = y; | ||
_startTime = timestamp; | ||
} | ||
|
||
void handleTouchEnd(int x, int y, int timestamp) { | ||
int touchDuration = timestamp - _startTime; | ||
if (touchDuration > _TIME_TOLERANCE) { | ||
return; | ||
} | ||
if (y > _startY + _POS_TOLERANCE) { | ||
yDirection = DOWN; | ||
} else if (y < _startY - _POS_TOLERANCE) { | ||
yDirection = UP; | ||
} | ||
if (x > _startX + _POS_TOLERANCE) { | ||
xDirection = RIGHT; | ||
} else if (x < _startX - _POS_TOLERANCE) { | ||
xDirection = LEFT; | ||
} | ||
if (fn != null && shouldFire) { | ||
fn(); | ||
} | ||
} | ||
|
||
void _handleTouchStartEvent(dom.TouchEvent ev) { | ||
// Guaranteed to have at least one touch in changedTouches. | ||
dom.Touch t = ev.changedTouches.first; | ||
handleTouchStart(t.client.x, t.client.y, ev.timeStamp); | ||
} | ||
|
||
void _handleTouchEndEvent(dom.TouchEvent ev) { | ||
// Guaranteed to have at least one touch in changedTouches. | ||
dom.Touch t = ev.changedTouches.first; | ||
handleTouchEnd(t.client.x, t.client.y, ev.timeStamp); | ||
} | ||
} | ||
|
||
/** | ||
* The `ng-swipe-right` directive allows execution of callbacks when user | ||
* swipes her finger to the right. | ||
* Also see [NgSwipeLeft]. | ||
*/ | ||
@Decorator( | ||
selector: '[ng-swipe-right]', | ||
map: const {'ng-swipe-right':'&fn'}) | ||
class NgSwipeRight extends _SwipeGesture { | ||
NgSwipeRight(dom.Element target): super(target); | ||
|
||
bool get shouldFire => xDirection == _SwipeGesture.RIGHT && | ||
yDirection == _SwipeGesture.NO_SWIPE; | ||
} | ||
|
||
/** | ||
* The `ng-swipe-left` directive allows execution of callbacks when user | ||
* swipes his finger to the left. | ||
* Also see [NgSwipeRight]. | ||
*/ | ||
@Decorator( | ||
selector: '[ng-swipe-left]', | ||
map: const {'ng-swipe-left':'&fn'}) | ||
class NgSwipeLeft extends _SwipeGesture { | ||
NgSwipeLeft(dom.Element target): super(target); | ||
|
||
bool get shouldFire => xDirection == _SwipeGesture.LEFT && | ||
yDirection == _SwipeGesture.NO_SWIPE; | ||
} |
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,71 @@ | ||
library ng_swipe_spec; | ||
|
||
import '../_specs.dart'; | ||
|
||
/** | ||
* Unfortunately, it is not possible to test swipe using events since | ||
* TouchEvent cannot be constructed using fake dom.Touch elements. | ||
* See: dartbug.com/8314 | ||
* TODO(8314): Once this is fixed, should update the tests. | ||
*/ | ||
void main() { | ||
describe('ng-swipe-right', () { | ||
NgSwipeRight swipe = new NgSwipeRight(new DivElement()); | ||
|
||
it('should not fire when distance is not enough', () { | ||
swipe.handleTouchStart(10, 10, 0); | ||
swipe.handleTouchEnd(15, 15, 1); | ||
expect(swipe.shouldFire).toBeFalse(); | ||
}); | ||
|
||
it('should fire on swipe to the right', () { | ||
swipe.handleTouchStart(10, 10, 0); | ||
swipe.handleTouchEnd(130, 15, 1); | ||
expect(swipe.shouldFire).toBeTrue(); | ||
}); | ||
|
||
it('should not fire on swipe to the left', () { | ||
swipe.handleTouchStart(130, 10, 0); | ||
swipe.handleTouchEnd(10, 15, 1); | ||
expect(swipe.shouldFire).toBeFalse(); | ||
}); | ||
|
||
it('should not fire on slow swipe', () { | ||
swipe.handleTouchStart(10, 10, 0); | ||
// 2 seconds later | ||
swipe.handleTouchEnd(130, 15, 2000); | ||
expect(swipe.shouldFire).toBeFalse(); | ||
}); | ||
|
||
|
||
}); | ||
|
||
describe('ng-swipe-left', () { | ||
NgSwipeLeft swipe = new NgSwipeLeft(new DivElement()); | ||
|
||
it('should not fire when distance is not enough', () { | ||
swipe.handleTouchStart(10, 10, 0); | ||
swipe.handleTouchEnd(15, 15, 1); | ||
expect(swipe.shouldFire).toBeFalse(); | ||
}); | ||
|
||
it('should not fire on swipe to the right', () { | ||
swipe.handleTouchStart(10, 10, 0); | ||
swipe.handleTouchEnd(130, 15, 1); | ||
expect(swipe.shouldFire).toBeFalse(); | ||
}); | ||
|
||
it('should fire on swipe to the left', () { | ||
swipe.handleTouchStart(130, 10, 0); | ||
swipe.handleTouchEnd(10, 15, 1); | ||
expect(swipe.shouldFire).toBeTrue(); | ||
}); | ||
|
||
it('should not fire on swipe on slow swipe', () { | ||
swipe.handleTouchStart(130, 10, 0); | ||
// 2 seconds later | ||
swipe.handleTouchEnd(10, 15, 2000); | ||
expect(swipe.shouldFire).toBeFalse(); | ||
}); | ||
}); | ||
} |