JavaScript Drag/Drop a Div on a Web Page [duplicate] - javascript

This question already has answers here:
HTML5 Drag and Drop anywhere on the screen
(3 answers)
Closed 9 years ago.
I am trying to code up some JavaScript that will allow me to move a div on a web page. That is, I want to make it so that you can click and drag a div from one location on the page to another. My JavaScript doesn't seem to be cooperating. However, I feel like I am making a very simple error. Perhaps another pair of eyes can find my problem(s)?
Any comments are appreciated.
Below is my JS, CSS, and HTML:
JavaScript:
function getStyle(object, styleName) {
if (window.getComputedStyle) {
return document.defaultView.getComputedStyle(object, null).getPropertyValue(styleName);
} else if (object.currentStyle) {
return object.currentStyle[styleName];
}
}
function grabCalculator(e) {
var evt = e || window.event;
calculator = evt.target || evt.srcElement;
var mousex = evt.clientX;
var mousey = evt.clientY;
diffx = parseInt(calculator.style.left) + mousex;
diffy = parseInt(calculator.style.top) + mousey;
addEvent(document, "mousemove", moveCalculator, false);
addEvent(document, "mouseup", dropCalculator, false);
}
function moveCalculator(e) {
var evt = e || window.event;
var mousex = evt.clientX;
var mousey = evt.clientY;
calculator.style.left = mousex + diffx + "px";
calculator.style.top = mousey + diffy + "px";
}
function addEvent(obj, eventType, fnName, cap) {
alert("TEST");
if (obj.attachEvent) {
obj.attachEvent("on" + eventType, fnName);
} else {
obj.addEventListener(eventType, fnName, cap);
}
}
function removeEvent(obj, eventType, fnName, cap) {
if (obj.attachEvent) {
obj.detachEvent("off" + eventType, fnName);
} else {
obj.removeEventListener(eventType, fnName, cap);
}
}
function dropCalculator(e) {
removeEvent(document, "mousemove", moveCalculator, false);
removeEvent(document, "mouseup", dropCalculator, false);
}
function init() {
diffx = null;
diffy = null;
calculator = document.getElementById("calculator");
//store top and left values of calculator
calculator.style.top = getStyle(calculator, "top");
calculator.style.left = getStyle(calculator, "left");
calcButtonState = true;
}
window.onload = init;
CSS:
#calculator
{
position: absolute;
z-index: 1;
left: 37%;
top: 25%;
border: solid;
border-color: red;
background: black;
width: 25%;
height: 45%;
}
This is only the relevant CSS.
HTML:
<!DOCTYPE HTML>
<html>
<head>
<link type="text/css" rel="stylesheet" href="style.css">
<script type="text/javascript" src="javascript.js"></script>
</head>
<body>
<div id="main">
<!--Calculator-->
<div id="calculator">
</div>
<!--End calculator-->
<header>
<div id="title">
Conversion Formulas
</div>
</header>
<nav>
</nav>
<div id="content">
<div id="dryMeasureContent">
</div>
<div id="wetMeasureContent">
</div>
<div id="distanceContent">
</div>
<div id="temperatureContent">
</div>
</div>
<footer>
</footer>
</div>
</body>
</html>
Note that my other HTML tags are in place, however, stackoverflow doesn't seem to handle HTML very well so they do not appear.

first of all, your init() function doesn't add any event listeners - this is the issue
try to add addEvent(calculator, 'mousedown', moveCalculator); after this line
calculator = document.getElementById("calculator");
i hope you understood my idea

Have you looked at the jquery library draggable http://jqueryui.com/draggable/ and droppable http://jqueryui.com/droppable/ ?
I've used these libraries with great success.
Super super easy to implement.

W3Schools has a great tutorial on drag and drop just using HTML5 and javascript.
<!DOCTYPE HTML>
<html>
<head>
<script>
function allowDrop(ev){
ev.preventDefault();
}
function drag(ev){
ev.dataTransfer.setData("Text",ev.target.id);
}
function drop(ev){
ev.preventDefault();
var data=ev.dataTransfer.getData("Text");
ev.target.appendChild(document.getElementById(data));
}
</script>
</head>
<body>
<div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)"></div>
<img id="drag1" src="img_logo.gif" draggable="true" ondragstart="drag(event)" width="336" height="69">
</body>
</html>

