Get away with built-in dragging html elements - html

I have a problem with html-objects that moving when I´m dragging them, you know the transparent "ghost" -copy of the element that appears when you holding down the mouse and drag it. My problem is that it interrupt my mouse event. I have a image that should be able to move inside a div when you dragging it with the mouse. I have to events for that, first one for mousedown that trigger mousemove-event, mousemove handles the movement of the image. mousedown is no problem but when I´m moving the mouse with the button down the transparent "ghost" - copy of the elements appear and interrupt my mousemove-event. Is that any one how knows how to get around or fix this thing?

Could you provide a sample?
From what it sounds like, the first thing to check is that the events are actually being hit. Writing messages out to console whenever each event fires should help prove or disprove that the events are occurring as-expected.

Then you start your mousemove event, set a timeout for the appended class 'hide' in 0 ms. Its work.
const dragAndDrop = () => {
const card = document.querySelector('.dragDrop');
const cells = document.querySelectorAll('.block');
const dragStart = function () {
// i added timeout for appended class
setTimeout(() => {
this.classList.add('hide');
}, 0);
};
const dragEnd = function () {
// i added timeout for appended class
setTimeout(() => {
this.classList.remove('hide');
}, 0);
};
const dragOver = function (event) {
event.preventDefault();
}
const dragEnter = function (event) {
event.preventDefault()
this.classList.add('hovered');
}
const dragLeave = function () {
this.classList.remove('hovered');
}
const dragDrop = function () {
this.append(card);
this.classList.remove('hovered')
}
cells.forEach((cell) => {
cell.addEventListener('dragover', dragOver);
cell.addEventListener('dragenter', dragEnter);
cell.addEventListener('dragleave', dragLeave);
cell.addEventListener('drop', dragDrop);
})
card.addEventListener('dragstart', dragStart);
card.addEventListener('dragend', dragEnd);
}
dragAndDrop()
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
body{
width: 100%;
height: 100vh;
display: flex;
justify-content: space-around;
padding-top: 20px;
}
.block{
width: 100px;
height: 100px;
background-color: rgb(99, 99, 99);
display: flex;
justify-content: center;
align-items: center;
}
.card{
width: 80px;
height: 60px;
background-color: black;
cursor: grab;
}
.hide {
display: none;
}
.hovered {
background-color: rgb(254, 164, 164);
}
<div class="block">
<div draggable="true" class="drag dragDrop">
<div class="card"></div>
<div class="text">Hello, world</div>
</div>
</div>
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>

I wrote this 12 years ago but if I remember right the solution was something like,
imageElement.addEventListener('dragover', function(e) {
e.preventDefault()
});
This should prevent the user from clicking and dragging on the image which means the browser won't add any visual effects.

Related

Why does the condition in the function not work?

