44

i'm trying to implement a touch listener for tablets to trigger some actions depending whether it touchmoved upwards or downwards.

I tried the native listener:

($document).bind('touchmove', function (e)
{
    alert("it worked but i don't know the direction");
});

But i don't know how to determine the direction.

Is this possible?

Or do i need to use touchstart/touchend, if I need this can I determine the direction before the touch movement stops?

If I can only do this with an external library, what's the best one?

thanks.

Ricardo A.
  • 685
  • 2
  • 8
  • 35
madprops
  • 3,909
  • 5
  • 34
  • 42

5 Answers5

72

I had some issues in Ipad and solved it with two events

var ts;
$(document).bind('touchstart', function (e){
   ts = e.originalEvent.touches[0].clientY;
});

$(document).bind('touchend', function (e){
   var te = e.originalEvent.changedTouches[0].clientY;
   if(ts > te+5){
      slide_down();
   }else if(ts < te-5){
      slide_up();
   }
});
Aureliano Far Suau
  • 6,531
  • 2
  • 22
  • 25
45

You need to save the last position of the touch, then compare it to the current one.
Rough example:

var lastY;
$(document).bind('touchmove', function (e){
     var currentY = e.originalEvent.touches[0].clientY;
     if(currentY > lastY){
         // moved down
     }else if(currentY < lastY){
         // moved up
     }
     lastY = currentY;
});
Andy
  • 29,707
  • 9
  • 41
  • 58
24

Aureliano's answer seems to be really accurate, but somehow it didn't work for me, so giving him the credits I decided to improve his answer with the following:

var ts;
$(document).bind('touchstart', function(e) {
    ts = e.originalEvent.touches[0].clientY;
});

$(document).bind('touchmove', function(e) {
    var te = e.originalEvent.changedTouches[0].clientY;
    if (ts > te) {
        console.log('down');
    } else {
        console.log('up');
    }
});

I simply changed the 'touchend' event for 'touchmove'

user3666197
  • 1
  • 6
  • 50
  • 92
Juan Herrera
  • 810
  • 1
  • 10
  • 16
  • 2
    This IS the answer. It's the best solution. The problem with Aureliano's answer is that you must lift your finger to trigger the touchend. With this solution, the user can either lift their finger, OR keep swiping without lifting their finger, and it will continue to listen and trigger your code as they do, allowing your code to be more responsive. – Blair Connolly Jun 19 '20 at 13:39
3

I have created a script that will ensure an element within your document will scroll without scrolling anything else, including the body. This works in a browser as well as a mobile device / tablet.

// desktop scroll
$( '.scrollable' ).bind( 'mousewheel DOMMouseScroll', function ( e ) {
    var e0 = e.originalEvent,
    delta = e0.wheelDelta || -e0.detail;

    this.scrollTop += delta * -1;
    e.preventDefault();
});

var lastY;
var currentY;

// reset touch position on touchstart
$('.scrollable').bind('touchstart', function (e){
    var currentY = e.originalEvent.touches[0].clientY;
    lastY = currentY;
    e.preventDefault();
});

// get movement and scroll the same way
$('.scrollable').bind('touchmove', function (e){
    var currentY = e.originalEvent.touches[0].clientY;
    delta = currentY - lastY;

    this.scrollTop += delta * -1;
    lastY = currentY;
    e.preventDefault();
});
2

This solution takes into account change in directions which the current answers does not. The solution below also takes care of touch sensitivity; this when the user is moving in one direction but on touch end the users finger nudges in a different direction messing up the actual direction.

 var y = 0; //current y pos
 var sy = y; //previous y pos
 var error = 5; //touch sensitivity, I found between 4 and 7 to be good values. 

 function move(e) {
    //get current y pos
    y = e.pageY;

    //ingnore user jitter
    if (Math.abs(y - sy) > error) {
        //find direction of y
        if (y > sy) {
            //move down 
        } else {
            //move up
        }
        //store current y pos
        sy = y;
    }
}
manish
  • 497
  • 9
  • 17
  • Most browsers already implement something like a debounced handler for touch events, so you'll always have that conditional as true. – Frondor Aug 13 '18 at 19:01