Why is my mousedown event triggered on a mouseup event? - javascript

I've been working on the etch-a-sketch project of the Odin project, and I came across some weird behavior when implementing the mousedown and mouseup event listeners.
I've created a 50x50 grid of divs in a container div. The container div listens on mousedown events, upon which it calls the startDrawing function, filling the boxes that the user hovers over. It also listens on mousedown events, so that when the mouse is released, the stopDrawing function is called and the filling of boxes stops.
All of this works pretty much fine, but sometimes when I start drawing a line with the mouse left button held down, the box div becomes "grabbed". After this, while dragging the mouse with the left button still down, the boxes are not filled when hovering over them. Then when I release the mouse it starts drawing. It's as if the behavior is toggled after the accidental "grabbing", but on the next mousedown it starts acting normally again.
This is probably harder to explain than to see it for yourself, so below is my code as well as a link to a corresponding codepen.
I've tried googling to find out how I can remove this "grabbing" behavior, but I haven't really found anything, probably because I don't even know what keywords to search for.
Can somebody explain what's happening and provide some info on how I can fix this?
Etch-a-Sketch Codepen
const GRID_SIZE = 50;
for(let i = 0; i < GRID_SIZE * GRID_SIZE; i++){
const container = document.getElementById('container');
let div = document.createElement('div');
div.classList.add('box');
container.appendChild(div);
}
function fillBox(e){
this.classList.add('filled');
}
function clearGrid(){
const boxes = document.querySelectorAll('.box');
boxes.forEach(box => box.classList.remove('filled'));
}
function startDrawing(){
// console.log("start drawing");
const boxes = document.querySelectorAll('.box');
boxes.forEach(box => box.addEventListener('mouseover', fillBox));
}
function stopDrawing(){
// console.log("stop drawing");
const boxes = document.querySelectorAll('.box');
boxes.forEach(box => box.removeEventListener('mouseover', fillBox));
}
const container = document.querySelector('#container');
container.addEventListener('mousedown', startDrawing);
container.addEventListener('mouseup', stopDrawing);
const button = document.querySelector('#clear-grid-btn');
button.onclick = clearGrid;
#container{
width: 500px;
display: grid;
grid-template-columns: repeat(50, 10px);
grid-template-rows: repeat(50, 10px);
border: solid;
border-color: black;
margin:auto;
}
.box{
width: 10px;
height: 10px;
}
.box:hover{
background-color: blue;
}
.filled{
background-color: blue;
}
#clear-grid-btn{
display:block;
margin:auto;
margin-top: 10px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="etch-a-sketch.css">
</head>
<body>
<div id="container"></div>
<button id="clear-grid-btn">Clear grid</button>
</body>
<script src="etch-a-sketch.js"></script>
</html>

What happens here is that the default behavior of a mousedown + mousemove is to initiate a grab.
Certainly, at some point, the browser will select some content in the page and start grabbing it.
The solution to avoid this is to tell the browser that your code does handle the event and should thus not perform its usual behavior. You can do so by calling the Event::preventDefault() method:
const GRID_SIZE = 50;
for(let i = 0; i < GRID_SIZE * GRID_SIZE; i++){
const container = document.getElementById('container');
let div = document.createElement('div');
div.classList.add('box');
container.appendChild(div);
}
function fillBox(evt){
evt.preventDefault(); // tell the browser we handle that event
this.classList.add('filled');
}
function clearGrid(){
const boxes = document.querySelectorAll('.box');
boxes.forEach(box => box.classList.remove('filled'));
}
function startDrawing(evt){
evt.preventDefault(); // tell the browser we handle that event
// console.log("start drawing");
const boxes = document.querySelectorAll('.box');
boxes.forEach(box => box.addEventListener('mouseover', fillBox));
}
function stopDrawing(evt){
evt.preventDefault(); // tell the browser we handle that event
// console.log("stop drawing");
const boxes = document.querySelectorAll('.box');
boxes.forEach(box => box.removeEventListener('mouseover', fillBox));
}
const container = document.querySelector('#container');
container.addEventListener('mousedown', startDrawing);
container.addEventListener('mouseup', stopDrawing);
const button = document.querySelector('#clear-grid-btn');
button.onclick = clearGrid;
#container{
width: 500px;
display: grid;
grid-template-columns: repeat(50, 10px);
grid-template-rows: repeat(50, 10px);
border: solid;
border-color: black;
margin:auto;
}
.box{
width: 10px;
height: 10px;
}
.box:hover{
background-color: blue;
}
.filled{
background-color: blue;
}
#clear-grid-btn{
display:block;
margin:auto;
margin-top: 10px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="etch-a-sketch.css">
</head>
<body>
<div id="container"></div>
<button id="clear-grid-btn">Clear grid</button>
</body>
<script src="etch-a-sketch.js"></script>
</html>