Related

How to cancel a drag (on dragenter)

I'm on classic javascript and i want to cancel a drag on enter in a specific div.
in HTML :
<!-- Element i want to drag -->
<div id="draggableElement" draggable="true"></div>
<!-- Element which cancels the drag on enter -->
<div id="specificDiv"></div>
in JS :
document.addEventListener("dragenter", event=> {
if (event.target.id == "specificDiv") {
// Cancel the drag
}
}, false);
I already search on the web but i didn't find a solution, however i found some js libraries but it's too much for the only thing i want to do.
Thanks by advance.
EDIT :
More precisly i want, at least, undisplay the draged image by entering in my specific div to see this one.
So i've already tried to hide the draged image but it doesn't work on dragenter (only in dragstart).
in JS :
let dragged;
document.addEventListener("dragstart", event=> {
dragged = event;
}, false);
document.addEventListener("dragenter", event=> {
if (event.target.id == "specificDiv") {
// Hide the dragged image or cancel the drag
event.dataTransfer.setDragImage(new Image(), 0, 0); // Doesn't work
dragged.dataTransfer.setDragImage(new Image(), 0, 0); // Doesn't work too
}
}, false);
Okay so you want to hide the dragged element when enters over renderCanvas but WITHOUT releasing mouse button am I right?
If so, you have to know that is not possible to modifying drag-ghost-image without releasing mouse button. In that case you can simulate a custom Drag&Drop and hide the dragged element when its position is in range with the other element:
let specificDiv = document.getElementById('specificDiv');
let renderCanvas = document.getElementById('renderCanvas');
//Catches target position
rect = renderCanvas.getBoundingClientRect();
rectX = rect.left;
rectY = rect.top;
//Release dragged element
let released;
document.addEventListener('mouseup', ()=>{
released = true;
})
//Drag element
specificDiv.addEventListener('mousedown', (ev) => {
released = false;
specificDiv.addEventListener('mousemove', (e)=>{
if(!released) {
//Collects actual mouse position while dragging
x = e.clientX
y = e.clientY
//Moves dragged element
specificDiv.style.left = (x-80) + 'px';
specificDiv.style.top = (y-80) + 'px';
//Hides dragged element when is over the other
if(y > rectY) {
specificDiv.style.opacity="0"
}
}
})
})
#specificDiv {
position: relative;
background-color: red;
height: 10em;
width: 10em;
}
#renderCanvas {
background-color: blue;
height: 20em;
width: 20em;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link href="css/styles.css" rel="stylesheet">
</head>
<body>
<!-- Div element you want to drag-->
<div id="specificDiv">DRAGGED ELEMENT</div>
<!-- Div element who cancels the drag on enter -->
<div id="renderCanvas">TARGET ELEMENT</div>
<script src="js/main.js"></script>
</body>
</html>
You'll have to adapt rectX and rectY to your specific divs position.
The following would be a solution to allow dropping on a div and on another div don't allow dropping:
function allowDrop(ev) {
ev.preventDefault();
}
function drag(ev) {
ev.dataTransfer.setData("text", ev.target.id);
}
function drop(ev) {
ev.preventDefault();
var data = ev.dataTransfer.getData("text");
ev.target.appendChild(document.getElementById(data));
}
const target = document.querySelector("#dragtarget");
const notarget = document.querySelector("#nodragtarget");
const dragged = document.querySelector("#dragitem");
target.addEventListener("dragover", allowDrop);
target.addEventListener("drop", drop);
dragged.addEventListener("dragstart", drag)
div[draggable] {
height: 3rem;
width: 3rem;
background: yellow;
}
div#dragtarget {
height: 5rem;
width: 5rem;
border: 1px solid green;
}
div#nodragtarget {
height: 5rem;
width: 5rem;
border: 1px solid red;
}
<div id="dragitem" draggable="true"></div>
<div id="dragtarget"></div>
<div id="nodragtarget"></div>
did my answer worked for you? I am quite curious

Alter an image's position based on a key that is pressed?

