Based on the suggestions here, if only one element is required to move, the below is possibly a simple way to do it:
(function () {
let offset = [0, 0];
let target = document.querySelector('.target');
let isDown = false;
target.addEventListener('mousedown', function(e) {
isDown = true;
target.style.position = 'relative';
offset = [
target.offsetLeft - e.clientX,
target.offsetTop - e.clientY
];
}, true);
document.addEventListener('mouseup', function() {
isDown = false;
}, true);
document.addEventListener('mousemove', function(e) {
event.preventDefault();
if (isDown) {
target.style.left = (e.clientX + offset[0]) + 'px';
target.style.top = (e.clientY + offset[1]) + 'px';
}
}, true);
})();
.target {
width: 100px;
height: 100px;
background-color: #0000FF;
}
<div class="target"></div>
What if there are 2 divs? what if there's 1000? that's when the approach above won't be as convenient because if we have 1000 divs, then we need another 1000 event listeners keeping track of 1000 offset
as well as isDown
variables. During an earlier attempt, I tried to get rid of the offset
and isDown
logic using $('.target').offset()
and make the calculation happen inside mousemove
handler, but I failed. Here's an attempt to do what I described earlier which is what I'm trying to improve:
(function() {
let targetsData = {};
let targets = document.querySelectorAll('.target');
Array.prototype.map.call(targets, (target) => {
targetsData[target] = { 'mousedown': false, 'offset': [0, 0] };
target.addEventListener('mousedown', (e) => {
target.style.position = 'relative';
targetsData[target]['mousedown'] = true;
targetsData[target]['offset'] = [
target.offsetLeft - e.clientX,
target.offsetTop - e.clientY
];
});
target.addEventListener('mouseup', (e) => {
targetsData[target]['mousedown'] = false;
});
target.addEventListener('mousemove', (e) => {
e.preventDefault();
if (targetsData[target]['mousedown']) {
let offset = targetsData[target]['offset']
target.style.left = (e.clientX + offset[0]) + 'px';
target.style.top = (e.clientY + offset[1]) + 'px';
}
});
});
})();
.target {
width: 100px;
height: 100px;
background-color: #0000FF;
margin-bottom: 5px
}
<div class="target"></div>
<div class="target"></div>
<div class="target"></div>
Only the first square from the top works and if dragged quickly, some weird effects start to happen and the other ones' side effects seem to be worse:
What's happening here? What would be a way to efficiently make all of the squares move properly?