checking if touchend comes after a drag

17,928

Solution 1

Use two listeners:

First set a variable to false:

var dragging = false;

Then ontouchmove set dragging to true

$("body").on("touchmove", function(){
      dragging = true;
});

Then on drag complete, check to see if dragging is true, and if so count it as a dragged touch:

$("body").on("touchend", function(){
      if (dragging)
          return;

      // wasn't a drag, just a tap
      // more code here
});

The touch end will still fire, but will terminate itself before your tap script is run.

To ensure the next time you touch it isn't already set as dragged, reset it back to false on touch down.

$("body").on("touchstart", function(){
    dragging = false;
});

Solution 2

Looks like one solution to my problem is found here:

http://alxgbsn.co.uk/2011/08/16/event-delegation-for-touch-events-in-javascript/

This bit of code detects any move after touchstart in order to abort tap behavior after tapend.

var tapArea, moved, startX, startY;

tapArea = document.querySelector('#list'); //element to delegate
moved = false; //flags if the finger has moved
startX = 0; //starting x coordinate
startY = 0; //starting y coordinate

//touchstart           
tapArea.ontouchstart = function(e) {

    moved = false;
    startX = e.touches[0].clientX;
    startY = e.touches[0].clientY;
};

//touchmove    
tapArea.ontouchmove = function(e) {

    //if finger moves more than 10px flag to cancel
    //code.google.com/mobile/articles/fast_buttons.html
    if (Math.abs(e.touches[0].clientX - startX) > 10 ||
        Math.abs(e.touches[0].clientY - startY) > 10) {
            moved = true;
    }
};

//touchend
tapArea.ontouchend = function(e) {

    e.preventDefault();

    //get element from touch point
    var element = e.changedTouches[0].target;

    //if the element is a text node, get its parent.
    if (element.nodeType === 3) { 
        element = element.parentNode;
    }

    if (!moved) {
        //check for the element type you want to capture
        if (element.tagName.toLowerCase() === 'label') {
            alert('tap');
        }
    }
};

//don't forget about touchcancel!
tapArea.ontouchcancel = function(e) {

    //reset variables
    moved = false;
    startX = 0;
    startY = 0;
};

More here: https://developers.google.com/mobile/articles/fast_buttons

Share:
17,928
Konrad Lawson
Author by

Konrad Lawson

Historian of modern Asian history and the aftermaths of modern war. Broad interests in history and the digital humanities. Strong supporter of open access and respect/encouragement of historical and other scholarship taking place outside the academy.

Updated on July 10, 2022

Comments

  • Konrad Lawson
    Konrad Lawson almost 2 years

    I have some code which changes the class of a table. On a phone, sometimes the table will be too wide for the screen and the user will drag/scroll about to see the contents. However, when they touch and drag the table around, it triggers touchend on every drag.

    How do I test to see whether the touchend came as a result of a touch-drag? I tried tracking dragstart and dragend but I couldn't get that to work and it seems an inelegant approach. Is there something I could add to below which would essentially determine, "Did this touchend come at the end of a drag?"

    $("#resultTable").on("touchend","#resultTable td",function(){ 
            $(this).toggleClass('stay');
    });
    

    My thanks in advance for your help.

    PS - using latest jquery, and while a regular click works, it is very slow in comparison to touchend.

  • Konrad Lawson
    Konrad Lawson over 11 years
    EH_warch, thanks for your answer. Hmm, my apologies here I'm not referring to dragging elements around, but to scrolling about the screen - a different kind of drag if you will. Imagine a table with 6 columns on a narrow iPhone screen. To see the last three columns, you need to touch, and move your finger to the left to see the rest of the table. However, you usually don't want that touch to be recognized by underlying elements as a tap, which with my code above, it currently what happens. How can I recognize only the tap, not tap+drag without using slow click() method (touchend much faster)
  • KoU_warch
    KoU_warch over 11 years
    Oh, ok i think you are looking for this then trott.github.com/LightningTouch/#/lightning-main
  • Konrad Lawson
    Konrad Lawson over 11 years
    Thanks for pointing that out! It looks like lightning touch includes some code that accounts for the problem, but it is 250 extra lines of code that is kind of overkill. I'm going to see if I can extract something useful out that using touchmove.
  • alex-i
    alex-i over 11 years
    in the if from touchend I believe you should also set dragging back to false. Other than that, it works nice.
  • lededje
    lededje over 11 years
    No need; the next time you touch down it will set it back to false again.
  • Michael Martin-Smucker
    Michael Martin-Smucker over 10 years
    @lededje Why would it be set back to false if you don't have any code resetting it?
  • lededje
    lededje almost 10 years
    @chris unfortunately?
  • northamerican
    northamerican almost 10 years
    i was just upset that this counter-intuitive solution is the best way to tackle the problem. your answer certainly helped and i voted for it.
  • lededje
    lededje almost 10 years
    @chris I agree this answer is filth but alas nothing better has been added to the spec :(
  • Sean T
    Sean T over 4 years
    There's loads of hacky fixes on here for this issue but this is the best answer. Safari is a joke