source: gs3-extensions/tabletop-dl/trunk/drag-with-inertia.js@ 37462

Last change on this file since 37462 was 37462, checked in by davidb, 14 months ago

Better merging of winbox.js styled page with DIY drag-with-intertia.html

File size: 8.1 KB
Line 
1// For details about event bubbling, see:
2// https://javascript.info/bubbling-and-capturing
3
4
5// If thinking about adding touch-pad gesutring, see:
6// https://kenneth.io/post/detecting-multi-touch-trackpad-gestures-in-javascript
7
8let DragDEBUG = true;
9
10var activeDrag = {
11
12 // The element to drag
13 draggableElement: null,
14
15 // Define the starting position of the element
16 startX: 0,
17 startY: 0,
18
19 // Define the current position and velocity of the element
20 currentX: 0,
21 currentY: 0,
22
23 lastX: 0,
24 lastY: 0,
25 animationId: null,
26
27 velocityX: 0,
28 velocityY: 0,
29
30 dragging: false
31};
32
33let docXDim = null;
34let docYDim = null;
35
36
37
38function handleDragStart(event, client_x, client_y)
39{
40 if (DragDEBUG) {
41 console.log(` handleDragStart(${client_x},${client_y})`);
42 }
43
44 activeDrag.currentX = activeDrag.lastX = activeDrag.draggableElement.offsetLeft;
45 activeDrag.currentY = activeDrag.lastY = activeDrag.draggableElement.offsetTop;
46
47 activeDrag.startX = client_x - activeDrag.currentX;
48 activeDrag.startY = client_y - activeDrag.currentY;
49
50 // Stop any existing animation
51 cancelAnimationFrame(activeDrag.animationId);
52
53 activeDrag.dragging = true;
54}
55
56
57function handleTouchStart(event)
58{
59 if (DragDEBUG) {
60 console.log("handleTouchtart()");
61 }
62
63 let client_x = event.touches[0].clientX;
64 let client_y = event.touches[0].clientY;
65
66 handleDragStart(event,client_x,client_y);
67}
68
69
70function handleMouseStart(event)
71{
72 if (DragDEBUG) {
73 console.log("handleMouseStart()");
74 }
75
76 if (event.target == event.currentTarget) {
77 // As we know this is our element, don't want to
78 // allow any other events, such as text selection with
79 // child div elements
80
81 event.preventDefault();
82 }
83
84 let client_x = event.clientX;
85 let client_y = event.clientY;
86
87 handleDragStart(event,client_x,client_y);
88}
89
90
91function handleDrag(event, client_x, client_y)
92{
93 if (DragDEBUG) {
94 console.log(` handleDrag(${client_x},${client_y})`);
95 }
96
97 if (event.target == event.currentTarget) {
98 if (DragDEBUG) {
99 console.log(` + event.target == event.currentTarget`);
100 }
101
102
103 const de_x_org = client_x - activeDrag.startX;
104 const de_y_org = client_y - activeDrag.startY;
105
106 let de_x_dim = $(activeDrag.draggableElement).width();
107 let de_y_dim = $(activeDrag.draggableElement).height();
108
109 let out_of_bounds_x = false;
110 let out_of_bounds_y = false;
111
112 //console.log(` (${de_x_org},${de_y_org})`);
113
114 if ((de_x_org >= 0) && ((de_x_org+de_x_dim <= docXDim))) {
115
116 activeDrag.draggableElement.style.left = `${de_x_org}px`;
117
118 // Update the current position of the element, store previous in LastX for velocity calc
119 activeDrag.lastX = activeDrag.currentX;
120 activeDrag.currentX = de_x_org;
121
122 }
123 else {
124 out_of_bounds_x = true;
125
126 // update startX by how much the overshoot is
127 if (de_x_org<0) {
128 activeDrag.startX += de_x_org;
129 }
130 else {
131 activeDrag.startX += (de_x_org+de_x_dim) - docXDim;
132 }
133
134 }
135
136 if ((de_y_org >= 0) && (de_y_org+de_y_dim <= docYDim)) {
137
138 activeDrag.draggableElement.style.top = `${de_y_org}px`;
139
140 // Update the current position of the element, store previous in LastY for velocity calc
141 activeDrag.lastY = activeDrag.currentY;
142 activeDrag.currentY = de_y_org;
143
144 }
145 else {
146 out_of_bounds_y = true;
147
148 // update startY by how much the overshoot is
149 if (de_y_org<0) {
150 activeDrag.startY += de_y_org;
151 }
152 else {
153 activeDrag.startY += (de_y_org+de_y_dim) - docYDim;
154 }
155 }
156
157 if (!event.clientX) {
158 // Touch event
159 //
160 // prevent additional event handler
161 // this is done to stop chrome's annoying back-page operation
162 // triggering on a long right drag
163
164 event.preventDefault();
165 }
166
167 if (out_of_bounds_x || out_of_bounds_y) {
168 // Hard up against an edge
169
170 /*
171 if (event.clientX) {
172 // Mouse event
173 //
174 // Don't want any child dragging events such as selecting text to trigger, unless
175 // actually over the child element
176
177 event.preventDefault();
178 }*/
179 }
180 }
181 else {
182 if (DragDEBUG) {
183 console.log(` - event.target != event.currentTarget`);
184 }
185 }
186}
187
188function handleTouchDrag(event)
189{
190 const client_x = event.touches[0].clientX;
191 const client_y = event.touches[0].clientY;
192
193 handleDrag(event,client_x,client_y);
194}
195
196function handleMouseDrag(event)
197{
198 if (activeDrag.dragging) {
199 const client_x = event.clientX;
200 const client_y = event.clientY;
201
202 handleDrag(event,client_x,client_y);
203 }
204}
205
206
207function handleDragEnd(event)
208{
209 if (DragDEBUG) {
210 console.log(` handleDragEnd(velocityX = ${activeDrag.currentX} - ${activeDrag.lastX}, velocityY = ${activeDrag.currentY} - ${activeDrag.lastY}`);
211 }
212
213 activeDrag.dragging = false;
214
215 // Calculate the velocity of the element based on the last few frames of movement
216 activeDrag.velocityX = activeDrag.currentX - activeDrag.lastX;
217 activeDrag.velocityY = activeDrag.currentY - activeDrag.lastY;
218
219 // Animate the movement of the element
220 activeDrag.animationId = requestAnimationFrame(animateElement);
221}
222
223// Define the animation function
224function animateElement() {
225 // Update the position of the element based on its current velocity
226 activeDrag.currentX += activeDrag.velocityX;
227 activeDrag.currentY += activeDrag.velocityY;
228
229 let x = activeDrag.currentX;
230 let y = activeDrag.currentY;
231
232 // Update the element's position
233 activeDrag.draggableElement.style.left = `${x}px`;
234 activeDrag.draggableElement.style.top = `${y}px`;
235
236 let de_x_dim = $(activeDrag.draggableElement).width();
237 let de_y_dim = $(activeDrag.draggableElement).height();
238
239
240 if (x < -0.05) {
241 // bounce, taking a small dampening hit in velocity/force first
242 activeDrag.velocityX *= 0.75;
243
244 activeDrag.currentX = 0;
245 activeDrag.velocityX = -1 * activeDrag.velocityX;
246 }
247 else if ((x+de_x_dim) > (docXDim+0.05)) {
248 // bounce, taking a small dampening hit in velocity/force first
249 activeDrag.velocityX *= 0.75;
250
251 activeDrag.currentX = docXDim-de_x_dim;
252 activeDrag.velocityX = -1 * activeDrag.velocityX;
253 }
254
255 if (y < -0.05) {
256 // bounce, taking a small dampening hit in velocity/force first
257 activeDrag.velocityY *= 0.75;
258
259 activeDrag.currentY = 0;
260 activeDrag.velocityY = -1 * activeDrag.velocityY;
261 }
262 else if (((y+de_y_dim) > (docYDim+0.05))) {
263 // bounce, taking a small dampening hit in velocity/force first
264 activeDrag.velocityY *= 0.75;
265
266 activeDrag.currentY = docYDim-de_y_dim;
267 activeDrag.velocityY = -1 * activeDrag.velocityY;
268 }
269
270 // Decelerate the velocity over time
271 activeDrag.velocityX *= 0.95;
272 activeDrag.velocityY *= 0.95;
273
274 // Stop the animation when the velocity is low enough
275 if (Math.abs(activeDrag.velocityX) < 0.1 && Math.abs(activeDrag.velocityY) < 0.1) {
276 cancelAnimationFrame(activeDrag.animationId);
277 } else {
278 activeDrag.animationId = requestAnimationFrame(animateElement);
279 }
280}
281
282function handleTouchDragEnd(event)
283{
284 handleDragEnd(event);
285}
286
287function handleMouseDragEnd(event)
288{
289 if (activeDrag.dragging) {
290 handleDragEnd(event)
291 }
292}
293
294// Add the event listeners
295//let lastX, lastY, animationId;
296//let animationId;
297
298// https://stackoverflow.com/questions/56703458/how-to-make-a-draggable-elements-for-touch-and-mousedrag-events
299
300$(document).ready(function() {
301 //console.log("document ready");
302
303 //docXDim = document.body.clientHeight;
304 //docYDim = document.body.clientWidth;
305
306 docXDim = Math.max($(document).width(), $(window).width() );
307 docYDim = Math.max($(document).height(),$(window).height());
308
309 activeDrag.draggableElement = document.getElementById('myWindow');
310
311 // psudeo drag-start
312 activeDrag.draggableElement.addEventListener('touchstart', handleTouchStart);
313 activeDrag.draggableElement.addEventListener('mousedown', handleMouseStart);
314
315 // psudeo drag
316 activeDrag.draggableElement.addEventListener('touchmove', handleTouchDrag);
317 activeDrag.draggableElement.addEventListener('mousemove', handleMouseDrag)
318
319
320 // psudeo drag-end
321 activeDrag.draggableElement.addEventListener('touchend', handleTouchDragEnd);
322 activeDrag.draggableElement.addEventListener('mouseup', handleMouseDragEnd);
323});
Note: See TracBrowser for help on using the repository browser.