How to make a draggable for touch? - javascript

I want the orange rectangle to be draggable using mouse or touch. The function for the mouse is working for me, so I tried copying it and replacing mousedown with ontouchstart, mousemove with ontouchmove and mouseup with ontouchend but it doesn't seem to move. Any suggestions? Thanks!
var move = document.querySelector('.move');
move.addEventListener('mousedown', mousedown);
move.addEventListener('ontouchstart', ontouchstart);
function mousedown() {
move.addEventListener('mousemove', mousemove);
move.addEventListener('mouseup', mouseup);
function mousemove(e){
var x = e.clientX - 100 + 'px';
var y = e.clientY - 100 + 'px';
this.style.left = x;
this.style.top = y;
}
function mouseup() {
move.removeEventListener('mousemove', mousemove)
}
}
function ontouchstart() {
move.addEventListener('ontouchmove', ontouchmove);
move.addEventListener('ontouchend', ontouchend);
function ontouchmove(e){
var x = e.clientX - 100 + 'px';
var y = e.clientY - 100 + 'px';
this.style.left = x;
this.style.top = y;
}
function ontouchend() {
move.removeEventListener('ontouchmove', ontouchmove)
}
}
.move {
height: 200px;
width: 200px;
background: orange;
position: fixed;
}
<body>
<div class="move"></div>
<script src="script.js"></script>
</body>

For one, the names of your events are incorrect. Omit the on prefix.
Second, touchmove works a little different from mousemove. The event parameter that gets passed to touchmove does not have a clientX or clientY property. Instead it contains a TouchList that needs to be iterated. See below:
var move = document.querySelector('.move');
move.addEventListener('mousedown', mousedown);
move.addEventListener('touchstart', ontouchstart);
function mousedown() {
move.addEventListener('mousemove', mousemove);
move.addEventListener('mouseup', mouseup);
function mousemove(e) {
var x = e.clientX - 100 + 'px';
var y = e.clientY - 100 + 'px';
this.style.left = x;
this.style.top = y;
}
function mouseup() {
move.removeEventListener('mousemove', mousemove)
}
}
function ontouchstart() {
move.addEventListener('touchmove', ontouchmove);
move.addEventListener('touchend', ontouchend);
function ontouchmove(e) {
e.preventDefault();
for (target of e.targetTouches) {
var x = target.clientX - 100 + "px";
var y = target.clientY - 100 + "px";
this.style.left = x;
this.style.top = y;
}
}
function ontouchend() {
move.removeEventListener('touchmove', ontouchmove)
}
}
.move {
height: 200px;
width: 200px;
background: orange;
position: fixed;
}
<body>
<div class="move"></div>
<script src="script.js"></script>
</body>
For more information see Touch Events and Using Touch Events.

Related

VueJS dragging an element on occasion causes it to stick to the mouse pointer

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>

How to use event listeners to make click, drag, and drop function? [duplicate]

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

Dragover: Can't move to left and top

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>

Movable Popup Directive makes Popup Jump to corner of Screen

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.

Drag and drop position relative

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>

Categories