CAUTION: This is primarily a "note to self" for future Ben. This represents a part of DOM interaction that I don't have a solid mental model for. As such, my confidence level here is not stellar.
The other day, I had to a fix a bug in InVision that related to dragging DOM (Document Object Model) elements up and down in the document. As the user's mouse approached the top or bottom edge of the browser viewport, we needed to scroll the viewport such that the user could drag the selected DOM element to a position that had not been previously-visible within the viewport. Because of some cross-browser quirkiness involved in the getting and setting of document and window dimensions and offsets, I wanted to break this logic out into a demo such that I could reference it at a later time. As such, the logic in this demo will automatically scroll the window when the user approaches the viewport edge.
That said, for this demo, we want to start scrolling the window in a meaningful direction when the user moves their mouse towards the edge of the browser. And, we want the scrolling velocity to increase as the user gets closer to the edge. So, not only do we have to determine if the user's mouse is contained within the "edge" of the viewport, we have to determine how much of the edge has been crossed.
Furthermore, we want the window scrolling to be activated even after the user stops moving their mouse. Meaning, if the user moves their mouse to the "edge" of the viewport and then stops moving, we want the window to continue scrolling until it has reached its maximum scroll position. To accomplish this, I'm using an iterative setTimeout() call. I am sure something much more clever could be accomplished. But, for this demo, I was more concerned with the math and the positional calculations than I was with the smoothness and efficiency of the window scrolling itself.
That said, here is the code. The bulk of the logic is contained within the mousemove handler. The demo steps a 200-pixel "edge" on each side of the viewport that will cause the window to scroll:
Since this is primarily a note-to-self, I'm not going to add much explanation beyond the comments that are in the code. Now, if we open this in the browser and try moving the mouse to the edge of the viewport, we can see the viewport start scrolling automatically with a dynamic intensity:
Obviously, because this is a demo about movement, the effects are much easier to see in the video than they are in an annotated screenshot.
Want to use code from this post? Check out the license.
This is an interesting exploration. I do remember that prototype.js Scriptaculous draggable, has an option setting that does just what you are trying to achieve. It would be interesting to compare their approach! I used to be an avid Scriptaculous fan, before I discovered JQuery.
I knew of Scriptaculous, but I think jQuery was my first real library. Before jQuery, I used some tiny one called
sack.js that did nothing put grab the contents of a URL and inject it as the
.innerHTML of some target element. Which, was still pretty cool :)
That said, dragging stuff is easily one of the most complicated things on the web, as far as I can see. Especially when you start to bring the idea of creating "ghost" elements. And, sprinkle in the fact that many UIs are data-driven now. Like, what happens when some Angular / React digest runs mid-drag? Do you change the element, mid-drag? Do you detach it from data-binding during the drag? These are not easy questions to answer.
Great explanation and code. Thanks a lot, you saved my time.
Awesome, glad you found this helpful!
Thanks a lot Ben, it's super helpful.
N-n-n-n-noice! I'm glad you found this interesting and helpful!
Just want to know How do Implement inside the div , as it now its taking mouse move event for entire window.
I have modified like this for div but it didn't worked for me.
var container = document.querySelector('.outer-board');
container.addEventListener( "mousemove", handleMousemove, false );
Suggest me how can I implement inside the div.
Same idea. Did you do successfully ?
Wow thanks a lot this article help me to solve mine auto-scroll issue
Thank you so much for this example! Is there a way to do this for a specific element vs the mouse. and have it scroll within a container?
were you able to figure it out? and if so can you let me know how you did it?
I did though, I will post it here later
That's awesome that you were able to get it to work. I'd also like to try and come up with a solution (basically by refactoring the current demo).
Thanks !! GREAT WORK
Thank you :D Glad you found this interesting!