Can you detect "dragging" in jQuery?

Jquery

Jquery Problem Overview


I have a throbber that is to appear when a user clicks a link.

The problem is is that that same link can be clicked and dragged to be rearranged. In this case, I wouldn't need the throbber to appear. It only needs to appear if its actually waiting to go somewhere.

How can I, with jQuery, create an event listener that would only allow a throbber to appear if its a click through to a link, and not a click and drag?

Jquery Solutions


Solution 1 - Jquery

On mousedown, start set the state, if the mousemove event is fired record it, finally on mouseup, check if the mouse moved. If it moved, we've been dragging. If we've not moved, it's a click.

var isDragging = false;
$("a")
.mousedown(function() {
    isDragging = false;
})
.mousemove(function() {
    isDragging = true;
 })
.mouseup(function() {
    var wasDragging = isDragging;
    isDragging = false;
    if (!wasDragging) {
        $("#throbble").toggle();
    }
});

Here's a demo: http://jsfiddle.net/W7tvD/1399/

Solution 2 - Jquery

For some reason, the above solutions were not working for me. I went with the following:

$('#container').on('mousedown', function(e) {
    $(this).data('p0', { x: e.pageX, y: e.pageY });
}).on('mouseup', function(e) {
    var p0 = $(this).data('p0'),
        p1 = { x: e.pageX, y: e.pageY },
        d = Math.sqrt(Math.pow(p1.x - p0.x, 2) + Math.pow(p1.y - p0.y, 2));

    if (d < 4) {
        alert('clicked');
    }
})

You can tweak the distance limit to whatever you please, or even take it all the way to zero.

Solution 3 - Jquery

With jQuery UI just do this!

$( "#draggable" ).draggable({
  start: function() {

  },
  drag: function() {

  },
  stop: function() {

  }
});

Solution 4 - Jquery

$(".draggable")
.mousedown(function(e){
    $(this).on("mousemove",function(e){
        var p1 = { x: e.pageX, y: e.pageY };
        var p0 = $(this).data("p0") || p1;
        console.log("dragging from x:" + p0.x + " y:" + p0.y + "to x:" + p1.x + " y:" + p1.y);
        $(this).data("p0", p1);
    });
})
.mouseup(function(){
    $(this).off("mousemove");
});

This solution uses the "on" and "off" functions to bind an unbind a mousemove event (bind and unbind are deprecated). You can also detect the change in mouse x and y positions between two mousemove events.

Solution 5 - Jquery

Try this: it shows when is 'dragged' state. ;) fiddle link

$(function() {
    var isDragging = false;
    $("#status").html("status:");
    $("a")
    .mousedown(function() {
        $("#status").html("status: DRAGGED");        
    })
    .mouseup(function() {
        $("#status").html("status: dropped");   
    });

    $("ul").sortable();
});

Solution 6 - Jquery

// here is how you can detect dragging in all four directions
var isDragging = false;
$("some DOM element").mousedown(function(e) {
	var previous_x_position = e.pageX;
	var previous_y_position = e.pageY;

	$(window).mousemove(function(event) {
		isDragging = true;
		var x_position = event.pageX;
		var y_position = event.pageY;

		if (previous_x_position < x_position) {
			alert('moving right');
		} else {
			alert('moving left');
		}
		if (previous_y_position < y_position) {
			alert('moving down');
		} else {
			alert('moving up');
		}
		$(window).unbind("mousemove");
	});
}).mouseup(function() {
	var wasDragging = isDragging;
	isDragging = false;
	$(window).unbind("mousemove");
});

Solution 7 - Jquery

Make sure you set the element's draggable attribute to false so you don't have side effects when listening to mouseup events:

<div class="thing" draggable="false">text</div>

Then, you can use jQuery:

$(function() {
  var pressed, pressX, pressY,
      dragged,
      offset = 3; // helps detect when the user really meant to drag

  $(document)
  .on('mousedown', '.thing', function(e) {
    pressX = e.pageX;
    pressY = e.pageY;
    pressed = true;
  })
  .on('mousemove', '.thing', function(e) {
    if (!pressed) return;
    dragged = Math.abs(e.pageX - pressX) > offset ||
              Math.abs(e.pageY - pressY) > offset;
  })
  .on('mouseup', function() {
    dragged && console.log('Thing dragged');
    pressed = dragged = false;
  });
});

Solution 8 - Jquery

I branched off from the accepted answer to only run when the click is being HELD down and dragged.

My function was running when I wasn't holding the mouse down. Here's the updated code if you also want this functionality:

var isDragging = false;
var mouseDown = false;

$('.test_area')
	.mousedown(function() {
	    isDragging = false;
	    mouseDown = true;
	})
	.mousemove(function(e) {
	    isDragging = true;

	    if (isDragging === true && mouseDown === true) {
	    	my_special_function(e);
	    }
	 })
	.mouseup(function(e) {

	    var wasDragging = isDragging;

	    isDragging = false;
	    mouseDown = false;

	    if ( ! wasDragging ) {
	        my_special_function(e);
	    }

	}
);

Solution 9 - Jquery