Why does the condition in the function not work?
Please tell me why the .not() condition does not work.
$(".one").not(".two").on("click", function() {
console.log("click one");
})
.one {
width: 500px;
height: 300px;
background: grey;
position: relative;
}
.two {
background: red;
position: absolute;
top: 20px;
right: 0px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="one">
<input type="file" class="two">
</div>
That's because of event bubbling.
When you click on .two, as it is a child of .one, the click event happens also on .one
To prevent this, you can use event.stopPropagation() but it might not be the right choice as it - indeed - stops the event propagation to every other element, and this could not be desirable if there are other events you listen to in your code and introduce bugs. Stopping propagation of events is something that should be used carefully:
Dangers of stopping Event propagation
Pros/Cons of using e.stopPropagation()
Another - and in my opinion preferred - option is to use the event.currentTarget and event.target. The first is the element to which the event is attached (.one in your case). The second is the actual HTML element that has been clicked.
So, you can check if the event.target is two or one and code different behavior for each alternative.
$(".one").on("click", function(event) {
console.log("event.target is: ", event.target);
console.log("event.currentTarget is: ", event.currentTarget);
if ($(event.target).hasClass('two')) {
console.log("Mmh... you clicked two, please click one");
} else if ($(event.target).hasClass('one')) {
console.log("YEAH! You clicked one this time");
}
})
.one {
width: 500px;
height: 300px;
background: grey;
position: relative;
}
.two {
background: red;
position: absolute;
top: 20px;
right: 0px;
}
.as-console-wrapper { max-height: 4.5em !important; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="one">
<input type="file" class="two">
</div>
$(".two").on("click", function(e) {
e.stopPropagation();
})

OnMouseOver change the content of a (pop-up) window

I'm a visual artist with not that many coding skills. I know some HTML and some CSS but that's it. I like to create a webpage that does the following:
On the left, there is an image with lines. When hovering over a line the window on the right shows an image, movie, or plays a sound. Hovering over the next line triggers another image, movie, or sound.
Anyone can point me in the correct direction? I made a gif to show how it should work...
Simple solution:
Select HTML elements which we want to hover over (left, middle, right), and HTML elements which contain our images/videos/audio etc. (img1, sound, img2)
For every element you want to hover over, you need to add event listener (addEventListener), so you can manipulate your HTML/CSS code with JavaScript.
2.2 Inside each event listener you add or remove class: none, which has CSS value of display: none (this means element won't be shown), depending on what your goal is.
To make images disappear when we don't hover our cursor over the element, we need to again add event listener to elements which already have on mouseover event listener. In this case we use mouseover or blur. When cursor isn't on the element, JavaScript will automatically add none class to it.
const left = document.querySelector('.left-line');
const middle = document.querySelector('.middle-line');
const right = document.querySelector('.right-line');
const img1 = document.querySelector('.image-1');
const sound = document.querySelector('.sound');
const img2 = document.querySelector('.image-2');
left.addEventListener('mouseover', () => {
img1.classList.remove('none');
img2.classList.add('none');
sound.classList.add('none');
});
middle.addEventListener('mouseover', () => {
img1.classList.add('none');
img2.classList.remove('none');
sound.classList.add('none');
});
right.addEventListener('mouseover', () => {
img1.classList.add('none');
img2.classList.add('none');
sound.classList.remove('none');
});
left.addEventListener('mouseout',() => addNoneClass());
middle.addEventListener('mouseout', () => addNoneClass());
right.addEventListener('mouseout', () => addNoneClass());
function addNoneClass() {
img1.classList.add('none');
img2.classList.add('none');
sound.classList.add('none');
}
* {
padding: 0;
margin: 0;
width: 100vw;
height: 100vh;
}
main {
display: flex;
width: 100%;
height: 100%;
}
section.left {
width: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.line-container {
width: 150px;
height: 150px;
display: flex;
align-items: center;
border: 2px solid black;
}
.left-line, .middle-line, .right-line {
width: 50px;
height: 90%;
margin: 0 10px;
}
.left-line { background-color: green; }
.middle-line { background-color: red; }
.right-line { background-color: blue; }
section.right {
width: 50%;
display:flex;
align-items: center;
justify-content: center;
}
.box {
width: 200px;
height: 200px;
border: 2px solid black;
}
img {
width: 200px;
height: 200px;
}
.none {
display: none;
}
<main>
<section class="left">
<div class="line-container">
<div class="left-line">
</div>
<div class="middle-line">
</div>
<div class="right-line">
</div>
</div>
</section>
<section class="right">
<div class="box">
<div class="image-1 none">
<img src="https://play-lh.googleusercontent.com/aFWiT2lTa9CYBpyPjfgfNHd0r5puwKRGj2rHpdPTNrz2N9LXgN_MbLjePd1OTc0E8Rl1" alt="image-1">
</div>
<div class="sound none">
<img src="https://sm.pcmag.com/pcmag_uk/review/g/google-pho/google-photos_z68u.jpg" alt="sound">
</div>
<div class="image-2 none">
<img src="https://cdn.vox-cdn.com/thumbor/I2PsqRLIaCB1iYUuSptrrR5M8oQ=/0x0:2040x1360/1200x800/filters:focal(857x517:1183x843)/cdn.vox-cdn.com/uploads/chorus_image/image/68829483/acastro_210104_1777_google_0001.0.jpg" alt="image-2">
</div>
</div>
</section>
</main>
You can do this by the following code example.
HTML:
<div class="lines">
<span id='line-1'>|</span>
<span id='line-2'>|</span>
<span id='line-3'>|</span>
</div>
<div id='output'></div>
JS
const line1 = document.getElementById('line-1')
const line2 = document.getElementById('line-2')
const line3 = document.getElementById('line-3')
const output = document.getElementById('output')
line1.addEventListener('mouseover', () => {
output.innerHTML = 'Content One'
})
line2.addEventListener('mouseover', () => {
output.innerHTML = 'Content Two'
})
line3.addEventListener('mouseover', () => {
output.innerHTML = 'Content Three'
})

Addding elements to centered flexbox from left to right

I have a flex box to center 3 divs in the screen. all the three are wrapped around a flex container that has justify-content: center which centers them in the screen. However, since I am using animation and each div is being added one after another, the first div gets added at the center instead of the beginning, the second gets added such that both of the first and second are centered, and when the third is added, all of them are aligned such that the second div is exactly in the middle of the screen. I want to change that such that each div gets added in-place from left to right while all are centered in the screen.
React code:
function foo() {
const [items, set] = React.useState([]);
const transitions = useTransition(items, (item) => item.key, {
from: { transform: "translate3d(0,-40px,0)" },
enter: { transform: "translate3d(0,0px,0)" },
leave: { transform: "translate3d(0,-40px,0)" },
});
React.useEffect(() => {
for (let i = 0; i < rows.length; i++) {
setTimeout(() => {
set((items) => {
const newItems = [...items];
newItems.push({ key: i, code: rows[i] });
return newItems;
});
}, 1000 * i);
}
}, []);
return (
<center>
<div class="flex-container">
{transitions.map(({ item, props, key }) => {
return (
<animated.div key={key} style={props} class="flex-item">
{item.code}
</animated.div>
);
})}
</div>
</center>
);
}
Styling:
.flex-container {
height: 50vh;
display: flex;
justify-content: center;
img{
width: 20%;
text-align: center;
}
}
.flex-item {
flex-basis: 14%;
align-self: center;
margin: 12px;
h4{
font-family: Lato;
font-weight:700;
color: white;
}
p{
color: white;
font-family: Lato;
}
}
Changing center to flex-start shifts everything to the beginning:
Adding fixed width doesn't work as well:
To solve your problem, simply align the cards the way you want them to look after they move, then apply the following CSS:
.card {
position: relative;
top: -100px;
}
If -100px is not enough, try -200px. The goal is that the cards will be off-screen at the top. Upon whatever action you desire, whether it be clicking a button like in my snippet below, or perhaps on page load, change the "top" property to 0, and it will place the card where it belongs in the normal flow of the page.
I additionally use the setTimeout function to delay each subsequent card, and the transition property to animate the movement smoothly since it seems like that is your desired goal.
const left = document.getElementById("left");
const center = document.getElementById("center");
const right = document.getElementById("right");
function foo() {
left.style.top = "0";
setTimeout(function() {
center.style.top = "0";
setTimeout(function() {
right.style.top = "0";
}, 500)
}, 500)
}
#container {
display: flex;
justify-content: center;
}
#container>* {
width: 100px;
height: 50px;
background: red;
margin: 0 0.5em;
position: relative;
top: -100px;
transition: top 1s ease-in-out;
}
button {
margin: auto;
}
<div id="container">
<div id="left"></div>
<div id="center"></div>
<div id="right"></div>
</div>
<button onclick="foo()" id="click-me">Click me!</button>

how to disable dragend animation in html5

I created a draggable element by setting its draggable attribute. When I drop the element, there is an animation of the element snapping back to its origin position:
How can the snap-back animation be disabled? I tried calling preventDefault() on the dragend event, but it had no effect on the animation.
The following snippet shows the basics:
document.getElementById('test').addEventListener(
'dragend', evt => {
evt.preventDefault();
}
);
#container {
border: 1px solid black;
min-width: 300px;
min-height: 200px;
position: relative;
}
#test {
width: 50px;
height: 50px;
background-color: red;
position: absolute;
top: 25px;
left: 40px;
}
<div id="container">
<div id="test" draggable='true'></div>
</div>
Not every browser will show the dragged #test jumping back to the original position.
In order to prevent the animation, you need the drop event to fire. For the drop event to fire, you need to call preventDefault() in the handler for dragover.
document.addEventListener('dragover', function(e) { e.preventDefault() })
Example in MDN docs shows the same thing: https://developer.mozilla.org/en-US/docs/Web/Events/drop#Example
An old blog post describing the quirks of HTML5 Drag and Drop API: https://www.quirksmode.org/blog/archives/2009/09/the_html5_drag.html
As was said earlier, you need to explicitly describe onDragOver handler on the parent's container (where you will drop your draggable element) and put .preventDefault() on event to prevent this animation.
Here is a simple React code example for better understanding of this mechanic (you can position the box inside the container by dragging it):
App.jsx
import './App.css'
const App = () => {
function handleDragOver(e) {
e.preventDefault()
}
function handleDrop(e) {
let box = document.getElementById('box')
if (box) {
box.style.top = e.clientY + 'px'
box.style.left = e.clientX + 'px'
}
}
return (
<div className="container" onDragOver={handleDragOver} onDrop={handleDrop}>
<div id="box" draggable></div>
</div>
)
}
export default App
App.css
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
width: 100vw;
height: 100vh;
position: relative;
}
#box {
width: 100px;
height: 100px;
background-color: lightgreen;
position: absolute;
}

