I have a div (which holds a Zoom iFrame) which I would like to move around the screen. However... on occasion if the user is being jerky with the mouse, it sticks to the pointer and the only way you can fix that is by refreshing the page.
Is that something anyone else has experienced and how did you solve it?
I would imagine its something to do with my Javascript portion and how I am listening for some events.
EDIT: Wanted to add that the below code was basically adjusted for Vue from this article: https://javascript.info/mouse-drag-and-drop
Thanks in advance!
HTML:
<div
class="zoom-wrapper"
ref="draggableContainer"
>
<div
#mousedown="dragMouseDown"
ref="grabBar"
</div>
</div>
Javascript
dragMouseDown(event) {
event.preventDefault();
const { draggableContainer, grabBar } = this.$refs;
let shiftX = event.clientX - draggableContainer.getBoundingClientRect().left;
let shiftY = event.clientY - draggableContainer.getBoundingClientRect().top;
draggableContainer.style.position = 'absolute';
draggableContainer.style.zIndex = 1000;
moveAt(event.pageX, event.pageY);
function moveAt(pageX, pageY) {
draggableContainer.style.left = pageX - shiftX + 'px';
draggableContainer.style.top = pageY - shiftY + 'px';
}
function onMouseMove(event) {
moveAt(event.pageX, event.pageY);
}
window.addEventListener('mousemove', onMouseMove);
window.onmouseup = function () {
window.removeEventListener('mousemove', onMouseMove);
grabBar.removeEventListener('mousedown', this.dragMouseDown);
window.onmouseup = null;
};
},
here is a working demo to move the element via click.
I think currently your mistake is how you wanted to remove the eventlistener on mousedown
I hope this demo will give you a hint how to solve your problem.
const { createApp, ref } = Vue;
const app = createApp({
setup() {
let draggableContainer = ref(null)
function mousedown (e) {
window.addEventListener('mousemove', mousemove)
window.addEventListener('mouseup', mouseup)
let prevX = e.clientX
let prevY = e.clientY
function mousemove (e) {
// new x - where is the mouse now
const newX = prevX - e.clientX
const newY = prevY - e.clientY
const rect = draggableContainer.value.getBoundingClientRect()
draggableContainer.value.style.left = rect.left - newX + 'px'
draggableContainer.value.style.top = rect.top - newY + 'px'
prevX = e.clientX
prevY = e.clientY
}
function mouseup () { // remove event listener
window.removeEventListener('mousemove', mousemove)
window.removeEventListener('mouseup', mouseup)
}
}
return {
draggableContainer,
mousedown
}
}
});
app.mount("#demo");
.zoom-wrapper {
width: 250px;
height: 150px;
background-color: #111;
position: absolute;
border: 1px solid #000;
color: #fff;
cursor: move;
}
<script src="https://unpkg.com/vue#next"></script>
<div id="demo">
<div
class="zoom-wrapper"
ref="draggableContainer"
#mousedown="mousedown"
>
insert iframe
</div>
</div>
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
I have an element which I would like to move with the mouse.
var troll = document.getElementById('troll');
troll.addEventListener('dragover', (e) => {
e.preventDefault();
e.target.style.left = e.clientX + 'px';
e.target.style.top = e.clientY + 'px';
}, false);
img {
width: 100px;
cursor: pointer;
position: absolute;
}
<div id="troll">
<img src="http://images.mmorpg.com/features/7909/images/Troll.png" alt="Troll">
</div>
From left to right and from top to bottom it works OK. Not perfect, since the very first move takes a whole space and it doesn't look smooth. But the main problem is that I can't move from right to left or from bottom to top.
Any help would be appreciated.
You wanna use drag not dragover, and some logic to know where you're going up or down or left or top.
var troll = document.getElementById('troll');
var X,Y = 0;
troll.addEventListener('drag', (e) => {
e.preventDefault();
if (e.clientX > X)
{
e.target.style.left = X + 'px';
}
else if (e.clientX < X)
{
e.target.style.left = X-- + 'px';
}
if (e.clientY > Y)
{
e.target.style.top = Y + 'px';
}
else if (e.clientY < Y)
{
e.target.style.top = Y-- + 'px';
}
X = e.clientX;
Y = e.clientY;
}, false);
img {
width: 100px;
cursor: pointer;
position: absolute;
}
<div id="troll">
<img src="http://images.mmorpg.com/features/7909/images/Troll.png" alt="Troll">
</div>
Hello I am very new to AngularJs but I modified a pretty cool directive that allows me to drag a modal popup... however when I click to move it, it jumps to the left hand corner of the screen.
JS:
(function () {
var schemaWizardApp = angular.module('schemaWizardApp');
schemaWizardApp.directive('modaldraggable', function ($document) {
"use strict";
return function (scope, element) {
var startX = 400,
startY = 400,
x = 400,
y = 400;
element= angular.element(document.getElementsByClassName("modal-dialog"));
console.log("added directive");
element.css({
position: 'fixed',
cursor: 'move'
});
element.on('mousedown', function (event) {
// Prevent default dragging of selected content
event.preventDefault();
startX = event.screenX - x;
startY = event.screenY - y;
$document.on('mousemove', mousemove);
$document.on('mouseup', mouseup);
});
function mousemove(event) {
y = event.screenY - startY;
x = event.screenX - startX;
element.css({
top: y + 'px',
left: x + 'px'
});
}
function mouseup() {
$document.unbind('mousemove', mousemove);
$document.unbind('mouseup', mouseup);
}
};
});
})();
CSS:
.modal-dialog {
position: fixed;
left: 40%;
}
So the answer is I had to set x = 400,y = 400; to whatever value on the screen I wanted.
Why when the ball is placed relative positioning when you press the mouse it bounces? Absolute positioning is when this doesn't happen.
var ball = document.querySelector('.ball');
ball.onmousedown = function(event) {
var shiftX = event.pageX - getCoords(this).left,
shiftY = event.pageY - getCoords(this).top;
this.style.position = 'relative';
this.zIndex = 10000;
function move(event) {
this.style.left = event.pageX - shiftX + 'px';
this.style.top = event.pageY - shiftY + 'px';
}
move.call(this, event);
document.onmousemove = function(event) {
move.call(ball, event);
};
this.onmouseup = function(event) {
document.onmousemove = this.onmouseup = null;
};
return false;
};
ball.ondragstart = function() {
return false;
};
function getCoords(elem) {
var box = elem.getBoundingClientRect();
return {
top: box.top + window.pageYOffset,
left: box.left + window.pageXOffset
};
}
body {
margin: 50px;
}
img {
cursor: pointer;
}
<img class="ball" src="https://js.cx/clipart/ball.svg" alt="" />
I guess it's because of the padding of the body element. Please explain.
it seems i found answer
Implementing drag and drop on relatively positioned elements in JavaScript
and as it says, with relative position, your element contain offset of all objects in his parent-tag
and parent's margin and padding too
so when you try to get elemtn's position, you should count it's real offset in parent, see in my code example work with count index
<html>
<body>
<div id=obj1 style="width:100px; height:100px; background:#000; position:relative; " ></div>
<div id=obj2 style="width:100px; height:100px; background:#000; position:relative; " ></div>
<div id=obj3 style="width:100px; height:100px; background:#000; position:relative; " ></div>
<script>
var dragObj, count=0;
function set_drag_drop(obj)
{
if(count>0){
// count margins and divs offset
// body{ margin:10px; }
// height:100px;
obj.adx = 10;
obj.ady = 10 + (count*100)
}else{
obj.adx = 0;
obj.ady = 0;
}
count++;
obj.onmousedown = function(e)
{
var rect = obj.getBoundingClientRect();
obj.dx = rect.left - e.clientX;
obj.dy = rect.top - e.clientY;
obj.isDown = true;
dragObj = this;
}
obj.onmouseup = function(e)
{
obj.isDown = false;
}
document.onmousemove = function(e)
{
if(dragObj && dragObj.isDown)
{
dragObj.style.left = e.pageX -dragObj.adx+ dragObj.dx +"px";
dragObj.style.top = e.pageY -dragObj.ady+ dragObj.dy + "px";
}
}
}
set_drag_drop(document.getElementById("obj1"));
set_drag_drop(document.getElementById("obj2"));
set_drag_drop(document.getElementById("obj3"));
</script>
</html>