Related

Adding touchstart event listener causes delay with click event listener in Chrome on iOS

I noticed that adding a touchstart event listener to buttons seems to cause a delay with the click event listener when running in Chrome on my iPhone X test device (I tested with Chrome v108.0.5359.52 and v110.0.5481.83). I haven't been able to reproduce the issue in Firefox or Safari on the same device, or in any browser on my Android device. When running the example HTML below in Chrome on an iOS device, try cycling through pressing each button in the top row, and you should get an acceptable level of responsiveness (the result div's content should update to match the pressed button reliably). However, the bottom row of buttons responds very poorly to button presses (the result div's content does not always update to match the pressed button). If you cycle through the bottom row of buttons slowly then it will work better, but why is there a difference in performance between the top row of buttons and the bottom row of buttons, and only in Chrome on iOS?
<!DOCTYPE html>
<html lang="en">
<head>
<title>Buttons</title>
<meta charset="utf-8" />
<meta name="viewport" content="user-scalable=0, initial-scale=1, minimum-scale=1, maximum-scale=1, width=device-width, minimal-ui=1">
<style>
.buttonHolder {
margin-top: 50px;
}
.result {
text-align: center;
margin: 25px 0;
font-size: 36px;
}
.button {
display: inline-block;
background-color: #fff;
border: 3px solid black;
border-radius: 8px;
padding: 25px 0;
margin: 0 1px;
text-align: center;
box-sizing: border-box;
width: calc(25% - 2px);
}
</style>
</head>
<body>
<script>
main();
function main() {
const output = document.createElement('div');
output.append(makeButtonsV1());
output.append(makeButtonsV2());
document.body.append(output);
}
function makeButtonsV1() {
const buttonHolder = document.createElement('div');
buttonHolder.classList.add('buttonHolder');
const result = document.createElement('div');
result.classList.add('result');
buttonHolder.append(result);
const buttonLabels = ['ONE', 'TWO', 'THREE', 'FOUR'];
result.textContent = buttonLabels[0];
for (const label of buttonLabels) {
const button = document.createElement('button');
button.classList.add('button');
button.textContent = label;
button.addEventListener('click', () => {
result.textContent = label;
});
buttonHolder.append(button);
}
return buttonHolder;
}
function makeButtonsV2() {
const buttonHolder = document.createElement('div');
buttonHolder.classList.add('buttonHolder');
const result = document.createElement('div');
result.classList.add('result');
buttonHolder.append(result);
const buttonLabels = ['ONE', 'TWO', 'THREE', 'FOUR'];
result.textContent = buttonLabels[0];
for (const label of buttonLabels) {
const button = document.createElement('button');
button.classList.add('button');
button.textContent = label;
button.addEventListener('click', () => {
result.textContent = label;
});
// Adding this seems to cause a delay with the above click handler
// when testing in Chrome on iOS (not reproducible in other
// browsers on iOS or any browser on my Android device, etc.).
button.addEventListener('touchstart', () => {});
buttonHolder.append(button);
}
return buttonHolder;
}
</script>
</body>
</html>

Through javascript, how do I add a div to my html script with another div inside of it?

I am trying to create a notes app where the user can press a button, type text, which will spawn a box consisting of the text, which can be stretched and dragged around the screen. The part I am having trouble on is when the button is pressed and the text is inserted, the first div will spawn, but the child div isn't being spawned properly and acts strange.
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="Filler/Style.css">
</head>
<body>
<button type="button" id="button">Add Filler</button>
<script src="Sketch.js"></script>
<script src="Filler/Sketch.js"></script>
<script src="Sidebar/Sketch.js"></script>
</body>
</html>
CSS
#mydiv {
position: absolute;
background-color: pink;
border: 1px solid black;
width: 200px;
height: 200px;
z-index: 4;
/* div able to be resised and scroll bar will be added if contents is too long .hidden*/
resize: both;
overflow: scroll;
/* create rounded borders */
border-radius: 15px;
-moz-border-radius: 15px;
text-align: center;
}
#mydivheader {
cursor: move;
z-index: 10;
}
Javascript
var myButton = document.getElementById("button");
myButton.addEventListener("click", clicked);
function clicked(){
const content = prompt("Div Contents");
const div = document.createElement('div');
const div2 = document.createElement('div');
div.id = "mydiv";
div.textContent = content;
div2.id = "mydivheader";
div2.style = "width: 100%; height: 15px;";
div2.textContent = content;
document.body.append(div);
div.appendChild(div2);
}
i didn't understood ur question properly.
is that the problem with content being generated twice. like one inside the parent div and another inside the child.
if so try this
function clicked(){
const content = prompt("Div Contents");
const div = document.createElement('div');
const div2 = document.createElement('div');
div.id = "mydiv";
div2.id = "mydivheader";
div2.style = "width: 100%; height: 15px;";
div2.textContent = content;
document.body.append(div);
div.appendChild(div2);
}

