UNPKG

2.15 kBJavaScriptView Raw
1export default function scrollDir(opts) {
2 const defaults = {
3 el: document.documentElement,
4 win: window,
5 attribute: 'data-scrolldir',
6 };
7 const el = (opts && opts.el) || defaults.el;
8 const win = (opts && opts.win) || defaults.win;
9 const attribute = (opts && opts.attribute) || defaults.attribute;
10 if (opts && opts.off === true) {
11 return el.setAttribute(attribute, 'off');
12 }
13 const body = document.body;
14 const historyLength = 32; // Ticks to keep in history.
15 const historyMaxAge = 512; // History data time-to-live (ms).
16 const thresholdPixels = 64; // Ignore moves smaller than this.
17 const history = Array(historyLength);
18 let dir = 'down'; // 'up' or 'down'
19 let e; // last scroll event
20 let pivot; // "high-water mark"
21 let pivotTime = 0;
22
23 const tick = function tickFunc() {
24 let y = win.scrollY;
25 const t = e.timeStamp;
26 const furthest = dir === 'down' ? Math.max : Math.min;
27
28 // Apply bounds to handle rubber banding
29 const yMax = body.offsetHeight - win.innerHeight;
30 y = Math.max(0, y);
31 y = Math.min(yMax, y);
32
33 // Update history
34 history.unshift({ y, t });
35 history.pop();
36
37 // Are we continuing in the same direction?
38 if (y === furthest(pivot, y)) {
39 // Update "high-water mark" for current direction
40 pivotTime = t;
41 pivot = y;
42 return;
43 }
44 // else we have backed off high-water mark
45
46 // Apply max age to find current reference point
47 const cutoffTime = t - historyMaxAge;
48 if (cutoffTime > pivotTime) {
49 pivot = y;
50 for (let i = 0; i < historyLength; i += 1) {
51 if (!history[i] || history[i].t < cutoffTime) break;
52 pivot = furthest(pivot, history[i].y);
53 }
54 }
55
56 // Have we exceeded threshold?
57 if (Math.abs(y - pivot) > thresholdPixels) {
58 pivot = y;
59 pivotTime = t;
60 dir = dir === 'down' ? 'up' : 'down';
61 el.setAttribute(attribute, dir);
62 }
63 };
64
65 const handler = function handlerFunc(event) {
66 e = event;
67 win.requestAnimationFrame(tick);
68 };
69
70 pivot = win.scrollY;
71 el.setAttribute(attribute, dir);
72 return win.addEventListener('scroll', handler);
73}