The code here should take the element and move it to the left or right. However, the image is still in place.
var posX = 100;
document.getElementById("ship").addEventListener("keydown", moveShip);
function moveShip(event) {
if (event.key == "ArrowLeft") {
posX -= 2;
} else if (event.key == "ArrowRight") {
posX += 2;
}
}
HTML of the code is very basic, nothing much has been added here
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="style.css" />
<title>ship</title>
</head>
<body>
<img id="ship" src="spaceship.png" />
<canvas id="myCanvas"></canvas>
<script src="extensions.js"></script>
<script src="main.js"></script>
</body>
</html>
The CSS of the code is here
canvas{
border: 1px, solid, black;
}
html{
background-color: black;
}
#ship{
width: 100px;
}
You should give the image a relative position and set the left CSS property to move it.
<img id="ship" src="spaceship.png" style="position: relative;"/>
<script>
var posX = 100;
var ship = document.getElementById("ship");
ship.style.left = posX;
ship.addEventListener("keydown", moveShip);
function moveShip(event) {
if (event.key == "ArrowLeft") {
posX -= 2;
} else if (event.key == "ArrowRight") {
posX += 2;
}
ship.style.left = posX;
}
</script>

image dragging in javascript

i am trying to drag image in javascript
i know it is easily done using jQuery, but i want to make it using javascript
here is the code but it is not working
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>dragImage</title>
<meta name="author" content="engy" />
<!-- Date: 2015-02-17 -->
</head>
<body>
<!--<img src="bbe.jpg" style="width:104px;height:128px">-->
<!-- <img id = "img" src="bbe.jpg" style="position:absolute; TOP:posY; LEFT:posX; WIDTH:50px; HEIGHT:50px"> -->
<!--top=y=155px;left=x=70px;-->
<script>
var flagdown = 0;
</script>
<script>
function up() {
flagdown = 0;
}
function down() {
//document.write("jk");
flagdown = 1;
}
function move(e) {
if (flagdown == 1) {
var posX = e.clientX;
var posY = e.clientY;
document.getElementById("img").style.marginLeft = posX;
document.getElementById("img").style.marginTop = posY;
}
}
document.onmousemove = move;
</script>
</body>
</html>
can anyone help me?
i have tried it in many browsers but it still doesn't work
var flagdown = 0;
function up() {
flagdown = 0;
}
function down() {
//document.write("jk");
flagdown = 1;
}
function move(e) {
if (flagdown == 1) {
var posX = e.clientX;
var posY = e.clientY;
document.getElementById("img").style.marginLeft = posX;
document.getElementById("img").style.marginTop = posY;
}
}
document.onmousemove = move;
<img onmouseup="up()" onmousedown="down()" id="img" src="bbe.jpg" draggable="true" width="50" height="50">
<!DOCTYPE HTML>
<html>
<head>
<style>
#div1 {width:350px;height:70px;padding:10px;border:1px solid #aaaaaa;}
</style>
<script>
function allowDrop(ev) {
ev.preventDefault();
}
function drag(ev) {
ev.dataTransfer.setData("text", ev.target.id);
}
function drop(ev) {
ev.preventDefault();
var data = ev.dataTransfer.getData("text");
ev.target.appendChild(document.getElementById(data));
}
</script>
</head>
<body>
<p>Drag image into the rectangle:</p>
<div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)"></div>
<br>
<img id="drag1" src="img_logo.gif" draggable="true" ondragstart="drag(event)" width="336" height="100">
</body>
</html>

Drag and drop html element

