Draggable div without jQuery UI

JqueryHtmlDraggable

Jquery Problem Overview


I'm trying to make a div draggable without using jQuery UI.

However, I'm stuck with the code below. I understand that I should use the mouse position relative to the container div (in which the div will be dragged) and that I should set the div's offset relative to those values.

I just can't figure out how. Any clues?

This is the code that doesn't (of course) work:

var X, Y;

$(this).mousedown(function() {
	$(this).offset({ 
		left: X, 
		top: Y
	});
});

$("#containerDiv").mousemove(function(event) {
	X = event.pageX;
	Y = event.pageY;
});

Jquery Solutions


Solution 1 - Jquery

Here's a really simple example that might get you started:

$(document).ready(function() {
    var $dragging = null;

    $(document.body).on("mousemove", function(e) {
        if ($dragging) {
            $dragging.offset({
                top: e.pageY,
                left: e.pageX
            });
        }
    });
    

    $(document.body).on("mousedown", "div", function (e) {
        $dragging = $(e.target);
    });
    
    $(document.body).on("mouseup", function (e) {
        $dragging = null;
    });
});

Example: http://jsfiddle.net/Jge9z/

>I understand that I shall use the mouse position relative to the container div (in which the div shall be dragged) and that I shall set the divs offset relative to those values.

Not so sure about that. It seems to me that in drag and drop you'd always want to use the offset of the elements relative to the document.

If you mean you want to constrain the dragging to a particular area, that's a more complicated issue (but still doable).

Solution 2 - Jquery

Here's another updated code:

$(document).ready(function() {
    var $dragging = null;
    $('body').on("mousedown", "div", function(e) {
        $(this).attr('unselectable', 'on').addClass('draggable');
        var el_w = $('.draggable').outerWidth(),
            el_h = $('.draggable').outerHeight();
        $('body').on("mousemove", function(e) {
            if ($dragging) {
                $dragging.offset({
                    top: e.pageY - el_h / 2,
                    left: e.pageX - el_w / 2
                });
            }
        });
        $dragging = $(e.target);
    }).on("mouseup", ".draggable", function(e) {
        $dragging = null;
        $(this).removeAttr('unselectable').removeClass('draggable');
    });
});​

Demo: http://jsfiddle.net/tovic/Jge9z/31/


I've created a simple plugin to this thread.

// Simple JQuery Draggable Plugin
// https://plus.google.com/108949996304093815163/about
// Usage: $(selector).drags();
// Options:
// handle            => your dragging handle.
//                      If not defined, then the whole body of the
//                      selected element will be draggable
// cursor            => define your draggable element cursor type
// draggableClass    => define the draggable class
// activeHandleClass => define the active handle class
//
// Update: 26 February 2013
// 1. Move the `z-index` manipulation from the plugin to CSS declaration
// 2. Fix the laggy effect, because at the first time I made this plugin,
//    I just use the `draggable` class that's added to the element
//    when the element is clicked to select the current draggable element. (Sorry about my bad English!)
// 3. Move the `draggable` and `active-handle` class as a part of the plugin option
// Next update?? NEVER!!! Should create a similar plugin that is not called `simple`!

(function($) {
    $.fn.drags = function(opt) {

        opt = $.extend({
            handle: "",
            cursor: "move",
            draggableClass: "draggable",
            activeHandleClass: "active-handle"
        }, opt);

        var $selected = null;
        var $elements = (opt.handle === "") ? this : this.find(opt.handle);

        $elements.css('cursor', opt.cursor).on("mousedown", function(e) {
            if(opt.handle === "") {
                $selected = $(this);
                $selected.addClass(opt.draggableClass);
            } else {
                $selected = $(this).parent();
                $selected.addClass(opt.draggableClass).find(opt.handle).addClass(opt.activeHandleClass);
            }
            var drg_h = $selected.outerHeight(),
                drg_w = $selected.outerWidth(),
                pos_y = $selected.offset().top + drg_h - e.pageY,
                pos_x = $selected.offset().left + drg_w - e.pageX;
            $(document).on("mousemove", function(e) {
                $selected.offset({
                    top: e.pageY + pos_y - drg_h,
                    left: e.pageX + pos_x - drg_w
                });
            }).on("mouseup", function() {
                $(this).off("mousemove"); // Unbind events from document
                if ($selected !== null) {
                    $selected.removeClass(opt.draggableClass);
                    $selected = null;
                }
            });
            e.preventDefault(); // disable selection
        }).on("mouseup", function() {
            if(opt.handle === "") {
                $selected.removeClass(opt.draggableClass);
            } else {
                $selected.removeClass(opt.draggableClass)
                    .find(opt.handle).removeClass(opt.activeHandleClass);
            }
            $selected = null;
        });

        return this;

    };
})(jQuery);