Continuous call on EventListener on mousedown

I'm working on an Etch A Sketch app for The Odin Project and I want to adjust one of the requirements where all I need to do is move the mouse on screen as a continuous stroke where each pixel touched on mouseover is filled, which is what's happening right now with my code.
What I want to change is the mouseover on my tile EventListener where it's really a continuous stroke on mousedown. I did try changing the e.target command in the setTiles function to toggle after changing the tile.addEventListener to mousedown, but it only works on each press of the left mouse button.
I'm trying to figure out a way to make this continuous on mousedown instead of using mouseover. I've included the code I have so far in the question.
const container = document.querySelector('#container');
const grid = document.querySelector('#grid');
const userInput = document.querySelector('#user-input');
let penDown = false;
grid.style.fontSize = '1em';
// Set pixel width and height
let wdt = '1em';
let hgt = '1em';
// Ask the user for the number of tiles for the sketch grid
function getUserInput() {
let input = parseInt(prompt(`Please enter the grid size you'd like`));
input <= 100 || !isNaN(input)
? createSketchGrid(input)
: alert('Please enter a valid number less than or equal to 100.');
}
// Event listener to create tiles in mouseover
function setTiles(e) {
e.target.classList.add('fill');
}
// function deleteTiles(e) {
// e.target.classList.toggle('fill');
// }
container.addEventListener('mousedown', function () {
penDown = true;
});
container.addEventListener('mouseup', function () {
penDown = false;
});
// Create the grid
function createSketchGrid(tiles) {
let gridSize = tiles * tiles;
for (let i = 0; i < gridSize; i++) {
let tile = document.createElement('div');
tile.style.width = wdt;
tile.style.height = hgt;
grid.appendChild(tile);
// tile.addEventListener('mouseover', setTiles, false);
if ((penDown === true)) {
tile.addEventListener('mousemove', setTiles);
}
}
}
userInput.addEventListener('click', getUserInput);
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html {
font-size: 10px;
}
h1 {
font-size: 3rem;
}
.grid {
/* font-size: 1.6rem; */
display: flex;
flex-wrap: wrap;
gap: 0.1em;
border: 2px solid black;
background-color: lightgrey;
flex: 0 0 32em;
}
.fill {
flex-wrap: wrap;
background-color: black;
}
<!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>Etch A Sketch</title>
<link rel="stylesheet" type="text/css" href="styles/style.css">
<script type="text/javascript" src="js/main.js" defer></script>
</head>
<body>
<h1 class="title">Etch A Sketch</h1>
<div id="container" class="container">
<button id="user-input" class="btn user-input" value="Grid Size">Grid Size</button>
<div id="grid" class="grid">
</div>
</div>
</body>
</html>

How to generate multiple div at random position inside a parent div using Javascript?

