Skip to content

Instantly share code, notes, and snippets.

@waffleflopper
Last active August 1, 2023 20:23
Show Gist options
  • Save waffleflopper/c8e789c2ef628a9d34ca8b1ba0eee8b5 to your computer and use it in GitHub Desktop.
Save waffleflopper/c8e789c2ef628a9d34ca8b1ba0eee8b5 to your computer and use it in GitHub Desktop.
use smooth scrolling svelte action (or pass element reference as first argument and use it wherever)
/**
* Author: Robert Baddeley (waffleflopper)
* 2023
*/
/* helper */
function clamp(num: number, min: number, max: number): number {
return Math.min(Math.max(num, min), max);
}
/* useSmoothScrolling */
interface SmoothScrollOptions {
friction?: number;
maxSpeed?: number;
deadZone?: number;
}
//friction around 0.94-0.95 feels the best, imo (behaves oddly outside of 0.9 to 0.96)
//lower max speed does weird things if users mouse wheel is set to scroll a lot of lines at once
//deadZone is to prevent run away scrolling from small scroll movements
export default function useSmoothScrolling(node: HTMLElement, params: SmoothScrollOptions) {
const {friction = 0.94, maxSpeed = 60, deadZone = 0.5} = params;
//todo: map 1-100 to 0.9 to 0.96 to make friction more readable
let clampedFriction = clamp(friction, 0.9, 0.96);
let velocity = 0;
const wheelHandler = (e: WheelEvent) => {
velocity += e.deltaY * 0.1;
velocity = clamp(velocity, -maxSpeed, maxSpeed);
};
const animationHandler = () => {
if (Math.abs(velocity) > deadZone) {
velocity *= clampedFriction;
node.scrollTop += velocity;
} else {
velocity = 0;
}
frameId = window.requestAnimationFrame(animationHandler);
};
node.addEventListener('wheel', wheelHandler, { passive: true });
let frameId = window.requestAnimationFrame(animationHandler);
return {
destroy() {
node.removeEventListener('wheel', wheelHandler);
window.cancelAnimationFrame(frameId);
}
};
}
@waffleflopper
Copy link
Author

Should work with vanilla JS.

It's set up as a svelte action e.g. fn(node, params) but it's vanilla so should work anywhere.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment