├── .bowerrc ├── .editorconfig ├── .gitattributes ├── .gitignore ├── .jshintrc ├── Gruntfile.js ├── LICENSE.txt ├── README.md ├── bower.json ├── dist ├── angular-swipe.js └── angular-swipe.min.js ├── package.json └── src ├── angular-swipe.js ├── app.js └── index.html /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | 8 | [*] 9 | 10 | # Change these settings to your own preference 11 | indent_style = space 12 | indent_size = 2 13 | 14 | # We recommend you to keep these unchanged 15 | end_of_line = lf 16 | charset = utf-8 17 | trim_trailing_whitespace = true 18 | insert_final_newline = true 19 | 20 | [*.md] 21 | trim_trailing_whitespace = false 22 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .tmp 3 | bower_components 4 | test 5 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "browser": true, 4 | "sub": true, 5 | "esnext": true, 6 | "bitwise": true, 7 | "camelcase": true, 8 | "curly": true, 9 | "expr": true, 10 | "eqeqeq": true, 11 | "immed": true, 12 | "indent": 2, 13 | "latedef": true, 14 | "newcap": true, 15 | "noarg": true, 16 | "quotmark": "single", 17 | "regexp": true, 18 | "undef": true, 19 | "unused": true, 20 | "strict": true, 21 | "trailing": true, 22 | "smarttabs": true, 23 | "jquery": true, 24 | "globals": { 25 | "angular": false 26 | }, 27 | "predef": [ "angular" ] 28 | } 29 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (grunt) { 4 | // load all grunt tasks 5 | require('load-grunt-tasks')(grunt); 6 | 7 | grunt.initConfig({ 8 | // configurable paths 9 | yeoman: { 10 | app: 'src', 11 | dist: 'dist' 12 | }, 13 | 14 | watch: { 15 | livereload: { 16 | options: { 17 | livereload: '<%= connect.options.livereload %>' 18 | }, 19 | files: [ 20 | '<%= yeoman.app %>/*.html', 21 | '{.tmp,<%= yeoman.app %>}/scripts/{,*/}*.js' 22 | ] 23 | } 24 | }, 25 | 26 | connect: { 27 | options: { 28 | port: 9000, 29 | livereload: 35729, 30 | hostname: 'localhost' 31 | }, 32 | livereload: { 33 | options: { 34 | open: true, 35 | base: [ 36 | '.tmp', 37 | 'bower_components', 38 | '<%= yeoman.app %>' 39 | ] 40 | } 41 | }, 42 | test: { 43 | options: { 44 | base: [ 45 | '.tmp', 46 | 'test', 47 | '<%= yeoman.app %>' 48 | ] 49 | } 50 | }, 51 | dist: { 52 | options: { 53 | open: true, 54 | base: '<%= yeoman.dist %>', 55 | livereload: false 56 | } 57 | } 58 | }, 59 | 60 | clean: { 61 | dist: { 62 | files: [{ 63 | dot: true, 64 | src: [ 65 | '.tmp', 66 | '<%= yeoman.dist %>/*', 67 | '!<%= yeoman.dist %>/.git*' 68 | ] 69 | }] 70 | }, 71 | server: '.tmp' 72 | }, 73 | 74 | jshint: { 75 | options: { 76 | jshintrc: '.jshintrc' 77 | }, 78 | all: [ 79 | '<%= yeoman.app %>/{,*/}*.js' 80 | ] 81 | }, 82 | 83 | copy: { 84 | dist: { 85 | files: [{ 86 | expand: true, 87 | dot: true, 88 | cwd: '<%= yeoman.app %>', 89 | dest: '<%= yeoman.dist %>', 90 | src: [ 91 | 'angular-swipe.js' 92 | ] 93 | }] 94 | } 95 | }, 96 | 97 | concat: { 98 | options: { 99 | separator: ';' 100 | }, 101 | dist: { 102 | src: ['<%= yeoman.app %>/angular-swipe.js'], 103 | dest: '<%= yeoman.dist %>/angular-swipe.min.js' 104 | } 105 | }, 106 | 107 | uglify: { 108 | options: { 109 | banner: '/*! angular-swipe.min.js <%= grunt.template.today("dd-mm-yyyy") %> */\n' 110 | }, 111 | dist: { 112 | files: { 113 | 'dist/angular-swipe.min.js': ['<%= concat.dist.dest %>'] 114 | } 115 | } 116 | } 117 | 118 | }); 119 | 120 | grunt.registerTask('serve', function (target) { 121 | if (target === 'dist') { 122 | return grunt.task.run(['build', 'connect:dist:keepalive']); 123 | } 124 | 125 | grunt.task.run([ 126 | 'clean:server', 127 | 'connect:livereload', 128 | 'watch' 129 | ]); 130 | }); 131 | 132 | grunt.registerTask('build', [ 133 | 'clean:dist', 134 | 'concat', 135 | 'uglify', 136 | 'copy:dist' 137 | ]); 138 | 139 | grunt.registerTask('default', [ 140 | 'jshint', 141 | 'build' 142 | ]); 143 | }; 144 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2010-2017 Google, Inc. http://angularjs.org 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | angular-swipe 2 | ============= 3 | 4 | Simple vertical/horizontal swipe gesture directives and a swipe service for angular js >= 1.6. Small extension of the existing angular $swipe service. 5 | 6 | ## Install 7 | 8 | + Add this line to your *bower.json* dependencies and run *bower install* afterwards. 9 | 10 | > 11 | ``` JavaScript 12 | "angular-swipe": "~0.2.1" 13 | ``` 14 | 15 | + Include the required source file (this path or similar) 16 | 17 | > 18 | ``` html 19 | 20 | ``` 21 | 22 | + Inject the `swipe` module into your app. 23 | 24 | > 25 | ``` JavaScript 26 | angular.module('app', ['swipe']); 27 | ``` 28 | 29 | ## Usage 30 | 31 | #### Module Name (Dependency) 32 | 33 | * swipe 34 | 35 | #### Directives 36 | 37 | * ng-swipe-up 38 | * ng-swipe-down 39 | * ng-swipe-left 40 | * ng-swipe-right 41 | 42 | #### Directive Attributes 43 | 44 | `ng-swipe-disable-mouse` "This attribute is useful for text that should still be selectable by the mouse and not trigger the swipe action." 45 | 46 | #### Service 47 | 48 | * swipe 49 | 50 | ## Example 51 | 52 | > 53 | ```html 54 |
55 |
56 |