Demo: http://tovic.github.io/dte-project/jquery-draggable/index.html

Solution 3 - Jquery

Here's my contribution:

http://jsfiddle.net/g6m5t8co/1/

<!doctype html>
<html>
    <head>
        <style>
			#container {
				position:absolute;
                background-color: blue;
				}
            #elem{
                position: absolute;
                background-color: green;
                -webkit-user-select: none;
                -moz-user-select: none;
                -o-user-select: none;
                -ms-user-select: none;
                -khtml-user-select: none;     
                user-select: none;
            }
        </style>
        <script>
            var mydragg = function(){
                return {
                    move : function(divid,xpos,ypos){
                        divid.style.left = xpos + 'px';
                        divid.style.top = ypos + 'px';
                    },
                    startMoving : function(divid,container,evt){
                        evt = evt || window.event;
                        var posX = evt.clientX,
                            posY = evt.clientY,
                        divTop = divid.style.top,
                        divLeft = divid.style.left,
						eWi = parseInt(divid.style.width),
						eHe = parseInt(divid.style.height),
						cWi = parseInt(document.getElementById(container).style.width),
						cHe = parseInt(document.getElementById(container).style.height);
						document.getElementById(container).style.cursor='move';
                        divTop = divTop.replace('px','');
                        divLeft = divLeft.replace('px','');
                        var diffX = posX - divLeft,
                            diffY = posY - divTop;
                        document.onmousemove = function(evt){
                            evt = evt || window.event;
                            var posX = evt.clientX,
                                posY = evt.clientY,
                                aX = posX - diffX,
                                aY = posY - diffY;
								if (aX < 0) aX = 0;
								if (aY < 0) aY = 0;
								if (aX + eWi > cWi) aX = cWi - eWi;
								if (aY + eHe > cHe) aY = cHe -eHe;
                            mydragg.move(divid,aX,aY);
                        }
                    },
                    stopMoving : function(container){
                        var a = document.createElement('script');
						document.getElementById(container).style.cursor='default';
                        document.onmousemove = function(){}
                    },
                }
            }();

        </script>
    </head>
    <body>
		<div id='container' style="width: 600px;height: 400px;top:50px;left:50px;">		
			<div id="elem" onmousedown='mydragg.startMoving(this,"container",event);' onmouseup='mydragg.stopMoving("container");' style="width: 200px;height: 100px;">
				<div style='width:100%;height:100%;padding:10px'>
				<select id=test>
					<option value=1>first
					<option value=2>second
				</select>
				<INPUT TYPE=text value="123">
				</div>
			</div>
		</div>	
    </body>
</html>





Solution 4 - Jquery

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

Solution 5 - Jquery

here's another way of making a draggable object that is centered to the click

http://jsfiddle.net/pixelass/fDcZS/

function endMove() {
    $(this).removeClass('movable');
}

function startMove() {
    $('.movable').on('mousemove', function(event) {
        var thisX = event.pageX - $(this).width() / 2,
            thisY = event.pageY - $(this).height() / 2;

        $('.movable').offset({
            left: thisX,
            top: thisY
        });
    });
}
$(document).ready(function() {
    $("#containerDiv").on('mousedown', function() {
        $(this).addClass('movable');
        startMove();
    }).on('mouseup', function() {
        $(this).removeClass('movable');
        endMove();
    });

});

CSS

#containerDiv {
    background:#333;
    position:absolute;
    width:200px;
    height:100px;
}

Solution 6 - Jquery

Dragging like jQueryUI: JsFiddle

You can drag the element from any point without weird centering.

