How to drag an element using javascript? - javascript

I'm working on a project which needs pictures to be draggable across the page. I found jQuery UI to be a very useful solution which is working as expected but sadly I cannot use it in the project. Instead, I needed to do it using pure javascript only. With some googling, I came up with this: http://jsfiddle.net/tovic/Xcb8d/light/
This was perfect, the only problem with it was that it was using IDs which means I can't have multiple draggable items across the page. I modified it to use classes: http://jsfiddle.net/Xcb8d/690/. The problem with the code is that even though both elements were draggable, once you start dragging the second element it's x_elem and y_elem are off. This leads the element to move to a far direction from your mouse. Does anyone know what could be causing this?
var selected = null, // Object of the element to be moved
x_pos = 0, y_pos = 0, // Stores x & y coordinates of the mouse pointer
x_elem = 0, y_elem = 0; // Stores top, left values (edge) of the element
// Will be called when user starts dragging an element
function _drag_init(elem) {
// Store the object of the element which needs to be moved
selected = elem;
x_elem = x_pos - selected.offsetLeft;
y_elem = y_pos - selected.offsetTop;
}
// Will be called when user dragging an element
function _move_elem(e) {
x_pos = document.all ? window.event.clientX : e.pageX;
y_pos = document.all ? window.event.clientY : e.pageY;
if (selected !== null) {
selected.style.left = (x_pos - x_elem) + 'px';
selected.style.top = (y_pos - y_elem) + 'px';
}
}
// Destroy the object when we are done
function _destroy() {
selected = null;
}
// Bind the functions...
var draggables = document.getElementsByClassName('draggable-element');
for(i = 0; i < draggables.length; i++) {
draggables[i].onmousedown = function () {
_drag_init(this);
return false;
};
}
document.onmousemove = _move_elem;
document.onmouseup = _destroy;

Related

How do I calculate and determine the area at which the div must be dropped?

I am building a drag and drop application purely in Javascript. I have coded the drag part where the element can be dragged and dropped randomly in the page. Now, I have built a drop zone that contains 9 boxes(divs) wherein 9 divs must be dropped. I can't think of an approach that will help me accomplish this task. I am thinking of making those divs 'absolute' and re-build them use top & left attributes. But how should I proceed further? How will the div that I drag i.e onmousedown will come to know that onmouseup it should drop at the specified location. Example: If I select a div numbered 1, it should drop at target numbered 1.
Here's the Javascript I am using for selecting and dragging:
window.onload = function() {
var el = document.getElementById('block1');
var mover = false, x, y, posx, posy, first = true;
el.onmousedown = function() {
mover = true;
};
el.onmouseup = function() {
mover = false;
first = true;
};
el.onmousemove = function(e) {
if (mover) {
if (first) {
x = e.offsetX;
y = e.offsetY;
first = false;
}
posx = e.pageX - x;
posy = e.pageY - y;
this.style.left = posx + 'px';
this.style.top = posy + 'px';
}
};
};
I would have the targets recognize a "onmouseenter" and set a Boolean to be true for that target, then set it to false "onmouseleave". then "onmouseup" check all of the booleans and if div1 has been dropped and target1 is true then div1 position = target position.
I know this is a pseudo code answer but its just my thought process on ho to solve the problem.

Drag each element separately

