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;
});
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>
$(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;});
});
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('');
}
});
}
});
});
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
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
});
};
});
});
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
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.
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.
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);
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;
}
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
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;
}
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");
}
}
Source: Stackoverflow.com