How to implement swipe gestures for mobile devices?
Asked Answered
A

8

49

I have an application made in AngularJS which has arrow key navigation to switch views.

I want to implement this navigation using swipe for touch devices. I tried jGestures library but it doesn't go well with swipe. I have been recommended NOT to use jquery mobile.

Is there any other way to implement swipe?

EDIT: It does not detect swipe cleanly. I tested it on multiple devices, including iPad and it takes multiple swipes to do an action(routing in my case).

Agone answered 26/2, 2013 at 8:41 Comment(3)
You may want to elaborate on the issues you had with jGestures. I've not used it myself, but it looks like a robust version of custom code I've written for simple gesture support (and seen elsewhere).Jerri
"I have been recommended NOT to use jquery mobile." why?Kilderkin
possible duplicate of Detect a finger swipe through JavaScript on the iPhone and AndroidKilderkin
S
67

I made this function for my needs.

Feel free to use it. Works great on mobile devices.

function detectswipe(el,func) {
  swipe_det = new Object();
  swipe_det.sX = 0; swipe_det.sY = 0; swipe_det.eX = 0; swipe_det.eY = 0;
  var min_x = 30;  //min x swipe for horizontal swipe
  var max_x = 30;  //max x difference for vertical swipe
  var min_y = 50;  //min y swipe for vertical swipe
  var max_y = 60;  //max y difference for horizontal swipe
  var direc = "";
  ele = document.getElementById(el);
  ele.addEventListener('touchstart',function(e){
    var t = e.touches[0];
    swipe_det.sX = t.screenX; 
    swipe_det.sY = t.screenY;
  },false);
  ele.addEventListener('touchmove',function(e){
    e.preventDefault();
    var t = e.touches[0];
    swipe_det.eX = t.screenX; 
    swipe_det.eY = t.screenY;    
  },false);
  ele.addEventListener('touchend',function(e){
    //horizontal detection
    if ((((swipe_det.eX - min_x > swipe_det.sX) || (swipe_det.eX + min_x < swipe_det.sX)) && ((swipe_det.eY < swipe_det.sY + max_y) && (swipe_det.sY > swipe_det.eY - max_y) && (swipe_det.eX > 0)))) {
      if(swipe_det.eX > swipe_det.sX) direc = "r";
      else direc = "l";
    }
    //vertical detection
    else if ((((swipe_det.eY - min_y > swipe_det.sY) || (swipe_det.eY + min_y < swipe_det.sY)) && ((swipe_det.eX < swipe_det.sX + max_x) && (swipe_det.sX > swipe_det.eX - max_x) && (swipe_det.eY > 0)))) {
      if(swipe_det.eY > swipe_det.sY) direc = "d";
      else direc = "u";
    }

    if (direc != "") {
      if(typeof func == 'function') func(el,direc);
    }
    direc = "";
    swipe_det.sX = 0; swipe_det.sY = 0; swipe_det.eX = 0; swipe_det.eY = 0;
  },false);  
}

function myfunction(el,d) {
  alert("you swiped on element with id '"+el+"' to "+d+" direction");
}

To use the function just use it like

detectswipe('an_element_id',myfunction);

detectswipe('an_other_element_id',my_other_function);

If a swipe is detected the function "myfunction" is called with parameter element-id and "l,r,u,d" (left,right,up,down).

Example: http://jsfiddle.net/rvuayqeo/1/


I (UlysseBN) made a new version of this script based on this one which use more modern JavaScript, it looks like it behaves better on some cases. If you think it should rather be an edit of this answer let me know, if you are the original author and you end up editing, I'll delete my answer.

