Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Crossing over to new elements during touchmove

I'd like to make it so that as you drag your finger over a set of elements, the background of the one you've got your finger on changes.

It seems like I want to use the touchmove event for this, but as far as I can tell the target element never changes, even as you drag around. The clientX and clientY do change, and I found this document.elementFromPoint function that works in chrome, but seems very roundabout (plus I'm not sure which browsers support it)

See this fiddle, I want the boxes to turn green as you touch through them:

http://jsfiddle.net/QcQYa/9/

By the way, in chrome, you'll need to go into the user agent tab of the inspector config modal and choose "emulate touch events" to see my example.

Edit: I found an idea to use mouseenter here How to detect html elements on touchmove and got it to work on desktop chrome, but not on mobile safari.

like image 875
spike Avatar asked Sep 12 '12 21:09

spike


3 Answers

I took a different approach:

Every touch event I check if the touch position is inside a $('.catch') object.

function highlightHoveredObject(x, y) {
    $('.catch').each(function() {
      // check if is inside boundaries
      if (!(
          x <= $(this).offset().left || x >= $(this).offset().left + $(this).outerWidth() ||
          y <= $(this).offset().top  || y >= $(this).offset().top + $(this).outerHeight()
      )) {

        $('.catch').removeClass('green');
        $(this).addClass('green');
      }
    });
}

You can see it working on jsFiddle.
It works on Chrome, I hope it also does on mobile devices.

Edit:
In this fiddle I used both versions, mine and that one from the link in the comments (document.elementFromPoint – a jQuery solution), both seem to work on my Android phone. I also added a quick and dirty benchmark (see console) and as expected document.elementFromPoint is a few thousandth faster, if that is your concern you should check the support of document.elementFromPoint for the browsers you want to support.

like image 65
dan-lee Avatar answered Nov 07 '22 14:11

dan-lee


You'll find my solution in this fiddle , I tested it on my android phone and it works fine, it uses jquerymobile to take advantage of vmousemove event, it also attachs a handler to touchmove event just to prevent scrolling the browser view on the mobile device.

I paste here the relevant HTML and javascript bits:

<div id="main" ontouchmove="touchMove(event);">
   <span class='catch'>One</span>
   <span class='catch'>Two</span>
   <span class='catch'>Three</span>
   <span class='catch'>Four</span>
   <span class='catch'>Five</span>
   <span class='catch'>Six</span>
   <span class='catch'>Seven</span>
</div>

now the javascript:

function elem_overlap(jqo, left, top) {
   var d = jqo.offset();
   return top >= d.top && left >= d.left && left <= (d.left+jqo[0].offsetWidth)
          && top <= (d.top+jqo[0].offsetHeight);
}

/* To prevent WebView from scrolling on swipe, see http://goo.gl/DIZbm */
touchMove = function(event) {
   event.preventDefault(); //Prevent scrolling on this element
}

$("#main").bind("vmousemove", function(evt){
   $('.catch').each(function(index) {
      if ( elem_overlap($(this), evt.pageX, evt.pageY) ) {
         $('.catch').not('eq('+index+')').removeClass('green');
         if (!$(this).hasClass('green')) {
            $(this).addClass('green');
         }
      }
   });
});
like image 2
Nelson Avatar answered Nov 07 '22 13:11

Nelson


You can't "trigger a touchend event" or cancel touches, which you would need to start touching another.

So you would be better off binding the touchmove event to the container, and manipulating the boxes based on their position/sizes and the touch position, like what part of Dan Lee's answer does.

like image 1
Jaibuu Avatar answered Nov 07 '22 13:11

Jaibuu