No Jquery Solution - Basic
The most basic draggable code would be :
Element.prototype.drag = function(){
var mousemove = function(e){ // document mousemove
this.style.left = ( e.clientX - this.dragStartX ) + 'px';
this.style.top = ( e.clientY - this.dragStartY ) + 'px';
}.bind(this);
var mouseup = function(e){ // document mouseup
document.removeEventListener('mousemove',mousemove);
document.removeEventListener('mouseup',mouseup);
}.bind(this);
this.addEventListener('mousedown',function(e){ // element mousedown
this.dragStartX = e.offsetX;
this.dragStartY = e.offsetY;
document.addEventListener('mousemove',mousemove);
document.addEventListener('mouseup',mouseup);
}.bind(this));
this.style.position = 'absolute' // fixed might work as well
}
and then usage (non-jquery) :
document.querySelector('.target').drag();
or in jquery :
$('.target')[0].drag();
Notice : the dragged element should have a position:absolute
or position:fixed
applied to it for the left,top movement to work...
the codepen below has some more "advanced" features : dragStart, dragStop callbacks, css classes appending to remove text selection of other elements while dragging, and a drop feature also...
checkout the following codepen :
http://codepen.io/anon/pen/VPPaEK
its basically setting a 'mousedown' event on the element which needs to be dragged, and then binding and unbinding the document mousemove to handle the movement.
Draggable Handle
in order to set a draggable handle for the element
Element.prototype.drag = function( setup ){
var setup = setup || {};
var mousemove = function(e){ // document mousemove
this.style.left = ( e.clientX - this.dragStartX ) + 'px';
this.style.top = ( e.clientY - this.dragStartY ) + 'px';
}.bind(this);
var mouseup = function(e){ // document mouseup
document.removeEventListener('mousemove',mousemove);
document.removeEventListener('mouseup',mouseup);
}.bind(this);
var handle = setup.handle || this;
handle.addEventListener('mousedown',function(e){ // element mousedown
this.dragStartX = e.offsetX;
this.dragStartY = e.offsetY;
document.addEventListener('mousemove',mousemove);
document.addEventListener('mouseup',mouseup);
handle.classList.add('dragging');
}.bind(this));
handle.classList.add('draggable');
this.style.position = 'absolute' // fixed might work as well
}
The above code is used like so :
var setup = {
handle : document.querySelector('.handle')
};
document.querySelector('.box').drag(setup);
Adding CSS to eliminate selectable text
The problem now, is that when dragging, the text within the draggable element is annoyingly being selected with no use...
This is why we have added the draggable
and dragging
classes to the element. which will cancel out this unwanted behavior, and also add a move cursor, to display that this element is draggable
.draggable{
cursor: move;
position: fixed;
}
.draggable.dragging{
user-select: none;
}
Adding Events
So now that we have our draggable element, we sometimes need to call various events.
setup.ondraginit // this is called when setting up the draggable
setup.ondragstart // this is called when mouse is down on the element
setup.ondragend // this is called when mouse is released (after dragging)
setup.ondrag // this is called while the element is being dragged
Each will pass the original mouse event to the specific handler
Finally, this is what we get...
Element.prototype.drag = function( setup ){
var setup = setup || {};
var mousemove = function(e){ // document mousemove
this.style.left = ( e.clientX - this.dragStartX ) + 'px';
this.style.top = ( e.clientY - this.dragStartY ) + 'px';
setup.ondrag && setup.ondrag(e); // ondrag event
}.bind(this);
var mouseup = function(e){ // document mouseup
document.removeEventListener('mousemove',mousemove);
document.removeEventListener('mouseup',mouseup);
handle.classList.remove('dragging');
setup.ondragend && setup.ondragend(e); // ondragend event
}.bind(this);
var handle = setup.handle || this;
handle.addEventListener('mousedown',function(e){ // element mousedown
this.dragStartX = e.offsetX;
this.dragStartY = e.offsetY;
document.addEventListener('mousemove',mousemove);
document.addEventListener('mouseup',mouseup);
handle.classList.add('dragging');
setup.ondragstart && setup.ondragstart(e); // ondragstart event
}.bind(this));
handle.classList.add('draggable');
setup.ondraginit && setup.ondraginit(e); // ondraginit event
}
And to use this :
var setup = {
handle : document.querySelector('.handle'),
ondragstart : e => { console.log('drag has started!'); },
ondrag : e => { console.log('drag!'); },
ondragend : e => { console.log('drag has ended!'); }
};
document.querySelector('.box').drag(setup);
note that e.target
is a reference back to our draggable element