Septi answered 24/11, 2014 at 22:6 Comment(8)
Thank you. I'd recommend to set min_x dynamically: min_x = Math.abs(swipe_det.eY - swipe_det.sY). Analog for other direction. Cause when you swipe 400px up and only 40px right, you probably intend to swipe up. However, your code would recognize a right swipe.Unamuno
@Septi I like your solution to swipe detection. But it incorrectly identifies single and double taps as swipes. How would I go about fixing that?Charis
I've made some updates to the script, javascript 1.8 and some logic changes. For instance, you don't really need min_x, max_x, min_y and max_y if you use deltas. Also it will be more precise to choose between vertical and horizontal by comparing deltas (abs((eX - sX) / (eY - sY)). You can see my fork here. If this comment gets enough upvotes (say 5) I'll edit the answer.Efficacy
I still can't believe that native jQuery doesn't have a proper swipe event handling. Thank you thoughtful soul for posting this code!Ichinomiya
@UlysseBN can u please edit and update the answer with correct code? escapeNetscape i used your code, but when i do swipe left or right, i get this error in JS console google chrome, swipe works, but how to get rid of this error? Intervention] Unable to preventDefault inside passive event listener due to target being treated as passive chromestatus.com/features/5093566007214080Trice
@Trice unfortunately jsfiddle has been down for a few hours (status.jsfiddle.net). I'll update when it is back up...Efficacy
@Trice jsfiddle is back on tracks. Since it was a full re-writting, I made my own answer: https://mcmap.net/q/350047/-how-to-implement-swipe-gestures-for-mobile-devices. Hope it will come in handy!Efficacy
Is it possible to detect that we can swipe up but cant move the screen up anymore, that is we have reached the top? I am trying to solve a problem where I cant detect scroll on the page, but can detect swipe thanks to your logic, but I need to find whether I cant move up anymore on swipe, that is the top part of a container element is in view.Avalokitesvara
A
28

Have you tried Hammerjs? It supports swipe gestures by using the velocity of the touch. http://eightmedia.github.com/hammer.js/

Amative answered 28/2, 2013 at 11:53 Comment(3)
I used quojs.tapquo.com. It worked well. Heard many positives about HammerJS, would try that in some other project. Thanks for your response.Agone
I wrote up a simple service wrapping Hammerjs. Works great with Angular.Twentytwo
Thanks for the recommendation! hammerjs works with the current version of JQuery without having to migrate jquery.mobile. No warnings, no errors. NICE!Thema
A
8

There is also an AngularJS module called angular-gestures which is based on hammer.js: https://github.com/wzr1337/angular-gestures

Anguilla answered 14/6, 2013 at 12:19 Comment(0)
E
6

Shameless plug I know, but you might want to consider a jQuery plugin that I wrote:

https://github.com/benmajor/jQuery-Mobile-Events

It does not require jQuery Mobile, only jQuery.

Execute answered 26/2, 2013 at 8:45 Comment(1)
Nice plugin so far, since I had a problem with jquery mobile!Rostock
E
6

NOTE: Greatly inspired by EscapeNetscape's answer, I've made an edit of his script using modern javascript in a comment. I made an answer of this due to user interest and a massive 4h jsfiddle.net downtime. I chose not to edit the original answer since it would change everything...


Here is a detectSwipe function, working pretty well (used on one of my websites). I'd suggest you read it before you use it. Feel free to review it/edit the answer.

// usage example
detectSwipe('swipeme', (el, dir) => alert(`you swiped on element with id ${el.id} to ${dir} direction`))

// source code

// Tune deltaMin according to your needs. Near 0 it will almost
// always trigger, with a big value it can never trigger.
function detectSwipe(id, func, deltaMin = 90) {
  const swipe_det = {
    sX: 0,
    sY: 0,
    eX: 0,
    eY: 0
  }
  // Directions enumeration
  const directions = Object.freeze({
    UP: 'up',
    DOWN: 'down',
    RIGHT: 'right',
    LEFT: 'left'
  })
  let direction = null
  const el = document.getElementById(id)
  el.addEventListener('touchstart', function(e) {
    const t = e.touches[0]
    swipe_det.sX = t.screenX
    swipe_det.sY = t.screenY
  }, false)
  el.addEventListener('touchmove', function(e) {
    // Prevent default will stop user from scrolling, use with care
    // e.preventDefault();
    const t = e.touches[0]
    swipe_det.eX = t.screenX
    swipe_det.eY = t.screenY
  }, false)
  el.addEventListener('touchend', function(e) {
    const deltaX = swipe_det.eX - swipe_det.sX
    const deltaY = swipe_det.eY - swipe_det.sY
    // Min swipe distance, you could use absolute value rather
    // than square. It just felt better for personnal use
    if (deltaX ** 2 + deltaY ** 2 < deltaMin ** 2) return
    // horizontal
    if (deltaY === 0 || Math.abs(deltaX / deltaY) > 1)
      direction = deltaX > 0 ? directions.RIGHT : directions.LEFT
    else // vertical
      direction = deltaY > 0 ? directions.UP : directions.DOWN

    if (direction && typeof func === 'function') func(el, direction)

    direction = null
  }, false)
}
#swipeme {
  width: 100%;
  height: 100%;
  background-color: orange;
  color: black;
  text-align: center;
  padding-top: 20%;
  padding-bottom: 20%;
}
<div id='swipeme'>
  swipe me