I'm making a gadget system in javascript like Win7 Sidebar, but I can use only one element. If I use two, all elements can have the same position or don't work. I need can use more than one elements and drag each one separately (each one with his particular positions).
I have only one element. How can I turn this to work with more than one?
var selected = null, // Object of the element to be moved
x_pos = 0, y_pos = 0, // Stores x & y coordinates of the mouse pointer
x_elem = 0, y_elem = 0; // Stores top, left values (edge) of the element
// Will be called when user starts dragging an element
function _drag_init(elem) {
// Store the object of the element which needs to be moved
selected = elem;
x_elem = x_pos - selected.offsetLeft;
y_elem = y_pos - selected.offsetTop;
}
// Will be called when user dragging an element
function _move_elem(e) {
x_pos = document.all ? window.event.clientX : e.pageX;
y_pos = document.all ? window.event.clientY : e.pageY;
if (selected !== null) {
selected.style.left = (x_pos - x_elem) + 'px';
selected.style.top = (y_pos - y_elem) + 'px';
}
}
// Destroy the object when we are done
function _destroy() {
selected = null;
}
// Bind the functions...
document.getElementById('draggable-element').onmousedown = function () {
_drag_init(this);
return false;
};
document.onmousemove = _move_elem;
document.onmouseup = _destroy;
body {padding:10px}
#draggable-element {
width:125px;
height:125px;
background-color:#666;
color:white;
padding:10px 12px;
cursor:move;
position:relative; /* important (all position that's not `static`) */
}
<div id="draggable-element">Gadget!<div style="width:20px;height:100%;background:#000;position:absolute;top:0;right:-25px"></div></div>
fiddle
Two things to note:
If you want to do something on multiple elements you need to either use class's or tags.
In your _drag_init() function, you set the x_elem and y_elem equal to x_pos and y_pos which are changed in you _move_elem() function. So it add's in the current positioning to the elements offset. So just get rid of the selected.Offset
However, there are still some other calculation issues that you need to work out
var selected = null, // Object of the element to be moved
x_pos = 0, y_pos = 0, // Stores x & y coordinates of the mouse pointer
x_elem = 0, y_elem = 0; // Stores top, left values (edge) of the element
// Will be called when user starts dragging an element
function _drag_init(elem) {
// Store the object of the element which needs to be moved
selected = elem;
x_elem = x_pos ;
y_elem = y_pos;
}
// Will be called when user dragging an element
function _move_elem(e) {
x_pos = document.all ? window.event.clientX : e.pageX;
y_pos = document.all ? window.event.clientY : e.pageY;
if (selected !== null) {
selected.style.left = (x_pos - x_elem) + 'px';
selected.style.top = (y_pos - y_elem) + 'px';
}
}
// Destroy the object when we are done
function _destroy() {
selected = null;
}
// Bind the functions...
var draggables = document.getElementsByClassName('draggable-element');
for(var i = 0; i < draggables.length; i++){
draggables[i].onmousedown = function () {
_drag_init(this);
return false;
};
}
document.onmousemove = _move_elem;
document.onmouseup = _destroy;
body {padding:10px}
.draggable-element {
width:125px;
height:125px;
background-color:#666;
color:white;
padding:10px 12px;
cursor:move;
position:relative; /* important (all position that's not `static`) */
}
<div class="draggable-element">Gadget!<div style="width:20px;height:100%;background:#000;position:absolute;top:0;right:-25px"></div></div>
<div class="draggable-element">Gadget!<div style="width:20px;height:100%;background:#000;position:absolute;top:0;right:-25px"></div></div>
<div class="draggable-element">Gadget!<div style="width:20px;height:100%;background:#000;position:absolute;top:0;right:-25px"></div></div>
<div class="draggable-element">Gadget!<div style="width:20px;height:100%;background:#000;position:absolute;top:0;right:-25px"></div></div>
<div class="draggable-element">Gadget!<div style="width:20px;height:100%;background:#000;position:absolute;top:0;right:-25px"></div></div>
<div class="draggable-element">Gadget!<div style="width:20px;height:100%;background:#000;position:absolute;top:0;right:-25px"></div></div>

Make a div follow the mouse just when the mouse is on mousedown