$(document).ready(function() {
	    
	    var $body = $('body');
	    var $target = null;
	    var isDraggEnabled = false;

	    $body.on("mousedown", "div", function(e) {
	       
	    	$this = $(this);
	       	isDraggEnabled = $this.data("draggable");

	       	if (isDraggEnabled) {
	       		if(e.offsetX==undefined){
					x = e.pageX-$(this).offset().left;
					y = e.pageY-$(this).offset().top;
				}else{
					x = e.offsetX;
					y = e.offsetY;
				};

				$this.addClass('draggable');
	        	$body.addClass('noselect');
	        	$target = $(e.target);
	       	};

	    });
	    
	     $body.on("mouseup", function(e) {
	        $target = null;
	        $body.find(".draggable").removeClass('draggable');
	        $body.removeClass('noselect');
	    });
	    
	     $body.on("mousemove", function(e) {
            if ($target) {
                $target.offset({
                    top: e.pageY  - y,
                    left: e.pageX - x
                });
            };     
	     });

	});

Solution 7 - Jquery

This is mine. http://jsfiddle.net/pd1vojsL/

3 draggable buttons in a div, dragging constrained by div.

<div id="parent" class="parent">
    <button id="button1" class="button">Drag me</button>
    <button id="button2" class="button">Drag me</button>
    <button id="button3" class="button">Drag me</button>
</div>
<div id="log1"></div>
<div id="log2"></div>

Requires JQuery (only):

$(function() {
    $('.button').mousedown(function(e) {
        if(e.which===1) {
            var button = $(this);
            var parent_height = button.parent().innerHeight();
            var top = parseInt(button.css('top')); //current top position
            var original_ypos = button.css('top','').position().top; //original ypos (without top)
            button.css({top:top+'px'}); //restore top pos
            var drag_min_ypos = 0-original_ypos;
            var drag_max_ypos = parent_height-original_ypos-button.outerHeight();
            var drag_start_ypos = e.clientY;
            $('#log1').text('mousedown top: '+top+', original_ypos: '+original_ypos);
            $(window).on('mousemove',function(e) {
                //Drag started
                button.addClass('drag');
                var new_top = top+(e.clientY-drag_start_ypos);
                button.css({top:new_top+'px'});
                if(new_top<drag_min_ypos) { button.css({top:drag_min_ypos+'px'}); }
                if(new_top>drag_max_ypos) { button.css({top:drag_max_ypos+'px'}); }
                $('#log2').text('mousemove min: '+drag_min_ypos+', max: '+drag_max_ypos+', new_top: '+new_top);
                //Outdated code below (reason: drag contrained too early)
                /*if(new_top>=drag_min_ypos&&new_top<=drag_max_ypos) {
                    button.css({top:new_top+'px'});
                }*/
            });
            $(window).on('mouseup',function(e) {
                 if(e.which===1) {
                    //Drag finished
                    $('.button').removeClass('drag');
                    $(window).off('mouseup mousemove');
                    $('#log1').text('mouseup');
                    $('#log2').text('');
                 }
            });
        }
    });
});

Solution 8 - Jquery

What I saw above is complicate.....

Here is some code can refer to.

$("#box").on({
                mousedown:function(e)
                {
                  dragging = true;
                  dragX = e.clientX - $(this).position().left;
                  //To calculate the distance between the cursor pointer and box 
                  dragY = e.clientY - $(this).position().top;
                },
                mouseup:function(){dragging = false;},
                  //If not set this on/off,the move will continue forever
                mousemove:function(e)
                {
                  if(dragging)
                  $(this).offset({top:e.clientY-dragY,left:e.clientX-dragX});
                  
                }
            })

dragging,dragX,dragY may place as the global variable.

It's a simple show about this issue,but there is some bug about this method.

If it's your need now,here's the Example here.

Solution 9 - Jquery

$(document).ready(function() {
    var $startAt = null;

    $(document.body).live("mousemove", function(e) {
        if ($startAt) {
            $("#someDiv").offset({
                top: e.pageY,
                left: $("#someDiv").position().left-$startAt+e.pageX
            });
            $startAt = e.pageX; 
        }
    });

    $("#someDiv").live("mousedown", function (e) {$startAt = e.pageX;});
    $(document.body).live("mouseup", function (e) {$startAt = null;});
});