</div>
Efficacy answered 5/11, 2019 at 20:50 Comment(2)
i have seen your code, but i dont find much difference between this and the original answer. can you please explain what changes you did? My app is used by people on old and new browsers, so i dont think modern JS which is in your answer will work on all browsers. BTW, when i did comment the line e.preventDefault(); in the original answer, the error seems to have gone, Do i need this line, or i can leave it as commented? Please confirm me. the div where i am adding swipe does not need to have horizontal scrolling, so i think i should be ok if i comment that line, please confirm me .Trice
Is it possible to detect that we can swipe up but cant move the screen up anymore, that is we have reached the top? I am trying to solve a problem where I cant detect scroll on the page, but can detect swipe thanks to your logic, but I need to find whether I cant move up anymore on swipe, that is the top part of a container element is in view.Avalokitesvara
M
2

Hammer time!

I have used Hammer JS and it work with gesture. Read details from here: https://hammerjs.github.io/

Good thing that it is much more light weight and fast then jQuery mobile. You can test it on their website as well.

Miaow answered 18/8, 2017 at 7:40 Comment(1)
Isn't this plugging the same lib as the answer above posted 4 years earlier in 2013?Debi
C
2

I like your solution and implemented it on my site - however, with some little improvements. Just wanted to share my code:

function detectSwipe(id, f) {
    var detect = {
        startX: 0,
        startY: 0,
        endX: 0,
        endY: 0,
        minX: 30,   // min X swipe for horizontal swipe
        maxX: 30,   // max X difference for vertical swipe
        minY: 50,   // min Y swipe for vertial swipe
        maxY: 60    // max Y difference for horizontal swipe
    },
        direction = null,
        element = document.getElementById(id);

    element.addEventListener('touchstart', function (event) {
        var touch = event.touches[0];
        detect.startX = touch.screenX;
        detect.startY = touch.screenY;
    });

    element.addEventListener('touchmove', function (event) {
        event.preventDefault();
        var touch = event.touches[0];
        detect.endX = touch.screenX;
        detect.endY = touch.screenY;
    });

    element.addEventListener('touchend', function (event) {
        if (
            // Horizontal move.
            (Math.abs(detect.endX - detect.startX) > detect.minX)
                && (Math.abs(detect.endY - detect.startY) < detect.maxY)
        ) {
            direction = (detect.endX > detect.startX) ? 'right' : 'left';
        } else if (
            // Vertical move.
            (Math.abs(detect.endY - detect.startY) > detect.minY)
                && (Math.abs(detect.endX - detect.startX) < detect.maxX)
        ) {
            direction = (detect.endY > detect.startY) ? 'down' : 'up';
        }

        if ((direction !== null) && (typeof f === 'function')) {
            f(element, direction);
        }
    });
}

Use it like:

detectSwipe('an_element_id', myfunction);

Or

detectSwipe('another_element_id', my_other_function);

If a swipe is detected the function myfunction is called with parameter element-id and 'left', 'right', 'up' oder 'down'.

Contortionist answered 4/2, 2018 at 13:26 Comment(1)
Well spotted! Thanks, changed the condition.Contortionist
N
0

I looked at several solutions but all failed with scroll and select text being the biggest confusion. Instead of scrolling right I was closing boxes and such.

I just finished my implementation that does it all for me.

https://github.com/webdevelopers-eu/jquery-dna-gestures

It is MIT so do what you want - and yes, it is really simple - 800 bytes minified. You can check it out on my (under-development) site https://cyrex.tech - swiperight on touch-devices should dismiss popup windows.

Nadda answered 4/2, 2020 at 21:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.