I'm trying to make a jquery function to follow the mouse coursor with a div, when it is on mousedown and when it is on mouseup it stay in the last position it was.
any sugestion.
Why not simply use drag and drop by jquery:
<script>
$(function() {
$( "#draggable" ).draggable();
});
</script>
Jquery draggable
I've put together a simple working example that defines a Draggable object. You specify the drag item (the element that you're moving around), as well as a drag boundary (the space—or element—that you are moving the item inside of). The concept of a boundary is important if you ever want to restrict a draggable item to a certain space on the page (such as a container), or define a relative coordinate system on which to base your math.
My solution isn't the fastest, but it demonstrates the concept:
$(function() {
window.mousedown = 0;
$(window).on('mousedown mouseup', function(e) {
if(e.type == 'mousedown') { this.mousedown++; }
else { this.mousedown--; }
});
var Draggable = function(dragItem, dragBoundary) {
this.item = $(dragItem).css('position', 'absolute');
this.item.on('mousemove', $.proxy(this.handleDragEvent, this));
this.boundary = $(dragBoundary).css('position', 'relative');
};
Draggable.prototype.handleDragEvent = function(e) {
if(window.mousedown) {
var mousePosition = this.mapToBoundary([e.clientX, e.clientY]);
var mouseX = mousePosition[0],
mouseY = mousePosition[1];
if(typeof this.prevMouseX == "undefined") this.prevMouseX = mouseX;
if(typeof this.prevMouseY == "undefined") this.prevMouseY = mouseY;
this.itemX = this.item.offset().left - this.boundary.offset().left;
this.itemY = this.item.offset().top - this.boundary.offset().top;
var deltaX = mouseX - this.prevMouseX,
deltaY = mouseY - this.prevMouseY;
this.item.css({
'left': this.itemX + deltaX,
'top': this.itemY + deltaY
});
this.prevMouseX = mouseX;
this.prevMouseY = mouseY;
}
};
Draggable.prototype.mapToBoundary = function(coord) {
var x = coord[0] - this.boundary.offset().left;
var y = coord[1] - this.boundary.offset().top;
return [x,y];
};
var draggable = new Draggable($('.draggable'), $('.container'));
});
Notice that we are maintaining a mousedown value on global, allowing us to determine when it would be appropriate to drag around our element (we only add a mousemove listener to the drag item itself). I've also included a spacer div above the boundary div to demonstrate how you can move the boundary anywhere around the page and the coordinate system is still accurate. The code to actually restrict a draggable item within its assigned boundary could be written using simple math.
Here is the fiddle: http://jsfiddle.net/bTh9s/3/
EDIT:
Here is the start to some code for restricting a Draggable item within its container.
Draggable.prototype.restrictItemToBoundary = function() {
var position = this.item.position();
position.right = position.left + this.item.outerWidth();
position.bottom = position.top + this.item.outerHeight();
if(position.left <= 0) {
this.item.css('left', 1);
} else if(position.right >= this.boundary.outerWidth()) {
this.item.css('left', this.boundary.outerWidth() - this.item.outerWidth());
}
if(position.top <= 0) {
this.item.css('top', 1);
} else if(position.bottom >= this.boundary.outerHeight()) {
this.item.css('top', this.boundary.outerHeight() - this.item.outerHeight());
}
};
This method should be called inside of Draggable.handleDragEvent just after you update the CSS positioning of the drag item. It seems this solution is glitchy, but it's a start.

HTML5 Multiple Canvases event listener - how to determine which canvas experienced the event?

I'm new to JS. I'm not using jQuery, and I have a question. I've created a variable number of canvases on a page, all have an eventlistener like so:
for (i=0; i<numberOfCanvases; i++){
var canv = document.createElement("canvas");
canv.addEventListener('click', clickReporter, false);
document.body.appendChild(canv); }
Given the listener function clickReporter:
function clickReporter(e){...}
I am trying to use this function to tell me the mouse position of the click event relative to the canvas:
function getMousePos(canvas, evt){
// get canvas position
var obj = canvas;
var top = 0;
var left = 0;
while (obj && obj.tagName != 'BODY') {
top += obj.offsetTop;
left += obj.offsetLeft;
obj = obj.offsetParent;
}
// return relative mouse position
var mouseX = evt.clientX - left + window.pageXOffset;
var mouseY = evt.clientY - top + window.pageYOffset;
return {
x: mouseX,
y: mouseY
};
}
which i found from this tutorial: http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/
The problem is, it assumes there is only one canvas, and I do have a list of canvases right now that are placed on a webpage, but I was wondering, given just the clickReporter() function, is there an easy way to determine which canvas was selected? a function like evt.getCanvas() or evt.getParentCanvas()?
I'm asking because when an event occurs (a mouse click on 1 of many canvases, I want to create actions at that location for ONLY that canvas)
function clickReporter(e){
console.log( this ); // in a eventListener , this point to the element fire the event
console.log( e.target ); // in fireFox and webkit, e.target point to the element fire the event
}
I would think evt.target (event.target) would work.

