bryan
bryan

Reputation: 9389

Canceling a custom drag function when mouse slides off div

I have a draggable function in jquery to make it so I can drag and move elements on a div. Sometimes, when dragging the mouse comes off the div and I am not able to put back down the element.

I'm trying to add a keydown event for the escape button or something so that when pressed, the same thing happens on .on("mouseup", function(event) {

I've tried doing .on("mouseup keydown", function(event) { but it doesn't catch any keys that are being pressed.

Does anyone have any ideas on how I can cancel the drag? Either by a keydown or even on a mouseup regardless of if the mouse is on the div or not that is being dragged?

Just to be clear, the problem I am having is sometimes I will be dragging the element, I will mouseup but the mouse wasn't on the element when mouseup was called. Therefore, the element is still dragging and I no longer have my finger on the mouse and I have no way to stop the element from dragging to get it back on the document.

EDIT: Here is a jsfiddle, notice I am trying to get this to work on a scaled container. youtube video showing drag glitch

(function($) {
    $.fn.drags = function(opt, callback) {
        opt = $.extend({
            handle: "",
            cursor: "move"
        }, opt);
        if (opt.handle === "") {
            var $el = this;
        } else {
            var $el = this.find(opt.handle);
        }
        return $el.css('cursor', opt.cursor).on("mousedown", function(e) {
            if (opt.handle === "") {
                var $drag = $(this).addClass('draggable');
            } else {
                var $drag = $(this).addClass('active-handle').parent().addClass('draggable');
            }
            var z_idx = $drag.css('z-index'),
                drg_h = $drag.outerHeight(),
                drg_w = $drag.outerWidth(),
                pos_y = $drag.offset().top + drg_h - e.pageY,
                pos_x = $drag.offset().left + drg_w - e.pageX;
            $drag.css('z-index', 1000).parents().on("mousemove", function(e) {
                $('.draggable').offset({
                    top: e.pageY + pos_y - drg_h,
                    left: e.pageX + pos_x - drg_w
                }).on("mouseup", function() {
                    $(this).removeClass('draggable').css('z-index', z_idx);
                });
            });
            e.preventDefault();
        }).on("mouseup", function(event) {
            if (opt.handle === "") {
                $(this).removeClass('draggable');
            } else {
                $(this).removeClass('active-handle').parent().removeClass('draggable');
            }

            if (typeof callback == 'function') {
                alert("this is a callback");
            }

        });
    }
})(jQuery);

Upvotes: 2

Views: 3648

Answers (1)

posit labs
posit labs

Reputation: 9431

Here are a few things that might work:

Instead of listening for mouseup on the target element, listen for it on document.body. That way it will fire regardless of if the cursor is over the dragged element.

If you want to cancel the drag when the cursor wanders out of the page, add an event listener for mouseleave on document.body and use it to cancel the drag.

If you make a code-pen (or similar) test case, I will be happy to dig into the code.

Edit__

Handling mouseleave on the document prevents it from getting stuck in a draggable state. It also fixes the multiplied movement that you were seeing.

$(document.body).on('mouseleave', function(){
    $el.removeClass('draggable').css('z-index', z_idx);
});

Edit2__

Previous JSFiddle was incorrect.

https://jsfiddle.net/spk4523t/6/

Upvotes: 5

Related Questions