'How to make a draggable elements for touch and mouse(drag) events
I have the following code for a drag and drop application which works as expected on desktop, however when I want to use the application on mobile the drag events do not work as expected. I am aware that touch events are required however I am not sure how to go about setting them up and implementing the functions.
<style>
.objects {
display:inline-block;
background-color: #FFF3CC;
border: #DFBC6A 1px solid;
width: 50px;
height: 50px;
margin: 10px;
padding: 8px;
font-size: 18px;
text-align: center;
box-shadow: 2px 2px 2px #999;
cursor: move;
}
#drop_zone {
background-color: #EEE;
border: #999 1px solid;
width: 280px;
height: 200px;
padding: 8px;
font-size: 18px;
}
</style>
<h2 id="app_status">App status...</h2>
<h1>Drop Zone</h1>
<div id="drop_zone" ondragenter="drag_enter(event)" ondrop="drag_drop(event)" ondragover="return false" ondragleave="drag_leave(event)" ></div>
<div id="object1" class="objects" draggable="true" ondragstart="drag_start(event)" ondragend="drag_end(event)">object 1</div>
<div id="object2" class="objects" draggable="true" ondragstart="drag_start(event)" ondragend="drag_end(event)">object 2</div>
<div id="object3" class="objects" draggable="true" ondragstart="drag_start(event)" ondragend="drag_end(event)">object 3</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<script>
function _(id){
return document.getElementById(id);
}
var droppedIn = false;
function drag_start(event) {
_('app_status').innerHTML = "Dragging the "+event.target.getAttribute('id');
event.dataTransfer.dropEffect = "move";
event.dataTransfer.setData("text", event.target.getAttribute('id') );
}
function drag_enter(event) {
_('app_status').innerHTML = "You are dragging over the "+event.target.getAttribute('id');
}
function drag_leave(event) {
_('app_status').innerHTML = "You left the "+event.target.getAttribute('id');
}
function drag_drop(event) {
event.preventDefault(); /* Prevent undesirable default behavior while dropping */
var elem_id = event.dataTransfer.getData("text");
_('app_status').innerHTML = "Dropped "+elem_id+" into the "+event.target.getAttribute('id');
droppedIn = true;
// Create our XMLHttpRequest object
var hr = new XMLHttpRequest();
// Create some variables we need to send to our PHP file
var url = "jqueryserver.php";
var vars = "value= "+elem_id;
hr.open("POST", url, true);
// Set content type header information for sending url encoded variables in the request
hr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
// Access the onreadystatechange event for the XMLHttpRequest object
hr.onreadystatechange = function() {
if(hr.readyState == 4 && hr.status == 200) {
var return_data = hr.responseText;
document.getElementById("app_status").innerHTML = return_data;
}
}
// Send the data to PHP now... and wait for response to update the status div
hr.send(vars); // Actually execute the request
document.getElementById("app_status").innerHTML = event.target.getAttribute('id')+"processing...";
}
function drag_end(event) {
if(droppedIn == false){
_('app_status').innerHTML = "You let the "+event.target.getAttribute('id')+" go.";
}
droppedIn = false;
}
</script>
Solution 1:[1]
This question is old but i put there my example of dragging elements both with touch and mouse without any library
/******************************
required js */
function makeDraggable(elmnt) {
let pos1 = 0,
pos2 = 0,
pos3 = 0,
pos4 = 0;
let dragHandle = elmnt.getElementsByClassName("drag-handle")[0];
if (dragHandle !== undefined) {
// if present, the header is where you move the DIV from:
dragHandle.onmousedown = dragMouseDown;
dragHandle.ontouchstart = dragMouseDown; //added touch event
} else {
// otherwise, move the DIV from anywhere inside the DIV:
elmnt.onmousedown = dragMouseDown;
elmnt.ontouchstart = dragMouseDown; //added touch event
}
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
//Get touch or click position
//https://stackoverflow.com/a/41993300/5078983
if (e.type == 'touchstart' || e.type == 'touchmove' || e.type == 'touchend' || e.type == 'touchcancel') {
let evt = (typeof e.originalEvent === 'undefined') ? e : e.originalEvent;
let touch = evt.touches[0] || evt.changedTouches[0];
x = touch.pageX;
y = touch.pageY;
} else if (e.type == 'mousedown' || e.type == 'mouseup' || e.type == 'mousemove' || e.type == 'mouseover' || e.type == 'mouseout' || e.type == 'mouseenter' || e.type == 'mouseleave') {
x = e.clientX;
y = e.clientY;
}
console.log("drag start x: "+x+" y:"+y);
// get the mouse cursor position at startup:
pos3 = x;
pos4 = y;
document.onmouseup = closeDragElement;
document.ontouchend = closeDragElement;
// call a function whenever the cursor moves:
document.onmousemove = elementDrag;
document.ontouchmove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
//Get touch or click position
//https://stackoverflow.com/a/41993300/5078983
if (e.type == 'touchstart' || e.type == 'touchmove' || e.type == 'touchend' || e.type == 'touchcancel') {
let evt = (typeof e.originalEvent === 'undefined') ? e : e.originalEvent;
let touch = evt.touches[0] || evt.changedTouches[0];
x = touch.pageX;
y = touch.pageY;
} else if (e.type == 'mousedown' || e.type == 'mouseup' || e.type == 'mousemove' || e.type == 'mouseover' || e.type == 'mouseout' || e.type == 'mouseenter' || e.type == 'mouseleave') {
x = e.clientX;
y = e.clientY;
}
// calculate the new cursor position:
pos1 = pos3 - x;
pos2 = pos4 - y;
pos3 = x;
pos4 = y;
// set the element's new position:
elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
}
function closeDragElement() {
console.log("drag end x: "+pos3+" y:"+pos4);
// stop moving when mouse button is released:
document.onmouseup = null;
document.ontouchcancel = null; //added touch event
document.ontouchend = null; //added touch event
document.onmousemove = null;
document.ontouchmove = null; //added touch event
}
}
/*******************************
test js */
makeDraggable(document.getElementById("test-draggable"));
makeDraggable(document.getElementById("test-draggable2"));
makeDraggable(document.getElementById("test-full-draggable"));
/******************************
required css */
.draggable {
position: absolute;
z-index: 9;
}
.drag-handle {
cursor: move;
z-index: 10;
}
.full-draggable {
cursor: move;
}
/*******************************
test css */
.draggable {
background-color: #f1f1f1;
border: 1px solid #d3d3d3;
text-align: center;
}
.draggable .drag-handle {
padding: 10px;
background-color: #2196F3;
color: #fff;
}
#test-draggable2 {
left: 200px
}
#test-full-draggable {
left: 500px
}
<div id="test-draggable" class="draggable">
<div class="drag-handle">Drag using me</div>
I'm the <br>content, <br>you can't<br> drag touching<br> there
</div>
<div id="test-draggable2" class="draggable">
<div class="drag-handle">Drag using me</div>
It even works with many draggables<br>
I'm the <br>content, <br>you can't<br> drag touching<br> there
</div>
<div id="test-full-draggable" class="draggable full-draggable">
i don't have <br> a handle so <br> i'm completely <br> draggable
</div>
Solution 2:[2]
I found the problem with Marco's answer and the solution, so as promised I will include the answer here and leave the working code in codesandbox
Basically, the Surface Book 2 (not sure how widespread this is) didn't like the way Marco set up the listeners to the touch events. Something in the javascript engine or at the interface between the engine and the OS.
I just replaced the definition of the event listeners in this way in three places in his code (again whole working code available in the sandbox link above):
// dragHandle.ontouchstart = dragMouseDown; //added touch event
dragHandle.addEventListener("touchstart", dragMouseDown, false);
then:
// document.ontouchend = closeDragElement;
elmnt.addEventListener("touchend", closeDragElement, false);
// call a function whenever the cursor moves:
document.onmousemove = elementDrag;
// document.ontouchmove = elementDrag;
document.addEventListener("touchmove", elementDrag, false);
And finally in function closeDragElement:
// document.ontouchend = null; //added touch event
document.removeEventListener("touchend", closeDragElement, false);
document.removeEventListener("touchmove", elementDrag, false);
// document.ontouchmove = null; //added touch event
Wow! this was all, if this isn't witchcraft, what is it?
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Marco somefox |
| Solution 2 |
