drag and drop div element not work well - javascript

I've created a simple code to drag and drop div element but not work well.
When you drag the div element quickly to any direction top, left, right, down, the mouse cursor will leave the div element, Although I'm still press on the button .
HTML
<div id="box"></div>
CSS
div#box {
background-color:yellowgreen;
width:150px; height:100px;
border:1px solid #ffff66;
position:relative;
}
JavaScript
var elem = document.getElementById('box');
var PositionX = 0;
var PositionY = 0;
var MouseX = 0
var MouseY = 0;
var mouseDown = false;
elem.onmousedown = function(e) {
PositionX = elem.offsetLeft;
PositionY = elem.offsetTop;
MouseX = e.clientX;
MouseY = e.clientY;
mouseDown = true;
};
elem.onmousemove = function(e) {
if (mouseDown) {
elem.style.left = PositionX + e.clientX - MouseX + "px";
elem.style.top = PositionY + e.clientY - MouseY + "px";
}
};
elem.onmouseover = function(e) {
elem.style.cursor = 'move';
};
elem.onmouseup = function(e) {
mouseDown = false;
};
You can see online

Try changing this one line:
elem.onmousemove = function(e) {
to:
document.onmousemove = function(e) {

try this hope it would have your work done :
var elem= document.getElementbyId('<%=box.ClientID%>');
elem.onmousemove= function(e) {
if (mouseDown) {
elem.style.left = PositionX + e.clientX - MouseX + "px";
elem.style.top = PositionY + e.clientY - MouseY + "px";
}
};

Related

Dragging element not maintaining position relative to cursor when zooming body (using scale)

I want to achieve 2 things on my page:
drag HTML elements on the screen;
zoom the page using the "wheel" event.
I can accomplish both of these as follows:
Element Drag:
function make_element_draggable(id) {
const elem = document.getElementById(id);
elem.style.position = "absolute";
let initX, initY, firstX, firstY, whichDown;
window.addEventListener("mouseup", function() {
if(whichDown) {
whichDown.style.zIndex = 0;
}
whichDown = null;
}, false);
window.addEventListener("mousemove", draggable, false);
elem.addEventListener("mousedown", function(e) {
e.preventDefault();
whichDown = this;
initX = this.offsetLeft;
initY = this.offsetTop;
firstX = e.pageX;
firstY = e.pageY;
});
function draggable(e) {
e.preventDefault();
if(!whichDown) return;
whichDown.style.zIndex = 9;
whichDown.style.left = initX + e.pageX - firstX + "px";
whichDown.style.top = initY + e.pageY - firstY + "px";
}
}
Page Zoom:
function page_zoom(container_id) {
zoom = 1;
zoom_speed = 0.1;
const container = document.getElementById(container_id);
document.addEventListener("wheel", function(e) {
if(e.deltaY > 0) {
container.style.transform = `scale(${zoom += zoom_speed})`;
} else {
container.style.transform = `scale(${zoom -= zoom_speed})`;
}
});
}
HTML:
<body id="body">
<div id="container">
<a id="text_1">TEXT 1</a>
</div>
</body>
Usage:
make_element_draggable("text_1")
page_zoom("body")
Here is the result.
Notice how the drag works perfectly when no zoom in enabled (text remains centered in the circle), but once zoom in enabled the text no longer maintains its position relative to the cursor.
Is there a way to compensate for zoom amount, perhaps using it as a factor to adjust the top and left settings of the drag function?
Here is a CODEPEN showing all the code. Drag the text element, then zoom using your mouse wheel (trackpad on Mac), and notice the incorrect positioning of the text element relative to the cursor.
You forgot to take in account zoom when dragging:
function make_element_draggable(id) {
const elem = document.getElementById(id);
elem.style.position = "absolute";
let initX, initY, firstX, firstY, whichDown;
window.addEventListener("mouseup", function() {
if(whichDown) {
whichDown.style.zIndex = 0;
}
whichDown = null;
}, false);
window.addEventListener("mousemove", draggable, false);
elem.addEventListener("mousedown", function(e) {
e.preventDefault();
whichDown = this;
initX = this.offsetLeft;
initY = this.offsetTop;
firstX = e.pageX;
firstY = e.pageY;
});
function draggable(e) {
e.preventDefault();
if(!whichDown) return;
whichDown.style.zIndex = 9;
whichDown.style.left = initX + (e.pageX - firstX)/zoom + "px";
whichDown.style.top = initY + (e.pageY - firstY)/zoom + "px";
}
}
function page_zoom(container_id) {
zoom = 1;
zoom_speed = 0.1;
const container = document.getElementById(container_id);
document.addEventListener("wheel", function(e) {
if(e.deltaY > 0) {
container.style.transform = `scale(${zoom += zoom_speed})`;
} else {
container.style.transform = `scale(${zoom -= zoom_speed})`;
}
});
}
page_zoom("body")
make_element_draggable("text_1")
<body id="body">
<div id="container">
<a id="text_1">TEXT 1</a>
</div>
</body>

Can't drop element after the drag

I'm new in JS and trying to make simple interface with pure JS, where User can dynamically add elements and move them around.
I found solutions for create elements and drag'n'drop elements, that perfectly works separatly. But when I tried to unite them, drop function stop working...
What am I doing wrong?
Template:
<head>
<title>Int Demo</title>
<script src='js/script.js'></script>
<style type="text/css">
.wrapper {width: 300px; height: 200px; background: #A3A1A1;}
.textblock {cursor: pointer; background: red;}
</style>
</head>
<body>
<div class="button" id="button">Add Textbox</div>
<div class="wrapper" id="wrapper"></div>
</body>
</html>
My JS file:
document.addEventListener("DOMContentLoaded", function() { init(); }, false);
function init() {
button = document.getElementById('button');
wrapper = document.getElementById('wrapper');
button.addEventListener('click', btnClick, false);
wrapper.ondblclick = catchIt;
}
//add element
function btnClick() {
wrapper.innerHTML += '<p class="draggable textblock">Text Here!</p>';
sessionStorage.inputBoxes = wrapper;
console.log(sessionStorage);
}
// Activate Drag'n'Drop
document.onmousedown = function(e) {
var dragElement = e.target;
if (!dragElement.classList.contains('draggable')) return;
var coords, shiftX, shiftY;
startDrag(e.clientX, e.clientY);
document.onmousemove = function(e) {
moveAt(e.clientX, e.clientY);
};
dragElement.onmouseup = function() {
finishDrag();
};
function startDrag(clientX, clientY) {
shiftX = clientX - dragElement.getBoundingClientRect().left;
shiftY = clientY - dragElement.getBoundingClientRect().top;
dragElement.style.position = 'fixed';
document.body.appendChild(dragElement);
moveAt(clientX, clientY);
};
function finishDrag() {
dragElement.style.top = parseInt(dragElement.style.top) + pageYOffset + 'px';
dragElement.style.position = 'absolute';
document.onmousemove = null;
dragElement.onmouseup = null;
}
function moveAt(clientX, clientY) {
var newX = clientX - shiftX;
var newY = clientY - shiftY;
// bottom offset
var newBottom = newY + dragElement.offsetHeight;
if (newBottom > document.documentElement.clientHeight) {
var docBottom = document.documentElement.getBoundingClientRect().bottom;
var scrollY = Math.min(docBottom - newBottom, 10);
if (scrollY < 0) scrollY = 0;
window.scrollBy(0, scrollY);
newY = Math.min(newY, document.documentElement.clientHeight - dragElement.offsetHeight);
}
// top offset
if (newY < 0) {
var scrollY = Math.min(-newY, 10);
if (scrollY < 0) scrollY = 0;
window.scrollBy(0, -scrollY);
newY = Math.max(newY, 0);
}
if (newX < 0) newX = 0;
if (newX > document.documentElement.clientWidth - dragElement.offsetHeight) {
newX = document.documentElement.clientWidth - dragElement.offsetHeight;
}
dragElement.style.left = newX + 'px';
dragElement.style.top = newY + 'px';
}
return false;
}
I changed
dragElement.onmouseup = function() {
finishDrag();
};
into
document.onmouseup = function() {
finishDrag();
};
and it started working for me. This does mean that the end user will have to keep the mouse button pressed down to continue dragging and that the element will be placed immediately on mouse button up. But I'm assuming that this is the desired functionality, or do you want the drop to happen only on a second mouse click?

How to spoof dragging all elements of the same class with javascript?

I'm trying to make it so that a bunch of elements will move when the user holds down their mouse button and then drags the mouse. I'm trying to do this by listening to the mousedown and mousemove events and comparing their locations. The difference in the locations of is used to calculate how far to move all of the elements. The goal is that it will feel like all of the elements have been dragged. For some reason though, my approach results in the elements flying all over the place.
Here's an example of what I'm trying to do:
window.onload = function(){
var mouse = {isDown : false, lastX : null, lastY : null };
document.body.addEventListener("click", function(event){
var el = document.createElement("div");
el.className = "box";
el.style.left = event.clientX + "px";
el.style.top = event.clientY + "px";
el.style.backgroundColor = "BLACK";
el.style.width = "16px";
el.style.height = "16px";
el.style.position = "absolute";
document.body.appendChild(el);
});
document.body.addEventListener("mousedown", function(event){
mouse.isDown = true;
mouse.lastX = event.clientX;
mouse.lastY = event.clientY;
});
document.body.addEventListener("mouseup", function(){
mouse.isDown = false;
mouse.lastX = null;
mouse.lastY = null;
});
var removePx = function(string){return string.substring(0, string.length -2);}
document.body.addEventListener("mousemove", function(event){
console.log("move (" + event.clientX + "," + event.clientY + ")");
if(mouse.isDown){
var deltaX = event.clientX - mouse.lastX;
var deltaY = event.clientY - mouse.lastY;
console.log("DeltaX " + deltaX);
console.log("DeltaY " + deltaY);
var boxes = document.getElementsByClassName("box");
for(var i = 0; i<boxes.length; i++){
var box = boxes[i];
box.style.left = removePx(box.style.left) + deltaX + "px";
box.style.top = removePx(box.style.top) + deltaY + "px";
}
mouse.lastX = event.clientX;
mouse.lastY = event.clientY;
}
});
}
What's going wrong here? Also, is there a better way to accomplish this?
Regarding your code, i'd say that transform is preferrable regarding positioning for this kind of thing (instead of left/top) - see the discussion http://www.paulirish.com/2012/why-moving-elements-with-translate-is-better-than-posabs-topleft/.
Anyway, i didn't take a closer look at your code, but instead, tried a solution myself to what i understood of it. I just used a simple pattern regarding drag and drop which is:
onmousedown - setState to moving, store the clicked point, get the current matrix of the transformation applied
onmousemove - calculate dx, dy, accumulate this differences in the matrix, update current x and y in the state
onmouseup - just remove the moving state
Here's a snippet:
var main = document.querySelector('main');
var movable = [].slice.call(document.querySelectorAll('.movable'));
var _state = {
x: 0,
y: 0,
matrix: [1, 0, 0, 1, 0, 0],
moving: false
};
movable.forEach(function (elem) {
elem.style.transform = 'matrix(' + _state.matrix.join(',') + ')'
});
function onMouseDown (e) {
_state.moving = true;
_state.x = e.clientX;
_state.y = e.clientY;
_state.matrix = matrixToArray(e.target.style.transform);
}
function matrixToArray (matrix) {
return matrix
.match(/matrix\((.*)\)/)[1]
.split(' ')
.join('')
.split(',')
.map(function (a) {
return +a;
});
}
function onMouseMove (e) {
if (!_state.moving)
return;
var dx = e.clientX - _state.x;
var dy = e.clientY - _state.y;
_state.matrix[4] += dx;
_state.matrix[5] += dy;
var transf = 'matrix(' + _state.matrix.join(',') + ')'
movable.forEach(function (elem) {
elem.style.transform = transf;
});
_state.x = e.clientX;
_state.y = e.clientY;
}
function onMouseUp (e) {
_state.moving = false;
_state.x = e.clientX;
_state.y = e.clientY;
}
main.addEventListener('mousemove', onMouseMove);
main.addEventListener('mouseup', onMouseUp);
movable.forEach(function (elem) {
elem.addEventListener('mousedown', onMouseDown);
});
html,
body,
main {
width: 100%;
height: 100%;
}
div {
width: 50px;
height: 50px;
position: absolute;
}
#d1 { background: black; left: 10px; top: 10px;}
#d2 { background: brown; left: 70px; top: 10px;}
#d3 { background: green; left: 10px; top: 70px ;}
#d4 { background: purple; left: 70px; top: 70px ;}
<main>
<div id="d1" class="movable"></div>
<div id="d2" class="movable"></div>
<div id="d3" class="not-movable"></div>
<div id="d4" class="movable"></div>
</main>
ps.: this is not all that much efficient. One can surely iterate on this and create a better version of it!

Simple drag and drop code

Im struggling with seemingly a simple javascript exercise, writing a vanilla drag and drop. I think Im making a mistake with my 'addeventlisteners', here is the code:
var ele = document.getElementsByClassName ("target")[0];
var stateMouseDown = false;
//ele.onmousedown = eleMouseDown;
ele.addEventListener ("onmousedown" , eleMouseDown , false);
function eleMouseDown () {
stateMouseDown = true;
document.addEventListener ("onmousemove" , eleMouseMove , false);
}
function eleMouseMove (ev) {
do {
var pX = ev.pageX;
var pY = ev.pageY;
ele.style.left = pX + "px";
ele.style.top = pY + "px";
document.addEventListener ("onmouseup" , eleMouseUp , false);
} while (stateMouseDown === true);
}
function eleMouseUp () {
stateMouseDown = false;
document.removeEventListener ("onmousemove" , eleMouseMove , false);
document.removeEventListener ("onmouseup" , eleMouseUp , false);
}
Here's a jsfiddle with it working: http://jsfiddle.net/fpb7j/1/
There were 2 main issues, first being the use of onmousedown, onmousemove and onmouseup. I believe those are only to be used with attached events:
document.body.attachEvent('onmousemove',drag);
while mousedown, mousemove and mouseup are for event listeners:
document.body.addEventListener('mousemove',drag);
The second issue was the do-while loop in the move event function. That function's being called every time the mouse moves a pixel, so the loop isn't needed:
var ele = document.getElementsByClassName ("target")[0];
ele.addEventListener ("mousedown" , eleMouseDown , false);
function eleMouseDown () {
stateMouseDown = true;
document.addEventListener ("mousemove" , eleMouseMove , false);
}
function eleMouseMove (ev) {
var pX = ev.pageX;
var pY = ev.pageY;
ele.style.left = pX + "px";
ele.style.top = pY + "px";
document.addEventListener ("mouseup" , eleMouseUp , false);
}
function eleMouseUp () {
document.removeEventListener ("mousemove" , eleMouseMove , false);
document.removeEventListener ("mouseup" , eleMouseUp , false);
}
By the way, I had to make the target's position absolute for it to work.
you can try this fiddle too, http://jsfiddle.net/dennisbot/4AH5Z/
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>titulo de mi pagina</title>
<style>
#target {
width: 100px;
height: 100px;
background-color: #ffc;
border: 2px solid blue;
position: absolute;
}
</style>
<script>
window.onload = function() {
var el = document.getElementById('target');
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';
}
};
}
</script>
</head>
<body>
<div id="target" style="left: 10px; top:20px"></div>
</body>
</html>
I've just made a simple drag.
It's a one liner usage, and it handles things like the offset of the mouse to the top left corner of the element, onDrag/onStop callbacks, and SVG elements dragging
Here is the code.
// simple drag
function sdrag(onDrag, onStop) {
var startX = 0;
var startY = 0;
var el = this;
var dragging = false;
function move(e) {
el.style.left = (e.pageX - startX ) + 'px';
el.style.top = (e.pageY - startY ) + 'px';
onDrag && onDrag(el, e.pageX, startX, e.pageY, startY);
}
function startDragging(e) {
if (e.currentTarget instanceof HTMLElement || e.currentTarget instanceof SVGElement) {
dragging = true;
var left = el.style.left ? parseInt(el.style.left) : 0;
var top = el.style.top ? parseInt(el.style.top) : 0;
startX = e.pageX - left;
startY = e.pageY - top;
window.addEventListener('mousemove', move);
}
else {
throw new Error("Your target must be an html element");
}
}
this.addEventListener('mousedown', startDragging);
window.addEventListener('mouseup', function (e) {
if (true === dragging) {
dragging = false;
window.removeEventListener('mousemove', move);
onStop && onStop(el, e.pageX, startX, e.pageY, startY);
}
});
}
Element.prototype.sdrag = sdrag;
and to use it:
document.getElementById('my_target').sdrag();
You can also use onDrag and onStop callbacks:
document.getElementById('my_target').sdrag(onDrag, onStop);
Check my repo here for more details:
https://github.com/lingtalfi/simpledrag
this is how I do it
var MOVE = {
startX: undefined,
startY: undefined,
item: null
};
function contentDiv(color, width, height) {
var result = document.createElement('div');
result.style.width = width + 'px';
result.style.height = height + 'px';
result.style.backgroundColor = color;
return result;
}
function movable(content) {
var outer = document.createElement('div');
var inner = document.createElement('div');
outer.style.position = 'relative';
inner.style.position = 'relative';
inner.style.cursor = 'move';
inner.style.zIndex = 1000;
outer.appendChild(inner);
inner.appendChild(content);
inner.addEventListener('mousedown', function(evt) {
MOVE.item = this;
MOVE.startX = evt.pageX;
MOVE.startY = evt.pageY;
})
return outer;
}
function bodyOnload() {
document.getElementById('td1').appendChild(movable(contentDiv('blue', 100, 100)));
document.getElementById('td2').appendChild(movable(contentDiv('red', 100, 100)));
document.addEventListener('mousemove', function(evt) {
if (!MOVE.item) return;
if (evt.which!==1){ return; }
var dx = evt.pageX - MOVE.startX;
var dy = evt.pageY - MOVE.startY;
MOVE.item.parentElement.style.left = dx + 'px';
MOVE.item.parentElement.style.top = dy + 'px';
});
document.addEventListener('mouseup', function(evt) {
if (!MOVE.item) return;
var dx = evt.pageX - MOVE.startX;
var dy = evt.pageY - MOVE.startY;
var sty = MOVE.item.style;
sty.left = (parseFloat(sty.left) || 0) + dx + 'px';
sty.top = (parseFloat(sty.top) || 0) + dy + 'px';
MOVE.item.parentElement.style.left = '';
MOVE.item.parentElement.style.top = '';
MOVE.item = null;
MOVE.startX = undefined;
MOVE.startY = undefined;
});
}
bodyOnload();
table {
user-select: none
}
<table>
<tr>
<td id='td1'></td>
<td id='td2'></td>
</tr>
</table>
While dragging, the left and right of the style of the parentElement of the dragged element are continuously updated. Then, on mouseup (='drop'), "the changes are committed", so to speak; we add the (horizontal and vertical) position changes (i.e., left and top) of the parent to the position of the element itself, and we clear left/top of the parent again. This way, we only need JavaScript variables for pageX, pageY (mouse position at drag start), while concerning the element position at drag start, we don't need JavaScript variables for that (just keeping that information in the DOM).
If you're dealing with SVG elements, you can use the same parent/child/commit technique. Just use two nested g, and use transform=translate(dx,dy) instead of style.left=dx, style.top=dy