Solution 10 - Jquery

I have a simple version of this that doesn't use any JQuery whatsoever, and it's even easy to implement!

// add 'draggable-object' as an attribute to your div element
var dragDiv = document.querySelector("div[draggable-object]");
// add the '-header' to the header element of the draggable div if you want the user to press a specific part of the element to drag it
var dragDivHeader = document.querySelector("div[draggable-object-header]");

// function for getting the mouse offset from the div position
function getMouseOffset()
{
    var e = window.event;
    
    var divX = parseInt(getComputedStyle(dragDiv).left);
    var divY = parseInt(getComputedStyle(dragDiv).top);
    
    return {
        X: e.clientX - divX,
        Y: e.clientY - divY,
    };
}

// variable for storing mouse offset from div element position
var mouseOffset = null;

// enable the mouse events, but on the document itself for easy dragging
function enableMouseDrag()
{
    document.onmouseup = disableMouseDrag;
    document.onmousemove = dragDivWithMouse;
    
    mouseOffset = getMouseOffset(); // get the mouse offset only when pressing down once
}

// drag div with mouse
function dragDivWithMouse()
{
    var e = window;
    
    // get the new x/y position of the draggable div element
    var newX = e.clientX - mouseOffset.X;
    var newY = e.clientY - mouseOffset.Y;
    
    // sets the new element position while also keeping it inside the document page without more lines of code
    dragDiv.style.left = Math.max(2, Math.min(newX, document.documentElement.clientWidth - dragDiv.offsetWidth - 2)) + "px";
    dragDiv.style.top = Math.max(2, Math.min(newY, document.documentElement.clientHeight - dragDiv.offsetHeight - 2)) + "px";
}

// disable the mouse events for the document itself
function disableMouseDrag()
{
    document.onmouseup = null;
    document.onmousemove = null;
}

// add the enableMouseDrag event callback to the div itself, or specify its header if you want
dragDiv.onmousedown = enableMouseDrag;
// dragDivHeader.onmousedown = enableMouseDrag;

I hope this works as a simple usable solution.

Solution 11 - Jquery

Here is my simple version.
The function draggable takes a jQuery object as argument.


/**







@param {jQuery} elem
*/
function draggable(elem){




elem.mousedown(function(evt){
var x = parseInt(this.style.left || 0) - evt.pageX;
var y = parseInt(this.style.top || 0) - evt.pageY;



 elem.mousemove(function(evt){
 	elem.css('left', x + evt.pageX);
 	elem.css('top', y + evt.pageY);
 });




});




elem.mouseup(off);
elem.mouseleave(off);




function off(){
elem.off("mousemove");
}
}





Solution 12 - Jquery

Here is an implementation without using jQuery at all -
http://thezillion.wordpress.com/2012/09/27/javascript-draggable-2-no-jquery

Embed the JS file (http://zillionhost.xtreemhost.com/tzdragg/tzdragg.js) in your HTML code, and put the following code -

<script>
win.onload = function(){
 tzdragg.drag('elem1, elem2, ..... elemn');
 // ^ IDs of the draggable elements separated by a comma.
}
</script>

And the code is also easy to learn.
http://thezillion.wordpress.com/2012/08/29/javascript-draggable-no-jquery

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
QuestionholyredbeardView Question on Stackoverflow
Solution 1 - JqueryAndrew WhitakerView Answer on Stackoverflow
Solution 2 - JqueryTaufik NurrohmanView Answer on Stackoverflow
Solution 3 - Jqueryniente00View Answer on Stackoverflow
Solution 4 - Jqueryuser4602228View Answer on Stackoverflow
Solution 5 - Jqueryuser950658View Answer on Stackoverflow
Solution 6 - JquerySamsView Answer on Stackoverflow
Solution 7 - JqueryRichardView Answer on Stackoverflow
Solution 8 - JqueryHsinhsin HungView Answer on Stackoverflow
Solution 9 - JqueryWasim A.View Answer on Stackoverflow
Solution 10 - Jqueryuser17726210View Answer on Stackoverflow
Solution 11 - JqueryJohn BergView Answer on Stackoverflow
Solution 12 - JquerythezillionView Answer on Stackoverflow