I am actually trying to create a game when someone hover on the gray area then it will ask if he wants to play if he confirm then random 5 div will appear in some different area of that parent div.
at first there should be only 1 big div. when someone will hover a mouse there will be option if he wants to play the game. then the big div will generate 5 small divs inside it. ( next i have delete if someone click small divs and need to track point, so its a small game for just my learning perpose
but i stuck here because i can't generate divs in random position. if you run my code you will see 3 divs verticaly appear when you confirm to play
function hoverinside(x) {
let answer = confirm("Do you want to play the game?");
if (answer == true) {
alert("Enjoy the game");
myFunction();
}
else {
alert("If you want to play just hover on the gray area again");
location.reload();
}
}
function myFunction() {
var element = document.createElement('div');
element.style.cssText = "width:55px; height:55px; background:green;";
document.body.appendChild(element);
var div1 = document.getElementById("square");
div1.insertBefore(element, div1.childNodes[5])
var element2 = document.createElement('div');
element2.style.cssText = "width:55px; height:55px; background:yellow;"
document.body.appendChild(element2);
var div2 = document.getElementById("square");
div2.insertBefore(element2, div2.childNodes[5])
var element3 = document.createElement('div');
element3.style.cssText = "width:55px; height:55px; background:red;";
document.body.appendChild(element3);
var div3 = document.getElementById("square");
div3.insertBefore(element3, div3.childNodes[5])
}
function removediv1() {
var element = document.getElementById("div2");
element.classList.remove("div2");
}
h1 {
font-style: bold;
color: brown;
}
#square{
height: 350px;
width: 700px;
background-color: rgb(170, 168, 168);
border: brown;
border-style: solid;
}
#square1{
height: 35px;
width: 70px;
background-color: rgb(245, 10, 10);
}
<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">
<link href="style.css" rel="stylesheet" type="text/css">
<script src="gamejs.js"></script>
<title>Game</title>
</head>
<body onload=OpenInNewtab(google.com)>
<h1>Game:</h1>
<p>we will create the game over here. no problem just wait and chill and play with us.we will create the game over here. no problem just wait and chill and play with us.</p>
<h1>Points:</h1>
<br>
<div id="square" onmouseover="hoverinside(this)" >
<div id="child1"> </div>
</div>
</body>
</html>
this is my code
You can do something like this.
Steps
Create a child div
Add id to itnot necessay.
For distinguishing, add different colors
Make the child div as absolute
Add random left & right position styling to Child Div (This will assure the randomness)
Updated the code, so that child div be be confined inside parent div.
You can refer to this codepen: https://codepen.io/hackhimanshu1024/pen/JjrjOjK
Note: I am not adding hover and deleting events. You can handle it as per your code.
Note: Add other styles as per your requirements.
const parentBody = document.getElementById("root");
const btn1 = document.getElementById("btn1");
const btn2 = document.getElementById("btn2");
let i = 0, interval
function addDiv(cnt = 5) {
const div = document.createElement('div');
div.id = 'div';
div.style.top = `${Math.random() * 100}%`;
div.style.left = `${Math.random() * 100}%`;
div.style.backgroundColor = `rgb(${Math.random() * 100},${Math.random() * 100},${Math.random() * 100})`;
parentBody.appendChild(div);
i++;
if (i === cnt) clearInterval(interval);
}
function intervalDiv(){
i=0;
interval = setInterval(addDiv, 1000);
}
function multipleDiv(){
i=0;
while(i<5){
addDiv();
}
}
btn1.addEventListener('click', intervalDiv);
btn2.addEventListener('click', multipleDiv);
*{
box-sizing: border-box;
padding:0;
margin:0;
}
body{
height:100vh;
max-height:100vh;
max-width:100vw;
padding: 100px;
}
#root{
height:100%;
max-height:100%;
position: relative;
}
#btn1, #btn2{
position:relative;
z-index:200;
}
#div {
width: 200px;
height: 200px;
position: absolute;
transform: translate(-50%,-50%);
}
<html>
<body>
<div id="root">
<button id="btn1">CLICK ME on Interval</button>
<button id="btn2">CLICK ME for 5 times</button>
</div>
</body>
</html>

Swap places on moving on element like in Windows taskbar (pure JavaScript)

