-
Notifications
You must be signed in to change notification settings - Fork 0
/
javery-drag-drop.js
116 lines (84 loc) · 3.42 KB
/
javery-drag-drop.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
let isDragging = false;
document.addEventListener('mousedown', function(event) {
let dragElement = event.target.closest('.jspsych-free-sort-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) + window.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';
}
});