I have a div which can be dragged. If it's dragged, I would like to add its text to mouse and after leaving the mouse I want to show some menu like copy.
I have tried this:
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<style>
#div1
{
width:350px;
height:70px;
padding:10px;
border:1px solid #aaaaaa;
}
</style>
<script>
function drag(ev)
{
ev.dataTransfer.setData("Text",ev.target.id);
}
function drop(ev)
{
ev.preventDefault();
//console.log(ev.dataTransfer);
//var data=ev.dataTransfer.getData("Text");
//ev.target.appendChild(document.getElementById(data));
alert(ev.target.id);
}
function allowDrop(ev){
ev.preventDefault();
}
</script>
</head>
<body>
<a draggable="true" ondragstart="drag(event)" id="drag-id" >dragme</a>
<div id="div1" style="border: solid 1px; width:40px; height:40px;" ondrop="return drop(event)" ondragover="allowDrop(event)"></div>
</body>
</html>
SOLUTION using fake drag 'n drop.
The problem here is that it only works inside the body element.
var fakeDrag = {
setup: function(){
fakeDrag.el = document.createElement('span');
fakeDrag.el.style['pointer-events'] = 'none';
fakeDrag.el.style['position'] = 'absolute';
fakeDrag.el.style['display'] = 'none';
fakeDrag.el.textContent = 'dragging';
document.body.appendChild(fakeDrag.el);
},
dragging: false,
drag: function(event){
if(event.target.classList.contains('drag')){
fakeDrag.dragging = true;
fakeDrag.source = event.target;
fakeDrag.el.style['display'] = 'inline';
}
},
dragmove: function(event){
fakeDrag.el.style['top'] = ++event.clientY+'px';
fakeDrag.el.style['left'] = ++event.clientX+'px';
},
drop: function(event){
if(event.target.classList.contains('drop') && fakeDrag.dragging){
event.target.textContent = fakeDrag.source.textContent;
}
fakeDrag.dragging = false;
fakeDrag.el.style['display'] = 'none';
}
};
fakeDrag.setup();
For menu you use it:
<div id="context_menu" style="width:150px;border:1px solid black;background-color:#EEEEEE;visibility:hidden;position:absolute;line-height:30px; padding-left: 10px">
<div id="copy" onclick="CopyFunction(this)" divIDMenu="">copy</div>
<div id="paste"onclick="PasteFunction(this)" divIDCopy="" divIDMenu="">paste</div>
<div id="cut" onclick="cutFunction(this)"divIDMenu="">cut</div>
<div id="delete" onclick="deleteFunction(this)" divIDMenu="">delete</div>
<div id="reload" onclick="reloadFunction(this)" divIDMenu="">reload</div>
</div>

prevent full page scrolling iOS

