0

I'm handling touch events on a <canvas> area (using jQuery). I'd like to only handle single touch events, leaving multiple touch events uncancelled (e.g. so you can pinch-and-zoom).

The problem is that no matter how simultaneous the touches are, I get a touchstart with one point, followed by a touchmove with one point, and finally a touchstart with 2 points.

If I cancel the first touchdown event with preventDefault(), there's no zooming, even if I don't cancel after the touchmove nor the second touchdown.

If I don't preventDefault() on that first event, then touchmove events will scroll the page up and down in addition to my handling of the touch movement.

(testing on Android 8.1.0 - Samsung Galaxy Tab A)

I've looked around at various postings and web searches, e.g.: jquery preventdefault on first touch only or How to prevent default handling of touch events? or Javascript support for touch without blocking browsers pinch support

... and while not specific to this situation, I get the feeling that I'm out of luck. Seems a shortcoming of touch event handling, however, insofar as it makes multiple touches impossible to detect on the first event.

------------ EDIT -----------

Thanks for the suggestions folks! I do hope someone finds the answer useful, but unfortunately it doesn't fit my purposes, and I thought I should explain why (superfluous, perhaps, but may provide someone more insight).

To give some background, this is for a reusable module that provides an API for elements, including drawing 'sprites' and handling mouse/touch events like 'down', 'up', 'drag', etc. As such, I need to consider pros and cons carefully in the context of reusability and clarity.

The solutions mentioned here, and all others that I've found or indeed can conceive of, require a delay. There are two problems with this:

  1. The minor problem is that any delay-based implementation of "multiple touch" is subjective. Multiple-touching is not timed out — you can theoretically touch with one finger, take a leisurely sip of your coffee (presumably with your other hand), then touch with another finger, and still be able to (e.g.) zoom. If this were the only problem, I could probably live with a pre-determined time-out, but it would be based on my perception of users' habits. (I could forsee, for instance, someone touching a 'sprite' over a dense background like a geographical map, realizing there's some detail they want to focus on, and then trying to zoom in.)

  2. If I did delay on down, say by choosing a 300ms delay, it becomes a bit of a rabbit hole. A lot can happen in about a third of a second; likely, they could start a 'sprite' drag. There are then two choices:

If I wait to make sure it's a single touch, I miss (or cache) at least one 'move' event, and all dragging would then show a slight hesitation at the start. A third of a second is well within the bounds of perceptibility, so this is unacceptable.

Or, I could detect slight movement and assume that it's the start of a motion gesture like dragging. I'd then have to raise the API's 'down' and 'move' events simultaneously, a distasteful twiddle but again tolerable. More ambiguous is the threshold for determining it's actual motion. A very steady touch can easily get 4-6 pixels of movement on a touch screen, and I've seen well over 12 pixels for shaky touches. The gap could well be large enough to show an unseemly jitter.

As you can imagine, this is already a very processor-intensive module, especially problematic on mobile devices. Considering the increased code complexity and size (and further divergence of mouse vs touch event code paths), the possible need to introduce several tweakable settings that may be rather opaque to the user, and the fact that any solution is a compromise (point 1), I've decided that the least bad choice is to live with this limitation. The highest priorities here are smooth graphics handling and lean code (both size and processor intensiveness).

So at this point I'm willing to forego multiple touch gestures on the element. Zooming outside the element works fine, and is not unexpected behaviour — witness Google Maps.

For simpler applications, it should often be acceptable to delay detection of 'touchdown' to check for further touches.

dhc
  • 647
  • 8
  • 17

1 Answers1

0

Add a timer for your second tap in the middle of your first tap function.

For example:

$(myzone).touchstart(function(e){
   e.preventDefault();
   $(myzone).bind('touchstart',myeventTouch)
   action = setTimeout(function(e){
       $(myzone).unbind('touchstart',myeventTouch) 
       clearTimeout(action); 
   }, 500);
})

function myeventTouch(){
 //When double tap do..
}

If you don't want to do this, you can also add a jQuery plugin in your page, for example I searched for one and found jquery.doubletap.js https://gist.github.com/attenzione/7098476

Use this:

$(SELECTOR).on('doubletap',function(event){
alert('doubletap');
});
Jordi Castillo
  • 683
  • 1
  • 5
  • 13
  • I've thought of that, but is there a known interval at which this is reasonable? (It also gets messy, insofar as I have to unbind the event, and then rebind it each time) – dhc Mar 14 '19 at 19:44
  • 500 like in example is well, you can try it and adjust for your needs – Jordi Castillo Mar 14 '19 at 19:45
  • Yeah, but I'm not the only user ;)... maybe no other solution, but again it's messy – dhc Mar 14 '19 at 19:45
  • Edited, the plugin which i add do the same what I said, but if you prefere to use it! – Jordi Castillo Mar 14 '19 at 19:49