en.javascript.info/2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/solution.view/soccer.js

116 lines
No EOL
3.4 KiB
JavaScript

let isDragging = false;
document.addEventListener('mousedown', function(event) {
let dragElement = event.target.closest('.draggable');
if (!dragElement) return;
event.preventDefault();
dragElement.ondragstart = function() {
return false;
};
let coords, shiftX, shiftY;
startDrag(dragElement, event.clientX, event.clientY);
function onMouseUp(event) {
finishDrag();
};
function onMouseMove(event) {
moveAt(event.clientX, event.clientY);
}
// on drag start:
// remember the initial shift
// move the element position:fixed and a direct child of body
function startDrag(element, clientX, clientY) {
if(isDragging) {
return;
}
isDragging = true;
document.addEventListener('mousemove', onMouseMove);
element.addEventListener('mouseup', onMouseUp);
shiftX = clientX - element.getBoundingClientRect().left;
shiftY = clientY - element.getBoundingClientRect().top;
element.style.position = 'fixed';
moveAt(clientX, clientY);
};
// switch to absolute coordinates at the end, to fix the element in the document
function finishDrag() {
if(!isDragging) {
return;
}
isDragging = false;
dragElement.style.top = parseInt(dragElement.style.top) + pageYOffset + 'px';
dragElement.style.position = 'absolute';
document.removeEventListener('mousemove', onMouseMove);
dragElement.removeEventListener('mouseup', onMouseUp);
}
function moveAt(clientX, clientY) {
// new window-relative coordinates
let newX = clientX - shiftX;
let newY = clientY - shiftY;
// check if the new coordinates are below the bottom window edge
let newBottom = newY + dragElement.offsetHeight; // new bottom
// below the window? let's scroll the page
if (newBottom > document.documentElement.clientHeight) {
// window-relative coordinate of document end
let docBottom = document.documentElement.getBoundingClientRect().bottom;
// scroll the document down by 10px has a problem
// it can scroll beyond the end of the document
// Math.min(how much left to the end, 10)
let scrollY = Math.min(docBottom - newBottom, 10);
// calculations are imprecise, there may be rounding errors that lead to scrolling up
// that should be impossible, fix that here
if (scrollY < 0) scrollY = 0;
window.scrollBy(0, scrollY);
// a swift mouse move make put the cursor beyond the document end
// if that happens -
// limit the new Y by the maximally possible (right at the bottom of the document)
newY = Math.min(newY, document.documentElement.clientHeight - dragElement.offsetHeight);
}
// check if the new coordinates are above the top window edge (similar logic)
if (newY < 0) {
// scroll up
let scrollY = Math.min(-newY, 10);
if (scrollY < 0) scrollY = 0; // check precision errors
window.scrollBy(0, -scrollY);
// a swift mouse move can put the cursor beyond the document start
newY = Math.max(newY, 0); // newY may not be below 0
}
// limit the new X within the window boundaries
// there's no scroll here so it's simple
if (newX < 0) newX = 0;
if (newX > document.documentElement.clientWidth - dragElement.offsetWidth) {
newX = document.documentElement.clientWidth - dragElement.offsetWidth;
}
dragElement.style.left = newX + 'px';
dragElement.style.top = newY + 'px';
}
});