0

My page contains a red and a blue div:

<div id="red"></div>
<div id="blue"></div>

They're both absolutely positioned and are separated by a small amount:

#red {
    background-color: red;
    width: 5em;
    height: 5em;
    position: absolute;
    left: 5em;
    top: 5em;
}

#blue {
    background-color: blue;
    width: 5em;
    height: 5em;
    position: absolute;
    left: 15em;
    top: 5em;
}

I have some code to tell if the user clicks and drags their mouse from one div to the other:

$('#red').mousedown( function () {
    $('#blue').mouseup( function () {
        alert('Red to Blue')
    })
})

$('#blue').mousedown( function () {
    $('#red').mouseup( function () {
        alert('Blue to Red')
    })
})

This works perfectly the first time if the user moves the mouse directly from one div to the other with the mouse button held down.

There are 2 issues though:

  1. If the user releases the mouse button while outside of a div then clicks on the other one, mouseup will still run.
  2. Any time after the first, the user will have to click outside of either div in order for the handlers to work properly.
MBR-6161
  • 145
  • 1
  • 4

2 Answers2

0

You should change your approach like this:

var isDragging = false;
var dragElement = null;

$('#red, #blue').mousedown(function() {
   dragElement = $(this);
   isDragging = true;
});

$('#red, #blue').mouseup(function() {
    if(isDragging && dragElement){ 
        alert('Dragged in',dragElement);
        dragElement = null;
        isDragging = false;
    }
});

$('body *:not(#red, #blue)').mouseup(function() {
    if(isDragging && dragElement){ 
        alert('Not dragged',dragElement);
        dragElement = null;
        isDragging = false;
    }
});

There is an another question about it : Draggable div without jQuery UI

pirs
  • 2,410
  • 2
  • 18
  • 25
0

The mouseup event should be removed as soon as it happens (using .one()), and it should be detected outside of the divs. In addition we need to prevent the default behavior of mousedown by using event.preventDefault() to fix the 2nd problem. See comments in code.

Note: .one() (one not on) is used to bind a one time event handler, that is removed as soon as it's fired. This prevents multiple attachments of the mouseup event to the document.

var $red = $('#red')
var $blue = $('#blue');

$($.merge($red, $blue)).mousedown(function(e) {
  e.preventDefault(); // prevent the default behavior of mousedown
  var source = $(e.target);

  // attach the mouseup to the document as one time event to detect up
  $(document).one('mouseup', function(e) {
    // check if the source is red and the target is blue
    if ($blue.is(e.target) && source.is($red)) {
      alert('Red to Blue');
    } // check if the source is red and the target is blue
      else if ($red.is(e.target) && source.is($blue)) {
      alert('Blue to Red');
    }
  })
});
#red {
  background-color: red;
  width: 5em;
  height: 5em;
  position: absolute;
  left: 5em;
  top: 5em;
}

#blue {
  background-color: blue;
  width: 5em;
  height: 5em;
  position: absolute;
  left: 15em;
  top: 5em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="red"></div>

<div id="blue"></div>

And a more universal solution that uses data-* attributes to identify the source and the target:

$('[data-color]').mousedown(function(e) {
  e.preventDefault(); // prevent the default behavior of mousedown
  var source = $(e.target).attr('data-color'); // get the source data color

  // attach the mouseup to the document as one time event to detect up
  $(document).one('mouseup', function(e) {
    var target = $(e.target).attr('data-color'); // 
    
    if(target !== undefined && source !== target) {
      alert(source + ' to ' + target);
    }
  })
});
div[data-color] {
  position: absolute;
  width: 5em;
  height: 5em;
}

#red {
  left: 5em;
  top: 1em;
  background-color: red;
}

#blue {
  left: 15em;
  top: 1em;
  background-color: blue;
}

#yellow {
  left: 5em;
  top: 10em;
  background-color: yellow;
}

#green {
  left: 15em;
  top: 10em;
  background-color: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<!-- set data-type with the color to each element -->
<div id="red" data-color="Red"></div>

<div id="blue" data-color="Blue"></div>

<div id="yellow" data-color="Yellow"></div>

<div id="green" data-color="Green"></div>
Ori Drori
  • 183,571
  • 29
  • 224
  • 209