How to cancel a drag (on dragenter) - javascript

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

Related

how to drop an element into a div and retrieve the coordinates relative to the div element?

i have a div element with id="drag", if a div element with id='drag' is dragged and dropped onto a div element with id="drop", it will display the coordinates value relative to the div element with id="drop" . I've managed to retrieve the coordinates relative to the div id="drop", but when the page is scrolled, the Y value also changes. how to solve this so that when the page is scrolled the Y value remains relative to the div with id='drop'? here is my code below
`
`<!DOCTYPE html>
<html lang="en">
<head>
<title>jQuery UI Droppable</title>
</head>
<body style="height: 200vh">
<div
id="drop"
style="
width: 600px;
height: 600px;
background-color: brown;
margin: 0 auto;
"
></div>
<div
id="drag"
style="background-color: blue; width: 100px; height: 100px"
></div>
</body>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script>
$(function () {
$("#drag").draggable();
$("#drop").droppable({
accept: "#drag",
drop: function (e) {
var rect = e.target.getBoundingClientRect();
const coordinates = [
Math.round(e.pageX - rect.left),
Math.round(e.pageY - rect.top),
];
console.log(coordinates[0]);
console.log(coordinates[1]);
},
});
});
</script>
</html>`
`
At least from here, it never changes.
you can check it like that:
$(function () {
var coordinates;
$("#drag").draggable();
$("#drop").droppable({
accept: "#drag",
drop: function (e) {
var rect = e.target.getBoundingClientRect();
coordinates = [
Math.round(e.pageX - rect.left),
Math.round(e.pageY - rect.top),
];
setInterval(() => {
console.log(coordinates[0]);
console.log(coordinates[1]);
}, 500);
},
});
});

Drag doesn't work after mouseup in scope of drop container (Chrome, Edge)

When an element is dragged around and dropped somewhere in the page, the next element should have the same dragging behaviour as the first element.
I decided to implement the dragging with mouseevents instead of the drag and drop API. The dragged element should be rotatable during the dragging process with press on a button and this is not possible with the drag and drop API.
The problem happens if an element is dragged to the socpe of the drop container and the mouseup event happens in this scope. When the next element is dragged it isn't dragged as expected. There appears a grabbing cursor instead of a mouse cursor and the element doesn't follow the cursor. (In Chrome and Edge, in Firefox everything's fine)
Everything works as expected if an element is dragged over scope of the drop container and the mouseup event gets fired outside the scope.
Here is a link to a gif where you can see the problem.
The problem happens in Chrome and Edge, but not in Firefox. There is a mouseevent feature not supported in Chrome/Edge but in Firefox: "Support for mouseEventInit optional region field". Enabling "Experimental Web Platform Features" in Chrome still didn't solve the problem.
Checking the events in Chrome developer tools and Firefox Developer Tools one difference is that the offsetX and offsetY is in Firefox "0" but in Chrome a value is assigned. Don't know if this points to the potential issue.
How can the right dragging behaviour can be also implemented for Chrome and Edge?
const dragContainer = document.querySelector('#drag-container')
const dropContainer = document.querySelector('#drop-container')
const element1 = document.querySelector('#element-1')
const element2 = document.querySelector('#element-2')
makeElementDraggable(element1)
makeElementDraggable(element2)
function makeElementDraggable(element) {
element.addEventListener('mousedown', startDrag)
// Regards to: https://javascript.info/mouse-drag-and-drop
function startDrag(ev) {
element.style.position = 'absolute'
element.style.zIndex = 1000
document.body.append(element)
moveAt(ev.pageX, ev.pageY)
document.addEventListener('mousemove', onMouseMove)
document.addEventListener('mouseup', reset)
}
function onMouseMove(ev) {
moveAt(ev.pageX, ev.pageY)
}
function moveAt(pageX, pageY) {
element.style.left = pageX + 10 + 'px'
element.style.top = pageY + 'px'
}
function reset() {
document.removeEventListener('mousemove', onMouseMove)
element.removeEventListener('mousedown', startDrag)
}
}
#drag-container {
width: 250px;
height: 500px;
border: 1px solid black;
}
#element-1 {
background-color: aqua;
width: 250px;
height: 50px;
}
#element-2 {
background-color: blueviolet;
width: 200px;
height: 50px;
}
#drop-container {
height: 500px;
width: 500px;
border: 1px solid black;
}
<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>
</head>
<body>
<div id="drag-container">
<div id="element-1"></div>
<div id="element-2"></div>
</div>
<div id="drop-container"></div>
<script src="script.js"></script>
</body>
</html>

