-
Notifications
You must be signed in to change notification settings - Fork 23
/
scroll.js
66 lines (57 loc) · 2.06 KB
/
scroll.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
document.addEventListener("DOMContentLoaded", () => {
"use strict";
const root = (() => {
if ("scrollingElement" in document) return document.scrollingElement;
const html = document.documentElement;
const start = html.scrollTop;
html.scrollTop = start + 1;
const end = html.scrollTop;
html.scrollTop = start;
return end > start ? html : document.body;
})();
const ease = (duration, elapsed, start, end) =>
Math.round(end * (-Math.pow(2, -10 * elapsed/duration) + 1) + start);
const getCoordinates = hash => {
const start = root.scrollTop;
const delta = (() => {
if (hash.length < 2) return -start;
const target = document.querySelector(hash);
if (!target) return;
const top = target.getBoundingClientRect().top;
const max = root.scrollHeight - window.innerHeight;
return start + top < max ? top : max - start;
})();
if (delta) return new Map([["start", start], ["delta", delta]]);
};
const scroll = link => {
const hash = link.getAttribute("href");
const coordinates = getCoordinates(hash);
if (!coordinates) return;
const tick = timestamp => {
progress.set("elapsed", timestamp - start);
root.scrollTop = ease(...progress.values(), ...coordinates.values());
progress.get("elapsed") < progress.get("duration")
? requestAnimationFrame(tick)
: complete(hash, coordinates);
};
const progress = new Map([["duration", 800]]);
const start = performance.now();
requestAnimationFrame(tick);
};
const complete = (hash, coordinates) => {
history.pushState(null, null, hash);
root.scrollTop = coordinates.get("start") + coordinates.get("delta");
};
const attachHandler = (links, index) => {
const link = links.item(index);
link.addEventListener("click", event => {
event.preventDefault();
scroll(link);
});
if (index) return attachHandler(links, index - 1);
};
const links = document.querySelectorAll("a.scroll");
const last = links.length - 1;
if (last < 0) return;
attachHandler(links, last);
});