How to prevent dragenter event fires on the draggable element itself?

I have a list of element. They are all have draggable="true" attribute and can fire ondragenter and ondragover event. In other words, they are all draggable and droppable.
The problem is, when I drag an element, its ondragenter event fires immediately. This is not what I expected.
How can I prevent the these events which I am dragging an element?
var div = document.querySelectorAll('.div');
var i = 0;
for(i = 0; i < div.length; i++) {
(function(j) {
div[j].addEventListener('dragstart', handlDragStart);
div[j].addEventListener('dragenter', handleDragEnter);
div[j].addEventListener('dragover', handleDragOver);
})(i)
}
function handlDragStart(ev) {
ev.dataTransfer.effectAllowed = 'move';
ev.dataTransfer.dropEffect = 'move';
}
function handleDragEnter (ev) {
ev.preventDefault();
ev.target.classList.add('enter');
}
function handleDragOver (ev) {
ev.preventDefault();
}
.div {
width:100px;
height:100px;
border: 1px solid #333;
background-color: #ddd;
display: inline-block;
}
.enter {
border: 3px dotted red;
}
<div>
<div class="div" draggable="true">1</div>
<div class="div" draggable="true">2</div>
<div class="div" draggable="true">3</div>
<div class="div" draggable="true">4</div>
<div class="div" draggable="true">5</div>
</div>
I made this example.I expect that when I drag a rec into another rec, the latter get a red border. You can see when I start drag, the first rec get the red border immediately which means the dragenter() fires. How can I prevent it?