Div does not follow drag-bar when moving

Im trying to add a drag handle to an div , but the div doesn't move, just the handel.
But if I change the position to position absolute to the div that are supposed to move, I can actually move around the div, but from everywhere and not just the drag handle.
Any tips ? I created a jsfiddle for this.
http://jsfiddle.net/dymond/tQdFZ/11/
Some code.
var draggable = document.getElementsByClassName('hand'),
draggableCount = draggable.length,
i, currZ = 1;
function startDrag(evt) {
var diffX = evt.clientX - this.offsetLeft,
diffY = evt.clientY - this.offsetTop,
that = this;
this.style.opacity = "0.5";
this.style.zIndex = currZ++;
function moveAlong(evt) {
that.style.left = (evt.clientX - diffX) + 'px';
that.style.top = (evt.clientY - diffY) + 'px';
}
function stopDrag() {
document.removeEventListener('mousemove', moveAlong);
document.removeEventListener('mouseup', stopDrag);
changeClass()
}
function changeClass() {
var diceClass = document.getElementsByClassName("hand");
for (var i = 0; i < diceClass.length; i++) {
diceClass[i].style.opacity = "1";
}
}
document.addEventListener('mouseup', stopDrag);
document.addEventListener('mousemove', moveAlong);
}
for (i = 0; i < draggableCount; i += 1) {
draggable[i].addEventListener('mousedown', startDrag);
}
Try setting css:
.draggable { position: absolute; ...
and change js:
function moveAlong(evt) {
that.parentNode.style.left = (evt.clientX - diffX) + 'px';
that.parentNode.style.top = (evt.clientY - diffY) + 'px';
}
Since you want to move the parentNode, by draging the handle..

Categories

Resources