Swipe me up!

57 |
58 |
59 | ``` 60 | 61 | > 62 | ```JavaScript 63 | var app = angular.module('app', [ 'swipe' ]); 64 | app.controller('AppCtrl', function AppCtrl($scope) { 65 | $scope.swipe = function($event) { 66 | console.log($event); 67 | }; 68 | }) 69 | ``` 70 | 71 | ## Known issues and workarounds 72 | 73 | * ng-swipe-up and ng-swipe-down uses preventDefault when you start swiping. This prevents clicks from giving focus to input fields. Adding a `noPreventDefault` class to these elements will not preventDefault when the swipe start on them and thus allow clicks to work. 74 | 75 | * When embedding a Google map you might want to prevent a swipe event specifically inside the map. You can do that by adding the `noStartDrag` class to the Google map HTML element 76 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-swipe", 3 | "description": "Simple vertical and horizontal swipe gesture directive for angular js", 4 | "version": "0.2.1", 5 | "authors": [ 6 | "marmorkuchen.net " 7 | ], 8 | "homepage": "https://github.com/adzialocha/angular-swipe", 9 | "repository": { 10 | "type": "git", 11 | "url": "git@github.com:adzialocha/angular-swipe.git" 12 | }, 13 | "keywords": [ 14 | "swipe", 15 | "horizontal", 16 | "touch", 17 | "vertical", 18 | "gesture", 19 | "mobile", 20 | "angularjs", 21 | "angular", 22 | "directive" 23 | ], 24 | "main": "./dist/angular-swipe.js", 25 | "dependencies": { 26 | "angular": "~1.6.x" 27 | }, 28 | "ignore": [ 29 | ".jshintrc", 30 | "Gruntfile.js", 31 | "package.json", 32 | "src" 33 | ], 34 | "devDependencies": {}, 35 | "private": false, 36 | "license": "MIT" 37 | } 38 | -------------------------------------------------------------------------------- /dist/angular-swipe.js: -------------------------------------------------------------------------------- 1 | (function(window, angular, undefined) { 2 | 'use strict'; 3 | 4 | /* global -ngSwipe */ 5 | 6 | var ngSwipe = angular.module('swipe', []); 7 | 8 | ngSwipe.factory('swipe', [ function() { 9 | 10 | var MOVE_BUFFER_RADIUS = 40; 11 | var MAX_RATIO = 0.3; 12 | 13 | var POINTER_EVENTS = { 14 | 'mouse': { 15 | start: 'mousedown', 16 | move: 'mousemove', 17 | end: 'mouseup' 18 | }, 19 | 'touch': { 20 | start: 'touchstart', 21 | move: 'touchmove', 22 | end: 'touchend', 23 | cancel: 'touchcancel' 24 | } 25 | }; 26 | 27 | function getCoordinates(event) { 28 | var originalEvent = event.originalEvent || event; 29 | var touches = originalEvent.touches && originalEvent.touches.length ? originalEvent.touches : [originalEvent]; 30 | var e = (originalEvent.changedTouches && originalEvent.changedTouches[0]) || touches[0]; 31 | 32 | return { 33 | x: e.clientX, 34 | y: e.clientY 35 | }; 36 | } 37 | 38 | function getEvents(pointerTypes, eventType) { 39 | var res = []; 40 | angular.forEach(pointerTypes, function(pointerType) { 41 | var eventName = POINTER_EVENTS[pointerType][eventType]; 42 | if (eventName) { 43 | res.push(eventName); 44 | } 45 | }); 46 | return res.join(' '); 47 | } 48 | 49 | return { 50 | 51 | bind: function(element, eventHandlers, pointerTypes) { 52 | 53 | // Absolute total movement 54 | var totalX, totalY; 55 | // Coordinates of the start position. 56 | var startCoords; 57 | var lastPos; 58 | // Whether a swipe is active. 59 | var active = false; 60 | // Decide where we are going 61 | var isDecided = false; 62 | var isVertical = true; 63 | 64 | pointerTypes = pointerTypes || ['mouse', 'touch']; 65 | 66 | element.on(getEvents(pointerTypes, 'start'), function(event) { 67 | startCoords = getCoordinates(event); 68 | active = true; 69 | totalX = 0; 70 | totalY = 0; 71 | isDecided = false; 72 | isVertical = true; 73 | lastPos = startCoords; 74 | eventHandlers['start'] && eventHandlers['start'](startCoords, event); 75 | }); 76 | 77 | element.on(getEvents(pointerTypes, 'cancel'), function(event) { 78 | active = false; 79 | eventHandlers['cancel'] && eventHandlers['cancel'](event); 80 | }); 81 | 82 | element.on(getEvents(pointerTypes, 'move'), function(event) { 83 | 84 | if (! active) { 85 | return; 86 | } 87 | 88 | if (! startCoords) { 89 | return; 90 | } 91 | 92 | var coords = getCoordinates(event); 93 | 94 | totalX += Math.abs(coords.x - lastPos.x); 95 | totalY += Math.abs(coords.y - lastPos.y); 96 | 97 | lastPos = coords; 98 | 99 | if (totalX < MOVE_BUFFER_RADIUS && totalY < MOVE_BUFFER_RADIUS) { 100 | return; 101 | } else { 102 | if (! isDecided){ 103 | 104 | var deltaX, deltaY, ratio; 105 | 106 | deltaX = Math.abs(coords.x - startCoords.x); 107 | deltaY = Math.abs(coords.y - startCoords.y); 108 | 109 | ratio = deltaY / deltaX; 110 | 111 | if (ratio < MAX_RATIO){ 112 | event.preventDefault(); 113 | isVertical = false; 114 | } else { 115 | isVertical = true; 116 | } 117 | 118 | isDecided = true; 119 | } 120 | } 121 | 122 | event.isVertical = isVertical; 123 | eventHandlers['move'] && eventHandlers['move'](coords, event); 124 | }); 125 | 126 | element.on(getEvents(pointerTypes, 'end'), function(event) { 127 | if (! active){ 128 | return; 129 | } 130 | event.isVertical = isVertical; 131 | active = false; 132 | eventHandlers['end'] && eventHandlers['end'](getCoordinates(event), event); 133 | }); 134 | } 135 | }; 136 | }]); 137 | 138 | function makeSwipeDirective(directiveName, direction, axis, eventName) { 139 | ngSwipe.directive(directiveName, ['$parse', 'swipe', function($parse, swipe) { 140 | 141 | var MAX_OTHER_AXIS_DISTANCE = 75; 142 | var MAX_RATIO = 0.3; 143 | var MIN_DISTANCE = 30; 144 | 145 | return function(scope, element, attr) { 146 | 147 | var swipeHandler = $parse(attr[directiveName]); 148 | 149 | var startCoords, valid; 150 | 151 | function checkOverride(element, clazz) { 152 | do { 153 | var className = element.getAttribute('class'); 154 | if (className && className.match(clazz) !== null) { 155 | return true; 156 | } 157 | element = element.parentElement; 158 | } while (element !== null); 159 | return false; 160 | } 161 | 162 | function validSwipe(coords) { 163 | 164 | if (! startCoords || ! valid){ 165 | return false; 166 | } 167 | 168 | var deltaY = (coords.y - startCoords.y) * direction; 169 | var deltaX = (coords.x - startCoords.x) * direction; 170 | 171 | if(axis === null) { // tap 172 | return Math.abs(deltaY) < MIN_DISTANCE && 173 | Math.abs(deltaX) < MIN_DISTANCE; 174 | } 175 | else if(axis === false) { // horizontal swipe 176 | return Math.abs(deltaY) < MAX_OTHER_AXIS_DISTANCE && 177 | deltaX > 0 && 178 | deltaX > MIN_DISTANCE && 179 | Math.abs(deltaY) / deltaX < MAX_RATIO; 180 | } 181 | else { // vertical swipe 182 | return Math.abs(deltaX) < MAX_OTHER_AXIS_DISTANCE && 183 | deltaY > 0 && 184 | deltaY > MIN_DISTANCE && 185 | Math.abs(deltaX) / deltaY < MAX_RATIO; 186 | } 187 | } 188 | 189 | var pointerTypes = ['touch']; 190 | 191 | if (!angular.isDefined(attr['ngSwipeDisableMouse'])) { 192 | pointerTypes.push('mouse'); 193 | } 194 | 195 | swipe.bind(element, { 196 | 'start': function(coords, event) { 197 | if (axis && !checkOverride(event.target, 'noPreventDefault')) { 198 | event.preventDefault(); 199 | } 200 | startCoords = coords; 201 | valid = !checkOverride(event.target, 'noStartDrag'); 202 | }, 203 | 'cancel': function() { 204 | valid = false; 205 | }, 206 | 'end': function(coords, event) { 207 | if (validSwipe(coords)) { 208 | scope.$apply(function() { 209 | element.triggerHandler(eventName); 210 | swipeHandler(scope, { $event: event }); 211 | }); 212 | } 213 | } 214 | }, pointerTypes); 215 | }; 216 | }]); 217 | } 218 | 219 | // avoid conflicts with ngTouch module 220 | 221 | try { 222 | angular.module('ngTouch'); 223 | } catch(err) { 224 | makeSwipeDirective('ngSwipeLeft', -1, false, 'swipeleft'); 225 | makeSwipeDirective('ngSwipeRight', 1, false, 'swiperight'); 226 | } 227 | 228 | // left is negative x-coordinate, right is positive 229 | 230 | makeSwipeDirective('ngSwipeUp', -1, true, 'swipeup'); 231 | makeSwipeDirective('ngSwipeDown', 1, true, 'swipedown'); 232 | 233 | makeSwipeDirective('ngTap', 1, null, 'tap'); 234 | })(window, window.angular); 235 | -------------------------------------------------------------------------------- /dist/angular-swipe.min.js: -------------------------------------------------------------------------------- 1 | /*! angular-swipe.min.js 13-03-2017 */ 2 | !function(a,b,c){"use strict";function d(a,c,d,f){e.directive(a,["$parse","swipe",function(e,g){var h=75,i=.3,j=30;return function(k,l,m){function n(a,b){do{var c=a.getAttribute("class");if(c&&null!==c.match(b))return!0;a=a.parentElement}while(null!==a);return!1}function o(a){if(!p||!q)return!1;var b=(a.y-p.y)*c,e=(a.x-p.x)*c;return null===d?Math.abs(b)0&&e>j&&Math.abs(b)/e0&&b>j&&Math.abs(e)/b=0.8.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/angular-swipe.js: -------------------------------------------------------------------------------- 1 | (function(window, angular, undefined) { 2 | 'use strict'; 3 | 4 | /* global -ngSwipe */ 5 | 6 | var ngSwipe = angular.module('swipe', []); 7 | 8 | ngSwipe.factory('swipe', [ function() { 9 | 10 | var MOVE_BUFFER_RADIUS = 40; 11 | var MAX_RATIO = 0.3; 12 | 13 | var POINTER_EVENTS = { 14 | 'mouse': { 15 | start: 'mousedown', 16 | move: 'mousemove', 17 | end: 'mouseup' 18 | }, 19 | 'touch': { 20 | start: 'touchstart', 21 | move: 'touchmove', 22 | end: 'touchend', 23 | cancel: 'touchcancel' 24 | } 25 | }; 26 | 27 | function getCoordinates(event) { 28 | var originalEvent = event.originalEvent || event; 29 | var touches = originalEvent.touches && originalEvent.touches.length ? originalEvent.touches : [originalEvent]; 30 | var e = (originalEvent.changedTouches && originalEvent.changedTouches[0]) || touches[0]; 31 | 32 | return { 33 | x: e.clientX, 34 | y: e.clientY 35 | }; 36 | } 37 | 38 | function getEvents(pointerTypes, eventType) { 39 | var res = []; 40 | angular.forEach(pointerTypes, function(pointerType) { 41 | var eventName = POINTER_EVENTS[pointerType][eventType]; 42 | if (eventName) { 43 | res.push(eventName); 44 | } 45 | }); 46 | return res.join(' '); 47 | } 48 | 49 | return { 50 | 51 | bind: function(element, eventHandlers, pointerTypes) { 52 | 53 | // Absolute total movement 54 | var totalX, totalY; 55 | // Coordinates of the start position. 56 | var startCoords; 57 | var lastPos; 58 | // Whether a swipe is active. 59 | var active = false; 60 | // Decide where we are going 61 | var isDecided = false; 62 | var isVertical = true; 63 | 64 | pointerTypes = pointerTypes || ['mouse', 'touch']; 65 | 66 | element.on(getEvents(pointerTypes, 'start'), function(event) { 67 | startCoords = getCoordinates(event); 68 | active = true; 69 | totalX = 0; 70 | totalY = 0; 71 | isDecided = false; 72 | isVertical = true; 73 | lastPos = startCoords; 74 | eventHandlers['start'] && eventHandlers['start'](startCoords, event); 75 | }); 76 | 77 | element.on(getEvents(pointerTypes, 'cancel'), function(event) { 78 | active = false; 79 | eventHandlers['cancel'] && eventHandlers['cancel'](event); 80 | }); 81 | 82 | element.on(getEvents(pointerTypes, 'move'), function(event) { 83 | 84 | if (! active) { 85 | return; 86 | } 87 | 88 | if (! startCoords) { 89 | return; 90 | } 91 | 92 | var coords = getCoordinates(event); 93 | 94 | totalX += Math.abs(coords.x - lastPos.x); 95 | totalY += Math.abs(coords.y - lastPos.y); 96 | 97 | lastPos = coords; 98 | 99 | if (totalX < MOVE_BUFFER_RADIUS && totalY < MOVE_BUFFER_RADIUS) { 100 | return; 101 | } else { 102 | if (! isDecided){ 103 | 104 | var deltaX, deltaY, ratio; 105 | 106 | deltaX = Math.abs(coords.x - startCoords.x); 107 | deltaY = Math.abs(coords.y - startCoords.y); 108 | 109 | ratio = deltaY / deltaX; 110 | 111 | if (ratio < MAX_RATIO){ 112 | event.preventDefault(); 113 | isVertical = false; 114 | } else { 115 | isVertical = true; 116 | } 117 | 118 | isDecided = true; 119 | } 120 | } 121 | 122 | event.isVertical = isVertical; 123 | eventHandlers['move'] && eventHandlers['move'](coords, event); 124 | }); 125 | 126 | element.on(getEvents(pointerTypes, 'end'), function(event) { 127 | if (! active){ 128 | return; 129 | } 130 | event.isVertical = isVertical; 131 | active = false; 132 | eventHandlers['end'] && eventHandlers['end'](getCoordinates(event), event); 133 | }); 134 | } 135 | }; 136 | }]); 137 | 138 | function makeSwipeDirective(directiveName, direction, axis, eventName) { 139 | ngSwipe.directive(directiveName, ['$parse', 'swipe', function($parse, swipe) { 140 | 141 | var MAX_OTHER_AXIS_DISTANCE = 75; 142 | var MAX_RATIO = 0.3; 143 | var MIN_DISTANCE = 30; 144 | 145 | return function(scope, element, attr) { 146 | 147 | var swipeHandler = $parse(attr[directiveName]); 148 | 149 | var startCoords, valid; 150 | 151 | function checkOverride(element, clazz) { 152 | do { 153 | var className = element.getAttribute('class'); 154 | if (className && className.match(clazz) !== null) { 155 | return true; 156 | } 157 | element = element.parentElement; 158 | } while (element !== null); 159 | return false; 160 | } 161 | 162 | function validSwipe(coords) { 163 | 164 | if (! startCoords || ! valid){ 165 | return false; 166 | } 167 | 168 | var deltaY = (coords.y - startCoords.y) * direction; 169 | var deltaX = (coords.x - startCoords.x) * direction; 170 | 171 | if(axis === null) { // tap 172 | return Math.abs(deltaY) < MIN_DISTANCE && 173 | Math.abs(deltaX) < MIN_DISTANCE; 174 | } 175 | else if(axis === false) { // horizontal swipe 176 | return Math.abs(deltaY) < MAX_OTHER_AXIS_DISTANCE && 177 | deltaX > 0 && 178 | deltaX > MIN_DISTANCE && 179 | Math.abs(deltaY) / deltaX < MAX_RATIO; 180 | } 181 | else { // vertical swipe 182 | return Math.abs(deltaX) < MAX_OTHER_AXIS_DISTANCE && 183 | deltaY > 0 && 184 | deltaY > MIN_DISTANCE && 185 | Math.abs(deltaX) / deltaY < MAX_RATIO; 186 | } 187 | } 188 | 189 | var pointerTypes = ['touch']; 190 | 191 | if (!angular.isDefined(attr['ngSwipeDisableMouse'])) { 192 | pointerTypes.push('mouse'); 193 | } 194 | 195 | swipe.bind(element, { 196 | 'start': function(coords, event) { 197 | if (axis && !checkOverride(event.target, 'noPreventDefault')) { 198 | event.preventDefault(); 199 | } 200 | startCoords = coords; 201 | valid = !checkOverride(event.target, 'noStartDrag'); 202 | }, 203 | 'cancel': function() { 204 | valid = false; 205 | }, 206 | 'end': function(coords, event) { 207 | if (validSwipe(coords)) { 208 | scope.$apply(function() { 209 | element.triggerHandler(eventName); 210 | swipeHandler(scope, { $event: event }); 211 | }); 212 | } 213 | } 214 | }, pointerTypes); 215 | }; 216 | }]); 217 | } 218 | 219 | // avoid conflicts with ngTouch module 220 | 221 | try { 222 | angular.module('ngTouch'); 223 | } catch(err) { 224 | makeSwipeDirective('ngSwipeLeft', -1, false, 'swipeleft'); 225 | makeSwipeDirective('ngSwipeRight', 1, false, 'swiperight'); 226 | } 227 | 228 | // left is negative x-coordinate, right is positive 229 | 230 | makeSwipeDirective('ngSwipeUp', -1, true, 'swipeup'); 231 | makeSwipeDirective('ngSwipeDown', 1, true, 'swipedown'); 232 | 233 | makeSwipeDirective('ngTap', 1, null, 'tap'); 234 | })(window, window.angular); 235 | -------------------------------------------------------------------------------- /src/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var app = angular.module('app', [ 'swipe' ]); 4 | 5 | app.controller('AppCtrl', function AppCtrl($scope) { 6 | $scope.message = 'Hey!'; 7 | $scope.inputtest = ''; 8 | 9 | $scope.swipe = function($event) { 10 | console.log($event); 11 | }; 12 | 13 | $scope.$watch('inputtest', function(newVal) { 14 | $scope.message = 'Hey ' + newVal + '!'; 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | angular swipe 9 | 10 | 11 | 12 | 13 | 14 | 15 | 27 | 28 | 29 | 30 | 31 |
32 |

Test Horizontal

33 | 34 |

{{ message }}

35 |
36 |
37 |

Test Vertical

38 | 39 |

{{ message }}

40 |
41 | 42 | 43 | 44 | --------------------------------------------------------------------------------