61

I'm using the YUI slider that operates with mouse move events. I want to make it respond to touchmove events (iPhone and Android). How can I produce a mouse move event when a touchmove event occurs? I'm hoping that just by adding some script at the top that touchmove events will get mapped to the mouse move events and I won't have to change anything with the slider.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Questioner
  • 7,133
  • 16
  • 61
  • 94
  • Can you post the code you have so far? – meder omuraliev Oct 05 '09 at 01:45
  • I am using these two sliders from the YUI library: http://developer.yahoo.com/yui/examples/slider/slider-ticks_clean.html http://developer.yahoo.com/yui/examples/slider/slider_dual_with_highlight.html – Questioner Oct 05 '09 at 07:04

5 Answers5

118

I am sure this is what you want:

function touchHandler(event)
{
    var touches = event.changedTouches,
        first = touches[0],
        type = "";
    switch(event.type)
    {
        case "touchstart": type = "mousedown"; break;
        case "touchmove":  type = "mousemove"; break;        
        case "touchend":   type = "mouseup";   break;
        default:           return;
    }

    // initMouseEvent(type, canBubble, cancelable, view, clickCount, 
    //                screenX, screenY, clientX, clientY, ctrlKey, 
    //                altKey, shiftKey, metaKey, button, relatedTarget);

    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);
    event.preventDefault();
}

function init() 
{
    document.addEventListener("touchstart", touchHandler, true);
    document.addEventListener("touchmove", touchHandler, true);
    document.addEventListener("touchend", touchHandler, true);
    document.addEventListener("touchcancel", touchHandler, true);    
}

I've captured the touch events and then manually fired my own mouse events to match. Although the code isn't particularly general purpose as is, it should be trivial to adapt to most existing drag and drop libraries, and probably most existing mouse event code. Hopefully this idea will come in handy to people developing web applications for the iPhone.

Update:

In posting this, I noticed that calling preventDefault on all touch events will prevent links from working properly. The main reason to call preventDefault at all is to stop the phone from scrolling, and you can do that by calling it only on the touchmove callback. The only downside to doing it this way is that the iPhone will sometimes display its hover popup over the drag origin. If I discover a way to prevent that, I'll update this post.

Second Update:

I've found the CSS property to turn off the callout: -webkit-touch-callout.

Timothy Gu
  • 3,727
  • 28
  • 35
Mickey Shine
  • 12,187
  • 25
  • 96
  • 148
  • 1
    not all touchmove events translate to mousemove events! e.g. if you want to simply scroll down on your screen the touchmove event gets triggered as well but translates into a scroll event ...! – nerdess Mar 18 '13 at 12:03
  • I've found this most helpful, whilst trying to work out why a touch screen monitor for a kiosk wouldn't draw on screen where a mouse does. Chrome and Firefox seem to have difference behaviour in this respect. In Firefox I see that you still get mouse move events from touch screens, but not so with chrome. – Spacen Jasset Sep 08 '15 at 16:19
  • 2
    initMouseEvent method is now deprecated (https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/initMouseEvent) – Bohdan Lyzanets Dec 14 '15 at 16:19
  • Maybe 'touchcancel' event should be mapped too? Probably to the 'mouseup' as 'touchend' – Yuri Gor Jun 15 '16 at 12:45
  • @YuriGor probably `mouseout` is a better option, especially if user drags off screen. – Tom Roggero Jul 27 '17 at 21:36
  • To solve the problem with page scrolling on touch screens, you could set a custom special attribute to your element, like `document.getElementById('myElm').myprefixNoScroll=1;` and in your mapping function you check for this special attribute in the target element and prevent default action only when it is not set. Example (inside your `touchHandle()` function): `if (!event.target.myPrefixNoScrolling) event.preventDefault();`. This will allow you to normally scroll, but will stop scrolling on certain elements only (where you want you drag operations happen). – StanE Oct 30 '17 at 13:00
  • Does the mapping from touch events to mouse events and dispatching this new event, perform a real DRAG behavior on mobile browsers or does it only perform the EVENT but there is no visual effect like the native drag behavior. I tested this and others like this, the events will be fired but now visible effect is shown. – Michael Burger Feb 08 '18 at 15:12
  • Hello from future. In init() function we need use options like {passive:false} - https://www.chromestatus.com/features/5093566007214080 – DaemonHK Jan 22 '20 at 06:47
9

I finally found a way to get this working using Mickey's solution but instead of his init function. Use the init function here.

function init() {
    document.getElementById('filter_div').addEventListener("touchstart", touchHandler, true);
    document.getElementById('filter_div').addEventListener("touchmove", touchHandler, true);
    document.getElementById('filter_div').addEventListener("touchend", touchHandler, true);
    document.getElementById('filter_div').addEventListener("touchcancel", touchHandler, true);
}

If you see 'filter_div' is the chart area where we have the chart range filter and only in that area do we want to rewrite our touch controls!

Thank you Mickey. It was a great solution.

dertkw
  • 7,798
  • 5
  • 37
  • 45
Sana
  • 9,895
  • 15
  • 59
  • 87
4

Along the lines of @Mickey Shine's answer, Touch Punch provides mapping of touch events to click events. It's built to put this support into jQuery UI, but the code is informative.

Pat
  • 16,515
  • 15
  • 95
  • 114
3

For future users, who comeback here the following code might be used :

var eventMap = {};

(function(){
var eventReplacement = {
    "mousedown": ["touchstart mousedown", "mousedown"],
    "mouseup": ["touchend mouseup", "mouseup"],
    "click": ["touchstart click", "click"],
    "mousemove": ["touchmove mousemove", "mousemove"]
};


for (i in eventReplacement) {
    if (typeof window["on" + eventReplacement[i][0]] == "object") {
        eventMap[i] = eventReplacement[i][0];
    } 
    else {
        eventMap[i] = eventReplacement[i][1];
    };
 };
})();

And then in the events use like following :

$(".yourDiv").on(eventMap.mouseup, function(event) {
      //your code
}
Pritam Banerjee
  • 17,953
  • 10
  • 93
  • 108
2

For making @Mickey's code work on Edge and internet explorer, add the following lines in .css of the element where you want the simulation to happen:

.areaWhereSimulationHappens {
    overflow: hidden;
    touch-action: none;
    -ms-touch-action: none;
}

These lines prevent the default touch for edge and IE. But if you add it to the wrong element, then it also disables scroll (which happens by default on edge and IE on touch devices).

kumardeepakr3
  • 395
  • 6
  • 16