js (vanilla) - drop image on element 1 and handle the drop in default file uploader

I am trying to drop an image on image box - but using the drop event I already created for typical file uploader (prevent code duplication).
I have the following HTML:
<div id="Btn" class="btn2">
<input id="FileUpl" type="file" style="display:none;">
<img class="fill">
</div>
And the following JS:
let Btn=document.getElementById("Btn");
let FileUpl=document.getElementById("FileUpl");
Btn.addEventListener("drop",Go);
function Go(e) { FileUpl.ondrop(e); } // SEE NOTES BELOW
NOTES
The "FileUpl" originally is generated by a function, which attaches to it special handling of dropped file.
Hence: I prefer to not duplicate my code there to run in Btn, but to trigger the ondrop event there.
However: Seems nothing is being calling...
The drop event passes to FileUpl.ondrop, but somehow is not being processing.
While if I would drop directly on FileUpl control (if it would be stand alone one), then it would process the file on drop without any problem.
My question: What is the right way to trigger the handler I have in the control FileUpl...?
I am using Vanilla JS (no library)
You need to prevent the default action for dragenter, dragexit, and dragover events, After that you can handle the dropbox with drop event like this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Test</title>
<style>
.drop-section {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.drop-section > * {
border: 1px solid #eee;
min-width: 450px;
min-height: 450px;
padding: 30px;
line-height: 450px;
text-align: center;
}
</style>
</head>
<body>
<section class="drop-section">
<div class="drop-section__area">
Drop your image here!
</div>
</section>
<script>
let dropArea = document.querySelector(".drop-section__area");
// preventDefault and stopPropagation with some style
function dragHandler(e) {
e.preventDefault();
e.stopPropagation();
dropArea.style.background = "#f9f9f9";
dropArea.style.opacity = ".5";
};
dropArea.addEventListener("dragenter", dragHandler);
dropArea.addEventListener("dragexit", dragHandler);
dropArea.addEventListener("dragover", dragHandler);
// handle the drop event
function drop(e) {
e.stopPropagation();
e.preventDefault();
dropArea.style.background = "unset";
dropArea.style.opacity = "1";
var [file] = e.dataTransfer.files;
console.log(file.name);
};
dropArea.addEventListener("drop", drop);
</script>
</body>
</html>
Read more about DataTransfer from here

File won't open in Chrome or Firefox, file name in URL changes to "0"

I tried searching for "file name changes to 0 in browser" both in Google and here, but got nowhere. This is a simple file which suddenly stopped opening. I can't even get at the inspector to troubleshoot it. Undo/redo history is lost, so that will not help. I'm guessing it's a simple mistake, but I have NEVER seen this before.
<!doctype html>
<html lang="en">
<head>
<title>JS Animated Navigation Test</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script>
<!--
var location = 0;
var bar = document.getElementById("bar1");
function myMove()
{
// if (id != 0) clearInterval(id);
location = -144;
// if (location != -144) return; // don't execute onmouseover while previous onmouseover is still running.
id = setInterval(move, 1);
}
function move()
{
location++;
bar.style.left = location + 'px';
if (location == 300)
{
clearInterval(id);
id = setInterval(moveback, 1);
}
}
function moveback()
{
location--;
bar.style.left = location + 'px';
if (location == -144)
{
clearInterval(id);
// id = setInterval(move, 1);
}
}
-->
</script>
<style>
#container
{
width: 600px;
height: 100px;
position: relative;
background: white;
}
#bar1
{
width: 150px;
height: 30px;
position: absolute;
left: -144px;
background-color: white;
}
</style>
</head>
<body>
<p>
<button onclick="myMove()">Click Me</button>
</p>
<div id ="container">
<div id ="animate"><img src="imageGalleryBar.png" alt="Image Gallery" width="150" height="30" id="bar1" onmouseover="myMove()" /></div>
</div>
</body>
</html>
Thank you
You can't use the variable name location as it is a reserved word; what you're actually doing is setting the window.location variable to 0.
Rename it, or put it in a namespace or object.

How can I update "event.clientX" every sec?

I need to console log x coordinate every 1 sec when pointer is on picture but I have no idea how to update "event" from the js code.
function onPic(event) {
let xOnPic = event.clientX;
console.log(xOnPic);
setTimeout(onPic, 1000);
}
.testDiv {
width: 700px;
height: 350px;
background-image: url("./Pic/pic1.jpeg");
background-repeat: no-repeat;
background-size: 700px 350px;
}
<div onmouseover="onPic(event)" src="./Pic/pic1.jpeg" class="testDiv">
</div>
You need to throw the event more often. Use onmousemove for that. If you want to restrict the amount of outputs you can do that with a variable.
var wait = false
function onPic(event) {
if (!wait) {
wait = true;
let xOnPic = event.clientX;
console.log(xOnPic);
setTimeout(() => wait = false, 1000);
}
}
.testDiv {
width: 700px;
height: 350px;
background-image: url("./Pic/pic1.jpeg");
background-repeat: no-repeat;
background-size: 700px 350px;
}
<!DOCTYPE html>
<html>
<head>
<title>I have no title</title>
<meta charset="UTF-8">
<link rel="stylesheet" href="test.css">
</head>
<body>
<div onmousemove="onPic(event)" src="./Pic/pic1.jpeg" class="testDiv">
</div>
<script src="test.js"></script>
</body>
</html>
I should note that this will only trigger if the mouse actually moved in between, but that is what you usually want.
If you always want to update simply set an variable and output that every second.
let interval = null;
let xPos = 0;
function onEnter() {
interval = setInterval(() => {
console.log(xPos);
}, 1000);
}
function onMove(event) {
xPos = event.clientX;
}
function onLeave() {
clearInterval(interval);
}
.testDiv {
width: 700px;
height: 350px;
background-image: url("./Pic/pic1.jpeg");
background-repeat: no-repeat;
background-size: 700px 350px;
}
<!DOCTYPE html>
<html>
<head>
<title>I have no title</title>
<meta charset="UTF-8">
<link rel="stylesheet" href="test.css">
</head>
<body>
<div onmouseenter="onEnter(event)" onmousemove="onMove(event)" onmouseleave="onLeave(event)" src="./Pic/pic1.jpeg" class="testDiv">
</div>
<script src="test.js"></script>
</body>
</html>
here is a working fiddle. Just use mouseenter mouseleave and mousemove and set Intervall.
JS fiddle
HTML
<svg id="svg" class="pic">
</svg>
JS
let mouseInPic = false;
let x;
$("#svg").on("mouseenter", () => {
mouseInPic = true
})
$("#svg").on("mouseleave", () => {
mouseInPic = false
})
$("#svg").on("mousemove", (e) => {
x = e.clientX
})
window.setInterval(function(){
if(mouseInPic == true){
console.log(x)
}
}, 1000);
Here you have a native JS implementation, with 1 second throttling of the updates, so it will console the position every second but not more often than every second. Since it is not possible to get the mouse position without a mouse event when mouse is over the element but not moving, you will need to remember the position of the mouse and store it into global variable, if mouse is moved on mousemove, just update the new position xOnPic.
Use mouseover and mousemove to detect if mouse is over the selected element and mouseout to detect when mouse is out of the element, so that you can stop printing to console.
var xOnPic = 0
var mouseOverPic = false;
var tryingToUpdate = false;
function tryToUpdate(){
if (!tryingToUpdate){
tryingToUpdate = true
console.log(xOnPic);
setTimeout(onPic, 1000);
}
}
function onPic(){
if (mouseOverPic){
console.log(xOnPic);
setTimeout(onPic, 1000);
}else{
tryingToUpdate = false;
}
}
document.getElementById('Pic').addEventListener('mousemove', function(e){
xOnPic = e.clientX;
mouseOverPic = true;
tryToUpdate();
});
document.getElementById('Pic').addEventListener('mouseover', function(e){
xOnPic = e.clientX;
mouseOverPic = true;
tryToUpdate();
});
document.getElementById('Pic').addEventListener('mouseout', function(e){
xOnPic = '';
mouseOverPic = false;
});
.testDiv{
width: 700px;
height: 350px;
background-image: url("./Pic/pic1.jpeg");
background-repeat: no-repeat;
background-size: 700px 350px;
}
<!DOCTYPE html>
<html>
<head>
<title>I have no title</title>
<meta charset = "UTF-8">
<link rel = "stylesheet" href = "test.css">
</head>
<body>
<div id='Pic' src="./Pic/pic1.jpeg" class = "testDiv">
</div>
<script src = "test.js"></script>
</body>
</html>
Use
setInterval(onPic,1000);

Categories

Resources