Search code examples
csshtmldrag-and-drophtml5-draggable

HTML5 drag and drop: prevent dropping off the edge of the document window?


I am working on a simple HTML5 drag and drop element. Here is my JSFiddle: http://jsfiddle.net/e4ogxcum/3/

I would like to edit this so that it's impossible to drop the toolbar half way off the page. Is this possible?

In other words, I would like to prevent the toolbar being dropped half way off the page, like below:

enter image description here

Here is my code in full:

function drag_start(event) {
    console.log('drag_start', event);
    var style = window.getComputedStyle(event.target, null);
    event.dataTransfer.setData("text/plain",
    (parseInt(style.getPropertyValue("left"),10) - event.clientX) + ',' + (parseInt(style.getPropertyValue("top"),10) - event.clientY));
} 
function drag_over(event) { 
    event.preventDefault(); 
    return false; 
} 
function drop(event) { 
    event.preventDefault();
    var offset = event.dataTransfer.getData("text/plain").split(',');
    dm.style.left = (event.clientX + parseInt(offset[0],10)) + 'px';
    dm.style.top = (event.clientY + parseInt(offset[1],10)) + 'px';
    return false;
} 

var dm = document.getElementById('taskbar'); 
dm.addEventListener('dragstart',drag_start,false); 
document.body.addEventListener('dragover',drag_over,false); 
document.body.addEventListener('drop',drop,false)

;


Solution

  • You can limit the toolbar's drag extent by changing your drop event as follows:

    function drop(event) { 
      event.preventDefault();
      var offset = event.dataTransfer.getData("text/plain").split(',');
    
      var x= event.clientX + parseInt(offset[0],10);
      var y= event.clientY + parseInt(offset[1],10);
      var w= dm.offsetWidth;
      var h= dm.offsetHeight;
    
      dm.style.left= Math.min(window.innerWidth -w/2,Math.max(-w/2,x))+'px';
      dm.style.top = Math.min(window.innerHeight-h/2,Math.max(-h/2,y))+'px';
    
      return false;
    } 
    

    x and y are based on your calculations, but they are then constrained so at least half the toolbar is always on-screen.

    Fiddle


    An alternative solution is to simulate the drag-drop behavior by using mousedown, mouseup, and mousemove.

    In mousedown, grab the toolbar's left and top coordinates (variables x and y), its width and height (variables w and h), and the mouse's pageX and pageY coordinates (variables px and py).

    In mousemove, calculate the new left and top coordinates, then constrain them so at least half the element is always visible on screen:

    newx= x+(ev.pageX-px);
    newy= y+(ev.pageY-py);
    this.style.left= Math.min(window.innerWidth -w/2,Math.max(-w/2,newx))+'px';
    this.style.top = Math.min(window.innerHeight-h/2,Math.max(-h/2,newy))+'px';
    

    Fiddle

    Code:

    (function() {
      var tb= document.querySelector('aside'),
          moving,
          w, h,
          x, y,
          newx, newy,
          px,py;
    
      tb.addEventListener('mousedown',function(ev) {
        this.style.cursor= 'move';
        x= tb.offsetLeft;
        y= tb.offsetTop;
        w= tb.offsetWidth;
        h= tb.offsetHeight;
        px= ev.pageX;
        py= ev.pageY;
        moving= true;
      });
    
      document.addEventListener('mouseup',function() {
        tb.style.cursor= '';
        moving= false;
      });
    
      tb.addEventListener('mousemove',function(ev) {
        if(moving) {
          newx= x+(ev.pageX-px);
          newy= y+(ev.pageY-py);
          this.style.left= Math.min(window.innerWidth -w/2,Math.max(-w/2,newx))+'px';
          this.style.top = Math.min(window.innerHeight-h/2,Math.max(-h/2,newy))+'px';
        }
      });
    
      document.addEventListener('mousemove', function(ev) {
        if(moving) {
          ev.preventDefault();
        }
      });
    })();