I'm working on a page where I have a draggable item (a map inside a container). When you click and drag with the mouse, the map moves and everything is fine. I then wanted to add the same functionality for touch devices (such as a smartphone or a tablet). I searched the net and found a working script that "changes" touch input to mouseinput and thus making it possible to drag the map without dragging the entire page (which is standard behaviour). This is done using the line
event.preventDefault()
It is even possible to have click events as well by timing how long apart the touches are. I am no coding genius and all this programming was done by others. You can see the discussion at Javascript Drag and drop for touch devices (I have used the original code in the top answer as well as the timing code in the answer just below the top answer).
So far, so good. It is now possible to drag the map around and click any links on it or the page just as you would, if you were using a mouse. This works on all touch browsers I have tried (I haven't tried a lot, but the ones I've tried work). The only problem is, that you cannot drag the page itself around, since the default behaviour of the touch has been disabled. This is a problem when the content of the page (for instance the size of the map container) is larger than the browser window.
Luckily an answer was provided for this as well (it is the bottom-most answer on the page I linked to above): replacing
event.preventDefault()
with
if (touches.length > 1) event.preventDefault();
the default scrolling/resizing etc. of a touch works if you use one finger, but if you use more than one finger, the default behaviour is prevented. In other words: If you use two fingers, you can drag the map around without dragging the page (just as before), but if you use one finger, you can drag the page around! I really like this solution as it seems quite elegant to me.
Well, I added the line and tested on the default browser on my HTC Incredible phone (way to small screen but it is what I have). The default browser is just called "Internet". Everything works perfectly! So, I test on Firefox and Opera, and unfortunately, they are not working perfectly. It seems that once the
event.preventDefault()
is inside the "if" statement, it is completely ignored, so when I drag the map, it IS dragged (as the touch is still converted to a drag of the mouse), but the page itself is also dragged, regardless of the number of fingers I use. In short: The page behaves as if no
event.preventDefault()
is triggered.
I have looked around for several hours and have come to suspect that the event variable needs to be initialized or imported for Firefox and Opera to be able to use it, as described here: jQuery event.preventDefault() not working in Firefox (JSFiddle included)
My question (at long last): Could this be right, and how do I go about "importing" the event into the "if" statement?
The code is here (the init()
function is triggered by body onload)
<script type="text/javascript">
var clickms = 400;
var lastTouchDown = -1;
function touchHandler(event)
{
var touches = event.changedTouches,
first = touches[0],
type = "";
var d = new Date();
switch(event.type)
{
case "touchstart": type = "mousedown"; lastTouchDown = d.getTime(); break;
case "touchmove": type="mousemove"; lastTouchDown = -1; break;
case "touchend": if(lastTouchDown > -1 && (d.getTime() - lastTouchDown) < clickms){lastTouchDown = -1; type="click"; break;} type="mouseup"; break;
default: return;
}
var simulatedEvent = document.createEvent("MouseEvent");
simulatedEvent.initMouseEvent(type, true, true, window, 1,
first.screenX, first.screenY,
first.clientX, first.clientY, false,
false, false, false, 0/*left*/, null);
first.target.dispatchEvent(simulatedEvent);
if (touches.length > 1)
{
event.preventDefault();
}
}
function init()
{
document.addEventListener("touchstart", touchHandler, true);
document.addEventListener("touchmove", touchHandler, true);
document.addEventListener("touchend", touchHandler, true);
document.addEventListener("touchcancel", touchHandler, true);
}
</script>
Edit: I should add that I have tried inserting an alert statement into the if statement, just to see whether Firefox or Opera actually register that a two-finger gesture is performed. The alert is triggered without problems, so perhaps the problem is that once Firefox or Opera has started a two-finger gesture, the standard behaviour of the gesture (draggring or resizing the page) cannot be stopped, at least not in this way.