Under Mobile Safari, is it possible to allow one absolutely positioned div to scroll without allowing the entire page to bob up and down when it the scroll reaches the edges (elastically scrolling)?
Here is a minimal working example of the issue I'm facing:
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes" />
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
#a, #b {
position: absolute;
top: 0;
left: 0;
height: 100%;
padding: 10px;
overflow: auto;
}
#a {
width: 80px;
background: #f00;
}
#b {
background: #00f;
left: 80px;
width: 100%;
}
</style>
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script>
function pdcb(e) {
e.preventDefault();
}
function npcb(e) {
e.stopPropagation();
}
$(document).on('touchstart touchmove', pdcb).
on('touchstart touchmove', '.scrollable', npcb);
</script>
</head>
<body>
<div id="a" class="scrollable">
This<br>
should<br>
be<br>
scrollable<br>
but<br>
not<br>
scroll<br>
the<br>
whole<br>
page<br>
This<br>
should<br>
be<br>
scrollable<br>
but<br>
not<br>
scroll<br>
the<br>
whole<br>
page<br>
This<br>
should<br>
be<br>
scrollable<br>
but<br>
not<br>
scroll<br>
the<br>
whole<br>
page<br>
This<br>
should<br>
be<br>
scrollable<br>
but<br>
not<br>
scroll<br>
the<br>
whole<br>
page<br>
This<br>
should<br>
be<br>
scrollable<br>
but<br>
not<br>
scroll<br>
the<br>
whole<br>
page<br>
</div>
<div id="b">
this should never scroll
</div>
</body>
</html>
Solution:
$(document).on('touchmove', function(e) {
e.preventDefault();
}).ready(function() {
$(".scrollable").on('touchstart', function(e) {
this.allowUp = (this.scrollTop > 0);
this.allowDown = (this.scrollTop < this.scrollHeight - this.clientHeight);
this.prevTop = null;
this.prevBot = null;
this.lastY = e.originalEvent.pageY;
}).on('touchmove', function(e) {
var event = e.originalEvent;
var up = (event.pageY > this.lastY), down = !up;
this.lastY = event.pageY;
if ((up && this.allowUp) || (down && this.allowDown))
event.stopPropagation();
else
event.preventDefault();
});
});
The original answers are fantastic, but have a few flaws that I resolved:
If an element is at the top or the bottom, it won't scroll up and down respectively.
If an element is added dynamically, it won't have the scroll handlers.
There were unused variables (prevTop, prevBot)
My answer addresses those. (Notice that I use .scroll-y, instead of .scrollable)
First, add these CSS rules:
.scroll-y {
overflow-y: auto;
overflow-x: hidden;
-webkit-overflow-scrolling: touch; /* nice webkit native scroll */
}
Add the .scroll-y class to any elements you want to make scroll.
Then, add this JS somewhere:
// Disable scroll for the document, we'll handle it ourselves
$(document).on('touchmove', function(e) {
e.preventDefault();
});
// Check if we should allow scrolling up or down
$(document.body).on("touchstart", ".scroll-y", function (e) {
// If the element is scrollable (content overflows), then...
if (this.scrollHeight !== this.clientHeight) {
// If we're at the top, scroll down one pixel to allow scrolling up
if (this.scrollTop === 0) {
this.scrollTop = 1;
}
// If we're at the bottom, scroll up one pixel to allow scrolling down
if (this.scrollTop === this.scrollHeight - this.clientHeight) {
this.scrollTop = this.scrollHeight - this.clientHeight - 1;
}
}
// Check if we can scroll
this.allowUp = this.scrollTop > 0;
this.allowDown = this.scrollTop < (this.scrollHeight - this.clientHeight);
this.lastY = e.originalEvent.pageY;
});
$(document.body).on('touchmove', ".scroll-y", function(e) {
var event = e.originalEvent;
var up = event.pageY > this.lastY;
var down = !up;
this.lastY = event.pageY;
if ((up && this.allowUp) || (down && this.allowDown)) {
event.stopPropagation();
} else {
event.preventDefault();
}
});
While you're not hitting the edges of your div's content, you need to allow the native touchmove event to work on that element (so it can scroll), but you're going to want to stop the event from bubbling up the DOM so that it doesn't trigger scrolling on the page body.
When you hit the boundary of your element, you need to prevent the native momentum scrolling entirely.
The code I use for this is as follows (apologies to the original author, this is adapted from a tutorial on this topic I found somewhere on the internet in the past... Can't seem to find the URL now though):
where elem is your DOM node
elem.addEventListener('touchstart', function(event){
this.allowUp = (this.scrollTop > 0);
this.allowDown = (this.scrollTop < this.scrollHeight - this.clientHeight);
this.prevTop = null; this.prevBot = null;
this.lastY = event.pageY;
});
elem.addEventListener('touchmove', function(event){
var up = (event.pageY > this.lastY), down = !up;
this.lastY = event.pageY;
if ((up && this.allowUp) || (down && this.allowDown)) event.stopPropagation();
else event.preventDefault();
});
I usually define an array of elements and loop through them - applying this code to each one iteratively.
Best of luck, hope this helps.
The note provided by Aaron Grey helped!
See link:
http://blog.christoffer.me/six-things-i-learnt-about-ios-safaris-rubber-band-scrolling/
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="minimum-scale=1.0, width=device-width, maximum-scale=1.0, user-scalable=no, initial-scale=1">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<style>
.page{
font-size: 24px;
overflow: scroll;
}
.menu{
position: fixed;
top: 0;
bottom: 0;
left: 0;
width: 80%;
background: gray;
z-index: 1;
font-size: 10px;
overflow: scroll;
/* uncomment to get smooth momentum scroll, but also a rubber band effect */
/*-webkit-overflow-scrolling: touch;*/
}
.menu-item{
padding: 10px;
background: darkgray;
font-size: 24px;
}
</style>
</head>
<body>
<div class="menu scrollable">
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
</div>
<div class="page disable-scrolling">
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's
standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make
a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting,
remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing
Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions
of Lorem Ipsum.
</div>
<script>
document.ontouchmove = function ( event ) {
var isTouchMoveAllowed = true, target = event.target;
while ( target !== null ) {
if ( target.classList && target.classList.contains( 'disable-scrolling' ) ) {
isTouchMoveAllowed = false;
break;
}
target = target.parentNode;
}
if ( !isTouchMoveAllowed ) {
event.preventDefault();
}
};
function removeIOSRubberEffect( element ) {
element.addEventListener( "touchstart", function () {
var top = element.scrollTop, totalScroll = element.scrollHeight, currentScroll = top + element.offsetHeight;
if ( top === 0 ) {
element.scrollTop = 1;
} else if ( currentScroll === totalScroll ) {
element.scrollTop = top - 1;
}
} );
}
removeIOSRubberEffect( document.querySelector( ".scrollable" ) );
</script>
</body>
</html>

Categories

Resources