jQuery Drag and Drop on touch devices (iPad, Android) jQuery Drag and Drop on touch devices (iPad, Android) android android

jQuery Drag and Drop on touch devices (iPad, Android)


Paste this at the beginning of your .js file:

(function ($) {    // Detect touch support    $.support.touch = 'ontouchend' in document;    // Ignore browsers without touch support    if (!$.support.touch) {    return;    }    var mouseProto = $.ui.mouse.prototype,        _mouseInit = mouseProto._mouseInit,        touchHandled;    function simulateMouseEvent (event, simulatedType) { //use this function to simulate mouse event    // Ignore multi-touch events        if (event.originalEvent.touches.length > 1) {        return;        }    event.preventDefault(); //use this to prevent scrolling during ui use    var touch = event.originalEvent.changedTouches[0],        simulatedEvent = document.createEvent('MouseEvents');    // Initialize the simulated mouse event using the touch event's coordinates    simulatedEvent.initMouseEvent(        simulatedType,    // type        true,             // bubbles                            true,             // cancelable                         window,           // view                               1,                // detail                             touch.screenX,    // screenX                            touch.screenY,    // screenY                            touch.clientX,    // clientX                            touch.clientY,    // clientY                            false,            // ctrlKey                            false,            // altKey                             false,            // shiftKey                           false,            // metaKey                            0,                // button                             null              // relatedTarget                      );    // Dispatch the simulated event to the target element    event.target.dispatchEvent(simulatedEvent);    }    mouseProto._touchStart = function (event) {    var self = this;    // Ignore the event if another widget is already being handled    if (touchHandled || !self._mouseCapture(event.originalEvent.changedTouches[0])) {        return;        }    // Set the flag to prevent other widgets from inheriting the touch event    touchHandled = true;    // Track movement to determine if interaction was a click    self._touchMoved = false;    // Simulate the mouseover event    simulateMouseEvent(event, 'mouseover');    // Simulate the mousemove event    simulateMouseEvent(event, 'mousemove');    // Simulate the mousedown event    simulateMouseEvent(event, 'mousedown');    };    mouseProto._touchMove = function (event) {    // Ignore event if not handled    if (!touchHandled) {        return;        }    // Interaction was not a click    this._touchMoved = true;    // Simulate the mousemove event    simulateMouseEvent(event, 'mousemove');    };    mouseProto._touchEnd = function (event) {    // Ignore event if not handled    if (!touchHandled) {        return;    }    // Simulate the mouseup event    simulateMouseEvent(event, 'mouseup');    // Simulate the mouseout event    simulateMouseEvent(event, 'mouseout');    // If the touch interaction did not move, it should trigger a click    if (!this._touchMoved) {      // Simulate the click event      simulateMouseEvent(event, 'click');    }    // Unset the flag to allow other widgets to inherit the touch event    touchHandled = false;    };    mouseProto._mouseInit = function () {    var self = this;    // Delegate the touch handlers to the widget's element    self.element        .on('touchstart', $.proxy(self, '_touchStart'))        .on('touchmove', $.proxy(self, '_touchMove'))        .on('touchend', $.proxy(self, '_touchEnd'));    // Call the original $.ui.mouse init method    _mouseInit.call(self);    };})(jQuery);

Call me in the morning ;) (that's really arrogant, I didn't write this solution although I wish that I had, I'd reference it if I remember where I found it, if anyone know where this code came from please comment and credit that person)

UPDATE: Here you go: This is where I found this


I suggest jQuery UI Touch Punch. I've tested it on iOS 5 and Android 2.3 and it works great on both.


Old thread I know.......

Problem with the answer of @likwid_t is that it blocks also any input or other element that has to react on 'clicks' (for example inputs), so i wrote this solution. This solution made it possible to use any existing drag and drop library that is based upon mousedown, mousemove and mouseup events on any touch device (or cumputer). This is also a cross-browser solution.

I have tested in on several devices and it works fast (in combination with the drag and drop feature of ThreeDubMedia (see also http://threedubmedia.com/code/event/drag)). It is a jQuery solution so you can use it only with jQuery libs. I have used jQuery 1.5.1 for it because some newer functions don't work properly with IE9 and above (not tested with newer versions of jQuery).

Before you add any drag or drop operation to an event you have to call this function first:

simulateTouchEvents(<object>);

You can also block all components/children for input or to speed up event handling by using the following syntax:

simulateTouchEvents(<object>, true); // ignore events on childs

Here is the code i wrote. I used some nice tricks to speed up evaluating things (see code).

function simulateTouchEvents(oo,bIgnoreChilds){ if( !$(oo)[0] )  { return false; } if( !window.__touchTypes ) {   window.__touchTypes  = {touchstart:'mousedown',touchmove:'mousemove',touchend:'mouseup'};   window.__touchInputs = {INPUT:1,TEXTAREA:1,SELECT:1,OPTION:1,'input':1,'textarea':1,'select':1,'option':1}; }$(oo).bind('touchstart touchmove touchend', function(ev){    var bSame = (ev.target == this);    if( bIgnoreChilds && !bSame )     { return; }    var b = (!bSame && ev.target.__ajqmeclk), // Get if object is already tested or input type        e = ev.originalEvent;    if( b === true || !e.touches || e.touches.length > 1 || !window.__touchTypes[e.type]  )     { return; } //allow multi-touch gestures to work    var oEv = ( !bSame && typeof b != 'boolean')?$(ev.target).data('events'):false,        b = (!bSame)?(ev.target.__ajqmeclk = oEv?(oEv['click'] || oEv['mousedown'] || oEv['mouseup'] || oEv['mousemove']):false ):false;    if( b || window.__touchInputs[ev.target.tagName] )     { return; } //allow default clicks to work (and on inputs)    // https://developer.mozilla.org/en/DOM/event.initMouseEvent for API    var touch = e.changedTouches[0], newEvent = document.createEvent("MouseEvent");    newEvent.initMouseEvent(window.__touchTypes[e.type], true, true, window, 1,            touch.screenX, touch.screenY,            touch.clientX, touch.clientY, false,            false, false, false, 0, null);    touch.target.dispatchEvent(newEvent);    e.preventDefault();    ev.stopImmediatePropagation();    ev.stopPropagation();    ev.preventDefault();}); return true;}; 

What it does:At first, it translates single touch events into mouse events. It checks if an event is caused by an element on/in the element that must be dragged around. If it is an input element like input, textarea etc, it skips the translation, or if a standard mouse event is attached to it it will also skip a translation.

Result:Every element on a draggable element is still working.

Happy coding, greetz,Erwin Haantjes