12

I would like to add some multitouch features to my javascript application when it is accessed from an ios device (and maybe android later).

I want to provide a shiftkey-like functionality: the user may hold a button on the screen with one finger, and while this button is pressed, the behavior for a tap action on the rest of the screen is slightly different from the classic tap.

The problem i'm running into is that i do not receive any touchend event for the tapping finger unless a touchmove is fired for the first finger holding the shiftkey button.

Because the screen is very sensitive, touchmove events gets easily fired and in most cases everything works fine.

But when the user's finger is a bit too still, the tapping is not detected until the user moves his finger a bit. This induces a variable 'delay' between the tapping and the action that occurs on the screen (the delay may vary and last a few seconds if the user is very calm). My guess is that this delay will cause the user to tap again and thus fire the action a second time, which is something that i don't want !

You can test it here with your ipad/iphone : http://jsfiddle.net/jdeXH/8/

Try to make the body remain green for a few seconds by holding your finger very still on the cyan div while tapping on the red div.

Is this behavior to be expected ? Is there some known workaround for the problem ? I would have expected the touchend event to be fired right away when the finger is removed from the screen.

i tested this with iOS 5.1.1 (ipad1 and iphone4s)

edit: found a similar question Multitouch touchEvents not triggered as they should on Safari Mobile

Community
  • 1
  • 1
Louis
  • 397
  • 2
  • 14
  • it seems that there is a similar question here : http://stackoverflow.com/questions/8839333/multitouch-touchevents-not-triggered-as-they-should-on-safari-mobile – Louis Aug 06 '12 at 11:49
  • Great question. I hope someone can answer this. I'm running into the same exact behavior on an iphone 4 and ipad 3. For my own project I am attaching the event listener to a single containing element. This (maybe just in my imagination?) seems to improve performance slightly, but the issue's definitely there and it seems pretty sporadic: http://jsfiddle.net/seeligd/DwNd9/59/ – pho79 Aug 27 '12 at 05:30
  • @pho79, yup i agree that your version feels slightly more responsive most of the time, but sadly still not perfect.it's hard to believe that people don't use multitouch on webapps enough to have run into this problem already.. – Louis Aug 27 '12 at 09:14
  • @zaf no, i couldn't find a way to work around, so i just modified my application design for now. I'm still interested in any idea somebody might have though... If there isn't a viable solution to this problem, using _real_ multitouch in responsive webapps really seems pointless to me. – Louis Sep 10 '12 at 15:52
  • @dridri Yeah, I just spent nearly a full day trying to debug this. A real PITA. Time to change the design as well.... – zaf Sep 10 '12 at 16:23

4 Answers4

3

Well, it appears that the bug bothered some people more than me, they filed a bug directly to apple, and after a few years it is now fixed in iOS6 :)

Louis
  • 397
  • 2
  • 14
1

Okay this is a headache. Yes, there are two known issues. First of all, Safari sometimes doesn't bother firing the touchEnd event unless there is a touchMove somewhere, even if the touchMove doesn't really do much.

second, Chrome Mobile is a lovely experience as well, as on many Android devices the touchEnd event does not fire at all, regardless of what you do. So from my experience:

  • Implement a touchStart event which registers the start coordinate, etc
  • Implmenet a touchMove event which does the exact same thing as the touchEnd, but make sure the callback doesn't fire more than once. Use a boolean flag defined in a higher scope or something like that.
  • Implement the normal touchEnd event which should only fire if touchMove hasn't already fired the callback, using the same boolean flag defined in a higher scope.
flavian
  • 28,161
  • 11
  • 65
  • 105
0

Ok, I have implemented this solution and it seems to work.

//Initialize the tap touch
function ManageTapTouch() {
    this.__enabled__ = false;
}

ManageTapTouch.prototype.init = function(){
    $("#hold").bind('touchstart', $.proxy(this.__enable__, this));
    $('#hold').bind('touchend', $.proxy(this.__disable__, this));
    $('#tap').bind('touchstart',  $.proxy(this.__changeColorOnHold__, this));
    $('#tap').bind('touchend',  $.proxy(this.__changeColorOnOut__, this));
};
ManageTapTouch.prototype.__enable__ = function(event) {
    this.__enabled__ = true;
};
ManageTapTouch.prototype.__disable__ = function(event) {
    this.__enabled__ = false;
    $('body').css('background-color', 'blue'); 
};
ManageTapTouch.prototype.__changeColorOnHold__ = function(event) {
    if (this.__enabled__){
        $('body').css('background-color', 'black');
    }
};
ManageTapTouch.prototype.__changeColorOnOut__ = function(event) {
    $('body').css('background-color', 'blue');
};

new ManageTapTouch().init();

You can see it running here: http://jsfiddle.net/Tb6t6/15/

Also you can try another way on the iPhone using multitouch with: event.originalEvent.touches[0].pageX and event.originalEvent.touches[0].pageY where the index is the finger on the screen and event is the event fired on TouchStart. With this topics you can implement your own version of this action or use the one I propose here.

biegleux
  • 13,179
  • 11
  • 45
  • 52
droidpl
  • 5,872
  • 4
  • 35
  • 47
  • i'm sorry, but i can't see how your answer solved the problem, the code is roughly doing the same thing, and I still experience some 'lags' when i pull my finger off the screen.. is there something i'm missing here ? – Louis Sep 18 '12 at 07:50
  • What kind of lag are you experimenting? What is exactly not working? And what is your device? I tried with an HTC Desire S on the Chrome browser (Android 4.0) and iPhone but everithing works! The touchEnd is always called – droidpl Sep 21 '12 at 10:58
  • well, i have no idea how this behave on other devices as i am only interested in ios devices for this javascript application. Of course the touchend is always called, but not necessarily immediately i.e. only after another event (it's often touchmove) is fired. This induce the 'lag' between the actual removal of the finger from the screen and the firing of the touchend. In your demo, it causes the background to stay black even after the finger that was touching the red div is removed. In fact it will stay black until you move(slightly)/remove the first finger touching the cyan div. – Louis Sep 21 '12 at 11:16
  • Ok, I checked it. Your problem is related to the focus. When you select one div and your focus is not centered to the div but centered to the overflow layer your event is not displayed. I mean, the pinch event on iOs navigator that gives the functionality of zoom, makes the event not fired until you recover the focus on the div selected. Try to manage the pinch event and on executed refocus the divs or change the behaviour of your window using device-width meta parameter. – droidpl Sep 22 '12 at 13:43
  • actually, in my fiddle the event that makes iOS provide a zoom feature is disabled by returning false. It was worth a shot trying to refocus the div, but i still do get the random lag, maybe you could provide some code if you managed to make it work properly. – Louis Sep 24 '12 at 09:13
0

So it appears you have reached one of those scenarios which cannot be avoided and will only have buggy hacks. You are creating a UI feature which is not quite the "norm" yet, but seems to have some promise (I like... I like). The question to ask yourself at this point in technology is "how can I force the user to slide his finger in order to hold shift".

With the help of a good designer I think you could create a sliding toggle button similar to a flip switch... where a user must drag and hold to turn the switch "on". Upon release, the switch would spring back to the "off" position. I mention a designer because the button needs to look like it behaves. Maybe some of the comments can get creative.

Ryan Wheale
  • 26,022
  • 8
  • 76
  • 96