creating multiple custom divs jquery

I am building a tool where multiple boxes (divs, in this case) can be drawn by clicking and dragging the mouse. I want a new div to be drawn each time the function is called. But with what i have now, i am unable to make the height and width of the div follow the mouse's movement.
Here is my code:
$('#work_area').click(function(e) {
var increment = increment + 1; //has been defined in the global scope
var newBox = 'newBox' + increment;
var workAreaOffset = $('#work_area').offset();
if (ctr == 0) {
var clickLocX = e.pageX; //x coordinate of origin of select box
var clickLocY = e.pageY; //y coordinate of origin of select box
$('<div>').attr({
'class':'newBox',
zIndex:'15'
})
.addClass(newBox) //set new class for every box
.css({
top:clickLocY - workAreaOffset.top,
left:clickLocX - workAreaOffset.left
})
.appendTo('#work_area');
ctr = 1; //next stage of select box method reached
if (ctr == 1) {
$('#work_area').mousemove(function(e){
var XpageCoord = e.pageX;
var YpageCoord = e.pageY;
var boxHeight = YpageCoord - clickLocY; //height of the box changes with mouse movement
var boxWidth = XpageCoord - clickLocX; //width of the box changes with mouse movement
$(newBox).css({
height:boxHeight + 'px', //connect mouse movement with css class for select box
width:boxWidth + 'px'
});
ctr = 2; //next stage of the select box method reached
});
}
}
else if (ctr == 2) {
//$('.newBox').remove(); //select box removed with second click
$('#work_area').css({
cursor: 'default' //cursor changed back to normal
});
$('#work_area').unbind('mousemove'); //mouse movement no longer has effect
$(newBox).appendTo('#work_area');
ctr = 0; //reset
}
else {
$.noop(); //fall back
}
});
Please help?
That was REALLY close to working. The code below will work.
The primary issue is that $(newBox) is not returning anything, because variable newBox is not a well formed jQuery selector. And that's fine, because you're using newBox to return a unique class for each box. All you have to do is modify the two spots where you have $(newBox) to be
$('.' + newBox)
A couple of other questions and pointers:
Why do you have the line
var increment = increment + 1; ?
this declares increment to be a local variable, so it returns 'NaN'
Also, the drag and drop blocks only work if the mouse goes from top left to bottom right.
Anyway, best of luck.
$('#work_area').click(function(e) {
increment = increment + 1; //has been defined in the global scope
var newBox = 'newBox' + increment;
var workAreaOffset = $('#work_area').offset();
if (ctr == 0) {
var clickLocX = e.pageX; //x coordinate of origin of select box
var clickLocY = e.pageY; //y coordinate of origin of select box
$('<div>').attr({
'class':'newBox',
zIndex:'15'
})
.addClass(newBox) //set new class for every box
.css({
top:clickLocY - workAreaOffset.top,
left:clickLocX - workAreaOffset.left
})
.appendTo('#work_area');
ctr = 1; //next stage of select box method reached
if (ctr == 1) {
$('#work_area').mousemove(function(e){
var XpageCoord = e.pageX;
var YpageCoord = e.pageY;
var boxHeight = YpageCoord - clickLocY; //height of the box changes with mouse movement
var boxWidth = XpageCoord - clickLocX; //width of the box changes with mouse movement
$('.' + newBox).css({
height:boxHeight + 'px', //connect mouse movement with css class for select box
width:boxWidth + 'px'
});
ctr = 2; //next stage of the select box method reached
});
}
}
else if (ctr == 2) {
//$('.newBox').remove(); //select box removed with second click
$('#work_area').css({
cursor: 'default' //cursor changed back to normal
});
$('#work_area').unbind('mousemove'); //mouse movement no longer has effect
$('.' + newBox).appendTo('#work_area');
ctr = 0; //reset
}
else {
$.noop(); //fall back
}
});

Categories

Resources