I wrote this code to make any element with class draggable draggable.
const d = document.getElementsByClassName("draggable");
for (let i = 0; i < d.length; i++) {
d[i].style.position = "relative";
}
function filter(e) {
let target = e.target;
if (!target.classList.contains("draggable")) {
return;
}
target.moving = true;
e.clientX ?
(target.oldX = e.clientX,
target.oldY = e.clientY) :
(target.oldX = e.touches[0].clientX,
target.oldY = e.touches[0].clientY)
target.oldLeft = window.getComputedStyle(target).getPropertyValue('left').split('px')[0] * 1;
target.oldTop = window.getComputedStyle(target).getPropertyValue('top').split('px')[0] * 1;
document.onmousemove = dr;
document.addEventListener('touchmove', dr, {passive: false})
function dr(event) {
event.preventDefault();
if (!target.moving) {
return;
}
event.clientX ?
(target.distX = event.clientX - target.oldX,
target.distY = event.clientY - target.oldY) :
(target.distX = event.touches[0].clientX - target.oldX,
target.distY = event.touches[0].clientY - target.oldY)
target.style.left = target.oldLeft + target.distX + "px";
target.style.top = target.oldTop + target.distY + "px";
}
function endDrag() {
target.moving = false;
}
target.onmouseup = endDrag;
target.ontouchend = endDrag;
}
document.onmousedown = filter;
document.ontouchstart = filter;
div {
width: 100px;
height: 100px;
background: red;
}
<div class="draggable"></div>
tl;dr- I want to make a Windows taskbar thing where elements can be moved and the other elements move to the right or left based on where the dragged element is approaching it.
I want the draggable elements to snap to the grid similar to what happens when you drag an icon on the Windows taskbar or a tab on another tab in your browser.
Following is my attempt. I removed movement along the verticle axis and touch support to make the code more readable. The snapping is working fine but the element being hovered is not moving to the other space.
const d = document.getElementsByClassName("draggable");
let grid = 50;
for (let i = 0; i < d.length; i++) {
d[i].style.position = "relative";
d[i].onmousedown = filter;
}
function filter(e) {
let target = e.target;
target.moving = true;
target.oldX = e.clientX;
target.oldLeft = window.getComputedStyle(target).getPropertyValue('left').split('px')[0] * 1;
document.onmousemove = dr;
function dr(event) {
event.preventDefault();
if (!target.moving) {
return;
}
target.distX = event.clientX - target.oldX;
target.style.left = target.oldLeft + Math.round(target.distX / grid) * grid + 'px'
}
function endDrag() {
target.moving = false;
}
document.onmouseup = endDrag;
}
.parent {
width: 100%;
height: 100%;
background: lime;
display: flex;
align-items: center;
}
.child {
width: 50px;
height: 50px;
position: relative;
}
.one {
background: red;
}
.two {
background: blue;
}
<div class="parent">
<div class="child one draggable"></div>
<div class="child two draggable"></div>
</div>
Further, I think checking for when the mouse has crossed half of the width of a div, while an element is being dragged, the div should move either one unit left or right depending whether the element is left or right to the element being dragged. The checking part is no trouble. We can just compare the magnitudes of the elements' offsetLeft. But how do I make the element move?
Please try to answer in vanilla javascript.
Edits: 1. Updated code 2. Updated title 3. Updated tl;dr and changed title 3.Added more tags
Method 1: Pure JS Code continuing from question
The following code fulfills the question's demand. I added more elements to the original code (more elements = more fun). I have also added comments in the code. I am sure you will understand the code just by reading it. Here is a brief explanation anyway.
Snapping target in a grid
We first need to snap elements in a grid. We first snap target, see the next section for snapping other elements. The grid's width in pixels is specified in the line let grid = .... For smooth animation, we want the target to snap when we end dragging, not while we are dragging. This line of code in the function endDrag snaps the target into grid when drag is over.
target.style.left = target.oldLeft + Math.round(target.distX / grid) * grid + "px";
Moving other elements based on target
We also need to move the element whose position target takes. Otherwise, they would overlap. The function moveElementAt does this job. This is what happens in moveElementAt.
We name any element that collides with the target's top-left corner elementAt. The JavaScript property .elementFromPoint does the check.
In the checking, we exclude the target itself by setting its CSS pointer-events to none. We do nothing if elementAt is the parent element.
We check if the element is approaching at elementAt from left or right by some mathematical logic.
If the target is coming from the right, elementAt moves grid units towards the right.
If the target is coming from left elementAt moves grid units left.
const d = document.getElementsByClassName("draggable");
let grid = 50; //Width of one grid box
for (let i = 0; i < d.length; i++) {
d[i].style.position = "relative";
}
function filter(e) {
let target = e.target;
target.moving = true;
target.oldX = e.clientX;
target.oldLeft =
window
.getComputedStyle(target)
.getPropertyValue("left")
.split("px")[0] * 1; //Get left style as a number
document.onmousemove = dr;
function dr(event) {
event.preventDefault();
if (!target.moving) {
return;
}
target.distX = event.clientX - target.oldX;
target.style.left = target.oldLeft + target.distX + "px";
target.style.pointerEvents = "none"; //Stops target from being elementAt
moveElementAt();
}
function endDrag() {
target.moving = false;
target.style.left =
target.oldLeft + Math.round(target.distX / grid) * grid + "px";
moveElementAt(); //Do it at endDrag() also to stop elements from overlapping
target.style.pointerEvents = "auto";
}
function moveElementAt() {
let rootEl = target.parentNode;
let elementAt = document.elementFromPoint(
target.offsetLeft,
target.offsetTop //Get element at target's coordinates
);
if (elementAt === rootEl) {
return
} //Stop rootEl from moving
//Move elementAt either grid units left or right depending on which way target is approaching it from
if (target.offsetLeft - elementAt.offsetLeft * 1 <= grid / 2) //Can also compare to 0, comparing to grid/2 stops elements' position from breaking when moving very fast to some extent
{
elementAt.style.left =
window
.getComputedStyle(elementAt)
.getPropertyValue("left")
.split("px")[0] * 1 - grid + "px";
} else {
elementAt.style.left =
window
.getComputedStyle(elementAt)
.getPropertyValue("left")
.split("px")[0] * 1 + grid + "px";
}
}
document.onmouseup = endDrag;
}
document.onmousedown = filter;
.parent {
width: 100%;
height: 100%;
background: lime;
display: flex;
align-items: center;
}
.child {
width: 50px;
height: 50px;
position: relative;
}
.one {
background: red;
}
.two {
background: blue;
}
.three {
background: brown;
}
.four {
background: pink;
}
<!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" />
<title>Hello!</title>
<link rel="stylesheet" href="/style.css" />
<script src="/scriptmain.js"></script>
</head>
<body>
<div class="parent" id="parent">
<div class="child one draggable"></div>
<div class="child two draggable"></div>
<div class="child three draggable"></div>
<div class="child four draggable"></div>
</div>
</body>
</html>
The code is a bit glitchy when dragging unusually fast. I will fix the glitch later though.
Method 2: Using the Drag and Drop API / a library
Jon Nezbit notified me that there is a library called SortableJs specifically meant for this purpose. The question stated for a pure JS solution. So I coded a method that used the drag and drop API. Here is a snippet.
function sortable(rootEl) {
let dragEl;
for (let i = 0; i < rootEl.children.length; i++) {
rootEl.children[i].draggable = true;
}
rootEl.ondragstart = evt => {
dragEl = evt.target;
rootEl.addEventListener("dragover", onDragOver);
rootEl.addEventListener("dragend", onDragEnd);
};
function onDragOver(evt) {
let target = evt.target;
rootEl.insertBefore(
dragEl,
rootEl.children[0] === target ?
rootEl.children[0] :
target.nextSibling || target
);
}
function onDragEnd(evt) {
evt.preventDefault();
rootEl.removeEventListener("dragover", onDragOver);
rootEl.removeEventListener("dragend", onDragEnd);
}
}
sortable(document.getElementById("parent"))
.parent {
width: 100%;
height: 100%;
background: lime;
display: flex;
align-items: center;
}
.child {
width: 50px;
height: 50px;
position: relative;
}
.one {
background: red;
}
.two {
background: blue;
}
.three {
background: brown;
}
.four {
background: pink;
}
<!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" />
<title>Hello!</title>
<link rel="stylesheet" href="/style.css" />
</head>
<body>
<div class="parent" id="parent">
<div class="child one draggable"></div>
<div class="child two draggable"></div>
<div class="child three draggable"></div>
<div class="child four draggable"></div>
</div>
<script src="/script-dndmain.js"></script>
</body>
</html>
The library uses the HTML Drag and Drop API which does not give me the result as I wanted. But you should definitely check that out. Also, check out this excellent article from the author of the library which explains (with pure js) how they made that library. Although I did not use it, I am sure someone will be helped out.

Categories

Resources