14

Prelim caveat: I am very new to js and have mainly gotten by through doing web searches for examples/tutorials.

I am writing js which should run both on web and on mobile devices (e.g. iPad).

We have a library to help abstract away the differences between mouse and touch:

if (navigator.userAgent.search('Mobile') > 0) {
  window.FLAGS = {
    start: 'touchstart',
    end: 'touchend',
    move: 'touchmove',
    click: 'click',
    touchScreen: true
  };
} else {
  window.FLAGS = {
    start: 'mousedown',
    end: 'mouseup',
    move: 'mousemove',
    click: 'click',
    touchScreen: false
  };
}

Then in code you can do things like:

widget.view.bind(FLAGS.start, function(e) {

I am trying to find a touch equivalent for mouseleave so I can do a similar trick.

I can imagine ways to catch a leave event by tracking the position on move and comparing that to bounding box of widget in question, but I'm hoping there's a little one-liner like the touchstart/mousedown relationship.

VK Da NINJA
  • 510
  • 7
  • 19
Doug Banks
  • 143
  • 1
  • 1
  • 4
  • If the goal is to detect the touch deactivating (i.e., no longer able to generate a click) then there are actually *two* gestures that need to be detected. (1) the touch can leave the element, and (2) the touch can time out. It's not clear whether this question covers the second case, since `mouseleave` could be interpreted as only covering the mouselike gesture. Understandably so, since the second case was apparently broken between 2015 and 2022. Therefore I've opened a [new question](https://stackoverflow.com/questions/74844072/chrome-mobile-108-touchcancel-not-firing) about the second case. – personal_cloud Dec 18 '22 at 20:34

3 Answers3

23

It's been suggested, but not implemented AFAIK: http://www.quirksmode.org/mobile/advisoryTouch.html

Something like this might work (writing it from top of my head, untested):

var element;
document.addEventListener('touchstart', function(event) {
    event.preventDefault();
    var touch = event.touches[0];
    element = document.elementFromPoint(touch.pageX,touch.pageY);
}, false);

document.addEventListener('touchmove', function(event) {
    event.preventDefault();
    var touch = event.touches[0];
    if (element !== document.elementFromPoint(touch.pageX,touch.pageY)) {
        touchleave();
    }
}, false);

function touchleave() { 
    console.log ("You're not touching the element anymore");
}
Aleadam
  • 40,203
  • 9
  • 86
  • 108
  • 1
    Thank you. I think the bit about "not implemented" is what I needed to hear, and I doubly appreciate the sample code for a workaround. – Doug Banks Apr 21 '11 at 21:46
  • 1
    your post is old but - shouldn't it be "changedTouches" for the touchmove-event? at least on ipads the touches array is undefined onTouchMove - compare http://stackoverflow.com/a/7236327/818732 – Jörn Berkefeld Jul 14 '12 at 11:51
  • `if (element !== document.elementFromPoint(touch.pageX,touch.pageY)) { touchleave(); }` might not work if the target element has nested elements in it too because `elementFromPoint(x, y)` returns the most nested element containing the coordinates x, y. – oomer Jan 08 '22 at 22:25
0

might want to check out the jquery touchable plugin.

Anony372
  • 494
  • 2
  • 15
0

The whole idea about triggering touch leave is that we need to get the range of the element.

for example, the box width range starts from 0 to actual width, and the box height range starts from 0 to actual height

so if X, Y values are between this range then we are inside the box and if other than that then we left the box.

check this snippet for better clarifying.

// select the box that we will leave
const box = document.getElementById('box');

// add touchmove event to the box
box.addEventListener('touchmove', (e) => {
    // stop default behavior
    e.stopPropagation();
    e.preventDefault();
    e = e || window.event;

    // get box properties
    let a = box.getBoundingClientRect();
    // get current width
    let w = a.width;
    // get current height
    let h = a.height;

    // get values on x axis
    const x = e.touches[0].pageX - a.left; // to start the value from 0 (remove offsetleft)
    // get values on y axis
    const y = e.touches[0].pageY - a.top; // to start the value from 0 (remove offsettop)

    //! INFO
    // the box width range starts from [0 : w]
    // the box height range starts from [0 : h]

    // if X values between [0 , w] and Y values between [0 , h] then we inside the box | other than that then we left the box
    if ((x >= 0 && x <= w) && (y >= 0 && y <= h)) {
        console.log('in the box');
    } else {
        console.log('left the box');
    }

});
#box {
    width: 280px;
    height: 280px;
    outline: 1px solid red;
    margin: 100px auto;
}
<div id="box"></div>
Eissa Saber
  • 161
  • 1
  • 8