For this simplest way is touch start, touch move and touch end. That is working for both PC and touch device just check it in jquery documentation and hope this is the best solution for you. good luck

Solution 10 - Jquery

jQuery plugin based on Simen Echholt's answer. I called it single click.

/**
 * jQuery plugin: Configure mouse click that is triggered only when no mouse move was detected in the action.
 * 
 * @param callback
 */
jQuery.fn.singleclick = function(callback) {
	return $(this).each(function() {
	    var singleClickIsDragging = false;
		var element = $(this);
		
		// Configure mouse down listener.
		element.mousedown(function() {
	        $(window).mousemove(function() {
	        	singleClickIsDragging = true;
	            $(window).unbind('mousemove');
	        });
	    });

		// Configure mouse up listener.
		element.mouseup(function(event) {
	        var wasDragging = singleClickIsDragging;
	        singleClickIsDragging = false;
	        $(window).unbind('mousemove');
	        if(wasDragging) {
	        	return;
	        }
	        
	        // Since no mouse move was detected then call callback function.
	        callback.call(element, event);
		});
	});
};

In use:

element.singleclick(function(event) {
	alert('Single/simple click!');
});

^^

Solution 11 - Jquery

You've need to set a timer. When the timer times out, start the throbber and register the click. When drag occurs, clear the timer so it never completes.

Solution 12 - Jquery

If you're using jQueryUI - there is an onDrag event. If you're not, then attach your listener to mouseup(), not click().

Solution 13 - Jquery

You don`t have to setup variable, you can just set if it is moving in data-attribute

$youtubeSlider.find('a')
	.on('mousedown', function (e) {
		$(this).data('moving', false);
	})
	.on('mousemove', function (e) {
		$(this).data('moving', true);
	})
	.on('mouseup', function (e) {
		if (!$(this).data('moving')) {
			// Open link
		}
	});

Solution 14 - Jquery

I needed a function that always keeps track of mouse position and detect left-, right-, top-, bottom- dragging. It also does not trigger on click but needs a minimum of 15px move

/**
 * Check for drag when moved minimum 15px
 * Same time keep track of mouse position while dragging
 */
// Variables to be accessed outside in other functions
var dragMouseX;
var dragMouseY;
var myDragging = false; // true or false
var dragDirectionX = false; // left or right
var dragDirectionY = false; // top or bottom

$(document).on("mousedown", function(e) {
    // Reset some variables on mousedown
    var lastDirectionCheck = e.timeStamp;
    var dragStartX = e.pageX;
    var dragStartY = e.pageY;
    dragMouseX = e.pageX;
    dragMouseY = e.pageY;
    myDragging = false;
    dragDirectionX = false;
    dragDirectionY = false;

    // On the move
    $(document).on("mousemove", function(e) {
        dragMouseX = e.pageX;
        dragMouseY = e.pageY;

        // Recalculate drag direction every 200ms in case user changes his mind
        if (e.timeStamp > (lastDirectionCheck + 200)) {
            dragStartX = dragMouseX;
            dragStartY = dragMouseY;
            lastDirectionCheck = e.timeStamp;
        }

        // Check for drag when moved minimum 15px in any direction
        if (!myDragging && Math.abs(dragStartX - dragMouseX) > 15 || Math.abs(dragStartY - dragMouseY) > 15) {
            myDragging = true;
        }
        if (myDragging) {
            // Check drag direction X
            if (dragStartX > dragMouseX) dragDirectionX = 'left';
            if (dragStartX < dragMouseX) dragDirectionX = 'right';

            // Check drag direction Y
            if (dragStartY > dragMouseY) dragDirectionY = 'top';
            if (dragStartY < dragMouseY) dragDirectionY = 'bottom';

            // console.log(dragDirectionX + ' ' + dragDirectionY);
        }
    });
});

// Reset some variables again on mouseup
$(document).on("mouseup", function() {
    $(document).off("mousemove");
    myDragging = false;
    dragDirectionX = false;
    dragDirectionY = false;
});

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTripView Question on Stackoverflow
Solution 1 - JquerySimen EchholtView Answer on Stackoverflow
Solution 2 - JqueryanewcomerView Answer on Stackoverflow
Solution 3 - JqueryGaidenFocusView Answer on Stackoverflow
Solution 4 - JqueryjnaklaasView Answer on Stackoverflow
Solution 5 - JquerysyCView Answer on Stackoverflow
Solution 6 - JqueryJosephView Answer on Stackoverflow
Solution 7 - JqueryMarcelo KanzakiView Answer on Stackoverflow
Solution 8 - JqueryJackView Answer on Stackoverflow
Solution 9 - JqueryAnupView Answer on Stackoverflow
Solution 10 - JqueryipfaffenView Answer on Stackoverflow
Solution 11 - JqueryDiodeus - James MacFarlaneView Answer on Stackoverflow
Solution 12 - JqueryQuasipickleView Answer on Stackoverflow
Solution 13 - JqueryAipheeView Answer on Stackoverflow
Solution 14 - JqueryJulesezaarView Answer on Stackoverflow