I am new to javascript and web development a whole, so I am sure there is a concept I am missing here and hopefully an easy way to fix this. I am using pointer events for drag and drop and it seems that when using touch it works fine. But when using a mouse, the draggable div will have unpredictable behavior. If you move the mouse quickly while dragging the div, the cursor will loose the element and the div will get stuck in limbo. What is also strange, and possibly related, is that the pointermove event will fire without first having pointerdown fire.
I thought some type of default behavior was causing this issue so I have added a pointercancel event (which didn't help). And I have added e.preventDefault() to the handlers but this didn't help either.
<!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="styles.css">
<script src="script.js" defer></script>
<title>Document</title>
</head>
<body>
<div>
<div class="container" id="lineup">
<div class=draggable id="player1" draggable="false">1</div>
<div class=draggable id="player2" draggable="false">2</div>
<div class=draggable id="player3" draggable="false">3</div>
</div>
</div>
</body>
</html>
* {
box-sizing: border-box;
}
body {
font-family: Arial, Helvetica, sans-serif;
margin: 0;
}
#player{
border: 2px solid white;
border-radius: 6px;
margin: 2px;
}
.dragging{
border: 5px solid white;
border-radius: 6px;
margin: 2px;
color:blue;
}
.draggable.dragging {
opacity: .5;
}
.draggable{
height: 50px;
width: 50px;
border: 1px solid #000;
border-radius: 10px;
float: left;
background: blueviolet;
margin: 10px;
touch-action: none;
}
const draggables = document.querySelectorAll('.draggable')
draggables.forEach(draggable => {
draggable.addEventListener('pointerdown', e => {
e.preventDefault()
console.log(e)
draggable.classList.add('dragging')
draggable.setAttribute('draggable', true)
})
draggable.addEventListener('pointermove', e => {
console.log(e)
e.preventDefault()
const player = document.getElementById(e.target.attributes.id.nodeValue)
if (player == null) return
if (player.classList.contains('dragging')) {
positionPlayer(e, player)
} else {
return
}
})
draggable.addEventListener('pointerup', e => {
console.log(e)
e.preventDefault()
draggable.classList.remove('dragging')
draggable.setAttribute('draggable', false)
})
draggable.addEventListener('pointercancel', e => {
console.log(e)
e.preventDefault()
})
})
function positionPlayer(e, player) {
e.preventDefault()
player.style.position = 'absolute'
player.style.left = `${e.pageX-player.clientWidth/2}px`
player.style.top = `${e.pageY-player.clientWidth/2}px`
console.log(e)
}
Thanks Nick. I see you fixed the mouse issue by putting the listener on the document. The touch listeners did not work this way. I had to put them on the div to get them to work...kinda. I was looking for an easy way to use both types of listeners. To that end, the answer is jQuery. I have just started with web development so I had no idea jQuery existed. :) To anyone who may be reading this, that is new to web development like me, I suggest you learn about vanilla js and then jQuery. You will appreciate how helpful and efficient jQuery is.