Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What to do if "mousemove" and "click" events fire simultaneously?

I don't know whether it is only Chrome problem (can't check now), however let's try the following piece of code, where we bind two events to some element:

$("div").on({
    mousemove: function(e) {
        console.log("move");
    },
    click: function(e) {
        console.log("click");
    }
});

If we try to click the element, we'll find that for some reason mousemove event fires immediately after click, so in console we have:

>> ...
>> click
>> move

DEMO: http://jsfiddle.net/gKqVt/

Note, that mousedown and mouseup events work by the same scenario.

I saw many questions on SO about the same problem, but none (in my search) gave the straightforward idea what to do in order to fire the click event only.

like image 375
VisioN Avatar asked Jan 26 '13 16:01

VisioN


4 Answers

Mousemove appears to be binded to every mouse action there is in Chrome, so store the mouse position every time the mouse "moves" and check it against the previous mouse position to validate that it has indeed "moved"..

var currentPos=[];
$("div").on({
    mousemove: function(e) {
        if (e.pageX!==currentPos[0] && e.pageY !==currentPos[1]){
            currentPos=[e.pageX,e.pageY];
        this.innerHTML = "Event: " + e.type;
        console.log("move");
        }
    },
    click: function(e) {
        this.innerHTML = "Event: " + e.type;
        console.log("click");
    }
});

Demo | Source

like image 78
extramaster Avatar answered Nov 12 '22 14:11

extramaster


This appears to be a bug in Chrome that was first reported back in November, and remains open.

Chromium Issue 161464

If you are targeting Chrome specifically then it may be worth comparing the event timestamps to get around it (using some minimum delta time as @ExplosionPills suggested. But if you're looking for general behavior it seems that you're better off treating them as separate events, because in every browser but chrome (and maybe Safari? the bug is labeled as webkit-core) they will in fact be separate events.

like image 25
Ben McCormick Avatar answered Nov 12 '22 13:11

Ben McCormick


This behavior is odd, and it doesn't seem to occur universally (happens in Chrome/IE for me, but not FFX). I think you haven't gotten a straight answer because there isn't one really.

It's possible that the mouse is moved very slightly by the click action, but that's probably not it. Could just be a browser quirk. These don't even seem to be the same event since stopImmediatePropagation in click doesn't stop mousemove from firing. If you focus the element and hit a keyboard button, it will actually trigger click and only click.

Since this is so quirky, it seems like the only way to deal with it is times. As much of a kludge as this is, I do notice that click happens one millisecond before mousemove, so you could get close by comparing the click timestamp + 2 (or 10):

mousemove: function(e) {
    if ($(this).data('lastClick') + 10 < e.timeStamp) {

http://jsfiddle.net/gKqVt/3/

This is very specific, though. You should consider not having behavior that occurs immediately on mousemove since it's so frequent.

like image 3
Explosion Pills Avatar answered Nov 12 '22 12:11

Explosion Pills


Why don't just check that did the mouse really move or not like below:

function onMouseDown (e) {
    mouseDown = { x: e.clientX, y: e.clientY };
    console.log("click");
}

function onMouseMove (e) {
    //To check that did mouse really move or not
    if ( e.clientX !== mouseDown.x || e.clientY !== mouseDown.y) {
        console.log("move");
    }
}

FIDDLE DEMO

(I think it's will still correct in all browsers)

like image 3
Ben Mack Avatar answered Nov 12 '22 13:11

Ben Mack