Skip to content

Instantly share code, notes, and snippets.

@davidskuza
Forked from bennadel/index.htm
Created June 21, 2021 06:27
Show Gist options
  • Save davidskuza/776fcfdc4a2ca7c34c2df1bc6df950ba to your computer and use it in GitHub Desktop.
Save davidskuza/776fcfdc4a2ca7c34c2df1bc6df950ba to your computer and use it in GitHub Desktop.
Automatically Scroll The Window When The User Approaches The Viewport Edge In JavaScript
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>
Automatically Scroll The Window When The User Approaches The Viewport Edge In JavaScript
</title>
</head>
<body>
<h1>
Automatically Scroll The Window When The User Approaches The Viewport Edge In JavaScript
</h1>
<script type="text/javascript">
var edgeSize = 200;
var timer = null;
window.addEventListener( "mousemove", handleMousemove, false );
drawGridLines();
// --------------------------------------------------------------------------- //
// --------------------------------------------------------------------------- //
// I adjust the window scrolling in response to the given mousemove event.
function handleMousemove( event ) {
// NOTE: Much of the information here, with regard to document dimensions,
// viewport dimensions, and window scrolling is derived from JavaScript.info.
// I am consuming it here primarily as NOTE TO SELF.
// --
// Read More: https://javascript.info/size-and-scroll-window
// --
// CAUTION: The viewport and document dimensions can all be CACHED and then
// recalculated on window-resize events (for the most part). I am keeping it
// all here in the mousemove event handler to remove as many of the moving
// parts as possible and keep the demo as simple as possible.
// Get the viewport-relative coordinates of the mousemove event.
var viewportX = event.clientX;
var viewportY = event.clientY;
// Get the viewport dimensions.
var viewportWidth = document.documentElement.clientWidth;
var viewportHeight = document.documentElement.clientHeight;
// Next, we need to determine if the mouse is within the "edge" of the
// viewport, which may require scrolling the window. To do this, we need to
// calculate the boundaries of the edge in the viewport (these coordinates
// are relative to the viewport grid system).
var edgeTop = edgeSize;
var edgeLeft = edgeSize;
var edgeBottom = ( viewportHeight - edgeSize );
var edgeRight = ( viewportWidth - edgeSize );
var isInLeftEdge = ( viewportX < edgeLeft );
var isInRightEdge = ( viewportX > edgeRight );
var isInTopEdge = ( viewportY < edgeTop );
var isInBottomEdge = ( viewportY > edgeBottom );
// If the mouse is not in the viewport edge, there's no need to calculate
// anything else.
if ( ! ( isInLeftEdge || isInRightEdge || isInTopEdge || isInBottomEdge ) ) {
clearTimeout( timer );
return;
}
// If we made it this far, the user's mouse is located within the edge of the
// viewport. As such, we need to check to see if scrolling needs to be done.
// Get the document dimensions.
// --
// NOTE: The various property reads here are for cross-browser compatibility
// as outlined in the JavaScript.info site (link provided above).
var documentWidth = Math.max(
document.body.scrollWidth,
document.body.offsetWidth,
document.body.clientWidth,
document.documentElement.scrollWidth,
document.documentElement.offsetWidth,
document.documentElement.clientWidth
);
var documentHeight = Math.max(
document.body.scrollHeight,
document.body.offsetHeight,
document.body.clientHeight,
document.documentElement.scrollHeight,
document.documentElement.offsetHeight,
document.documentElement.clientHeight
);
// Calculate the maximum scroll offset in each direction. Since you can only
// scroll the overflow portion of the document, the maximum represents the
// length of the document that is NOT in the viewport.
var maxScrollX = ( documentWidth - viewportWidth );
var maxScrollY = ( documentHeight - viewportHeight );
// As we examine the mousemove event, we want to adjust the window scroll in
// immediate response to the event; but, we also want to continue adjusting
// the window scroll if the user rests their mouse in the edge boundary. To
// do this, we'll invoke the adjustment logic immediately. Then, we'll setup
// a timer that continues to invoke the adjustment logic while the window can
// still be scrolled in a particular direction.
// --
// NOTE: There are probably better ways to handle the ongoing animation
// check. But, the point of this demo is really about the math logic, not so
// much about the interval logic.
(function checkForWindowScroll() {
clearTimeout( timer );
if ( adjustWindowScroll() ) {
timer = setTimeout( checkForWindowScroll, 30 );
}
})();
// Adjust the window scroll based on the user's mouse position. Returns True
// or False depending on whether or not the window scroll was changed.
function adjustWindowScroll() {
// Get the current scroll position of the document.
var currentScrollX = window.pageXOffset;
var currentScrollY = window.pageYOffset;
// Determine if the window can be scrolled in any particular direction.
var canScrollUp = ( currentScrollY > 0 );
var canScrollDown = ( currentScrollY < maxScrollY );
var canScrollLeft = ( currentScrollX > 0 );
var canScrollRight = ( currentScrollX < maxScrollX );
// Since we can potentially scroll in two directions at the same time,
// let's keep track of the next scroll, starting with the current scroll.
// Each of these values can then be adjusted independently in the logic
// below.
var nextScrollX = currentScrollX;
var nextScrollY = currentScrollY;
// As we examine the mouse position within the edge, we want to make the
// incremental scroll changes more "intense" the closer that the user
// gets the viewport edge. As such, we'll calculate the percentage that
// the user has made it "through the edge" when calculating the delta.
// Then, that use that percentage to back-off from the "max" step value.
var maxStep = 50;
// Should we scroll left?
if ( isInLeftEdge && canScrollLeft ) {
var intensity = ( ( edgeLeft - viewportX ) / edgeSize );
nextScrollX = ( nextScrollX - ( maxStep * intensity ) );
// Should we scroll right?
} else if ( isInRightEdge && canScrollRight ) {
var intensity = ( ( viewportX - edgeRight ) / edgeSize );
nextScrollX = ( nextScrollX + ( maxStep * intensity ) );
}
// Should we scroll up?
if ( isInTopEdge && canScrollUp ) {
var intensity = ( ( edgeTop - viewportY ) / edgeSize );
nextScrollY = ( nextScrollY - ( maxStep * intensity ) );
// Should we scroll down?
} else if ( isInBottomEdge && canScrollDown ) {
var intensity = ( ( viewportY - edgeBottom ) / edgeSize );
nextScrollY = ( nextScrollY + ( maxStep * intensity ) );
}
// Sanitize invalid maximums. An invalid scroll offset won't break the
// subsequent .scrollTo() call; however, it will make it harder to
// determine if the .scrollTo() method should have been called in the
// first place.
nextScrollX = Math.max( 0, Math.min( maxScrollX, nextScrollX ) );
nextScrollY = Math.max( 0, Math.min( maxScrollY, nextScrollY ) );
if (
( nextScrollX !== currentScrollX ) ||
( nextScrollY !== currentScrollY )
) {
window.scrollTo( nextScrollX, nextScrollY );
return( true );
} else {
return( false );
}
}
}
// I draw the grid and edge lines in the document so that it is clear where
// scrolling will be initiated and with what intensity it is taking place.
function drawGridLines() {
var increment = 100;
var incrementCount = 100;
var maxDimension = ( increment * incrementCount );
// Draw the boxes that make up the grid.
for ( var x = 0 ; x < incrementCount ; x++ ) {
for ( var y = 0 ; y < incrementCount ; y++ ) {
var xOffset = ( x * increment );
var yOffset = ( y * increment );
var box = document.createElement( "span" );
box.style.position = "absolute";
box.style.top = ( yOffset + "px" );
box.style.left = ( xOffset + "px" );
box.style.height = ( increment + "px" );
box.style.width = ( increment + "px" );
box.style.border = "1px solid #CCCCCC";
box.style.font = "11px sans-serif";
box.style.color = "#999999" ;
box.style.boxSizing = "border-box";
box.style.padding = "5px 5px 5px 5px";
box.innerText = ( xOffset + ", " + yOffset );
document.body.appendChild( box );
}
}
// Draw the edges that delineate the scrolling zone.
var edge = document.createElement( "span" );
edge.style.position = "fixed";
edge.style.top = ( edgeSize + "px" );
edge.style.bottom = ( edgeSize + "px" );
edge.style.left = ( edgeSize + "px" );
edge.style.right = ( edgeSize + "px" );
edge.style.border = "2px solid #CC0000";
edge.style.borderRadius = "5px 5px 5px 5px";
document.body.appendChild( edge );
// Add mouse-guard so that nothing is selectable.
var guard = document.createElement( "div" );
guard.style.position = "fixed";
guard.style.top = "0px";
guard.style.bottom = "0px";
guard.style.left = "0px";
guard.style.right = "0px";
document.body.appendChild( guard );
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment