c69
c69

Reputation: 21497

Safari iPad 1: how to disable zoom/centering on double-tap, but keep pinch zoom

I wonder if its possible to prevent double-tap-to-zoom and double-tap-to-center on a specific HTML element in Safari iOS (iPad 1) ?

Because my small HTML5 game forces users to make fast clicks (or taps), which are interpreted as double clicks, and when it happens - the page changes zoom and centers itself.

Detecting double clicks (like in this answer - Safari iPad : prevent zoom on double-tap) smells bad..

Wrong answer #1: <meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"> - does not suit my purposes, because it will block any zoom.

Wrong answer #2: maybe would .preventDefault() on click event alone be enough for that ? - Does not have any effect.

Upvotes: 10

Views: 30042

Answers (8)

amenthes
amenthes

Reputation: 3346

I am preventing doubletaps like this:

var doubleTouchStartTimestamp = 0;
$(document).bind("touchstart", function (event) {
    var now = +(new Date());
    if (doubleTouchStartTimestamp + 500 > now) {
        event.preventDefault();
    }
    doubleTouchStartTimestamp = now;
});

The elegance lies within the fact, that no timeouts are needed. I only update a timestamp. It only gets compared on the next touchstart. Works for me on iOS 6.

Doubletaps further down the dom are not affected.

The same works without jQuery, as well:

var doubleTouchStartTimestamp = 0;
document.addEventListener("touchstart", function (event) {
    var now = +(new Date());
    if (doubleTouchStartTimestamp + 500 > now) {
        event.preventDefault();
    }
    doubleTouchStartTimestamp = now;
});

Upvotes: 7

Paul Styles
Paul Styles

Reputation: 150

JQuery approach to disable Double Tap Zoom in MVC4 To Disable the double tap (double mouse down) functionality on iOS 1+ you need to catch the touchStart Event and create an override to prevent the zoom.

// Using Single script.js and JQuery.Mobile-1.2.0 UI each page in MVC gets assigned JQuery through delegates so you don't have to do a full refresh of the page allowing you to take advantage of the data-prefetch which loads the page in the DOM when the app loads for the first time

$(document).delegate("#CashRegister", "pageinit", function () {

// To Disable 'Pinch to Zoom' Note: don't implement gester event handlers if you want to 
//keep pinch to zoom functionality NOTE: i use this as my pageinit is a delegate of a page
this.addEventListener("gesturestart", gestureStart, false);
this.addEventListener("gesturechange", gestureChange, false);
this.addEventListener("gestureend", gestureEnd, false);
//handle each event by disabling the defaults
function gestureStart(event) {
    event.preventDefault();
}

function gestureChange(event) {
    event.preventDefault();
}

function gestureEnd(event) {
    event.preventDefault();
}
//Recreate Double Tap and preventDefault on it
$(this).bind('touchstart', function preventZoom(e) {
// recreate the double tab functionality
        var t2 = e.timeStamp
      , t1 = $(this).data('lastTouch') || t2
      , dt = t2 - t1
      , fingers = e.originalEvent.touches.length; 
        $(this).data('lastTouch', t2);
        if (!dt || dt > 500 || fingers > 1) return; // not double-tap 
        e.preventDefault(); // double tap - prevent the zoom
        // also synthesize click events we just swallowed up
        $(this).trigger('click').trigger('click');
    });

Upvotes: 0

ecmanaut
ecmanaut

Reputation: 5150

I wrote a jQuery plugin for the same purpose - selectively disabling double-tap zoom on given page elements (in my case, navigation buttons to flip pages) I want to respond to every tap (including double-tap) as a normal click event, with no iOS "touch magic", no matter how fast the user clicks it.

To use it, just run something like $('.prev,.next').nodoubletapzoom(); on the elements you care for. The principle it uses is to listen for consecutive touchstart events on a node within 500ms, and running event.preventDefault() on the second, unless other touches are active at the same time. As that preventDefault consumes both touches, we also synthesize the two "missed" click events for the node, so your intended touch action happens as many times as the user intended.

Upvotes: 6

weisjohn
weisjohn

Reputation: 803

Actually, .preventDefault() definitely does work... using jQuery:

var InputHandler = {    
    startEventType : isTouch ? "touchstart" : "mousedown"
}

$(selector).bind(InputHandler.startEventType, function(evnt) {
    evnt.preventDefault();
});

Your problem with trying to prevent on .click() is that the browser isn't throwing a "click" element. Safari only fires a click to help simulate a click... But when there's a double tab, Safair doesn't through a "click" element. Your event handler for .click() doesn't ever fire, and therefore the .preventDefault() doesn't fire either.

Upvotes: -1

Brett Pontarelli
Brett Pontarelli

Reputation: 1728

You will need to implement a double tap function and preventDefault on the second tap. Here is some tested code that uses global variables that should get you started:

<button id="test1">Double Tap Me!</button>
<div id="test2">EMPTY</div>

var elm1 = document.getElementById('test1');
var elm2 = document.getElementById('test2');
var timeout;
var lastTap = 0;
elm1.addEventListener('touchend', function(event) {
    var currentTime = new Date().getTime();
    var tapLength = currentTime - lastTap;
    clearTimeout(timeout);
    if (tapLength < 500 && tapLength > 0) {
        elm2.innerHTML = 'Double Tap';
        event.preventDefault();
    } else {
        elm2.innerHTML = 'Single Tap';
        timeout = setTimeout(function() {
            elm2.innerHTML = 'Single Tap (timeout)';
            clearTimeout(timeout);
        }, 500);
    }
    lastTap = currentTime;
});

And a fiddle: http://jsfiddle.net/brettwp/J4djY/

Upvotes: 0

MattiSG
MattiSG

Reputation: 4006

There's no other way than catching the events you want to prevent, and call preventDefault() on them, as you had already more or less figured out.

Indeed, some particular CSS properties / values may change the global site behavior (fixed width or fixed, for example), but you're not safe from changes to the OS (see fixedhandling change in iOS5), nor do these changes necessarily prevent all behavior (pinch might be off, but not double-tapping).

So, the best way to disable default behavior only for double-tapping is to take advantage of the count of touches iOS provides: if we have only one contact, then we're tapping. Two, this means we're pinching.

The following setup code provides that functionality:

var elm = document.body; // or some selection of the element you want to disable

var catcher = function(evt) {
    if (evt.touches.length < 2)
        evt.preventDefault();
};

elm.addEventListener('touchstart', catcher, true);

Demo on jsFiddle.

Note: the third parameter (true) to addEventListener means that we want to capture events, that is catch them all, even for our descendant children.

Upvotes: 9

master_gracey
master_gracey

Reputation: 354

What iOS version/Safari browser are you using? That site most definitely does not let you double-tap. I found some CSS but haven't had time to try it as I'm about to step out:

body {
  -webkit-text-size-adjust:none;
  margin:0px;
}

div{
  clear:both!important;
  display:block!important;
  width:100%!important;
  float:none!important;
  margin:0!important;
  padding:0!important;
}

Upvotes: 0

master_gracey
master_gracey

Reputation: 354

Apple has a lot of tips with specialized tags for webkit (Safari). View Official Docs

Upvotes: 0

Related Questions