/
skimmer.js
125 lines (103 loc) · 2.6 KB
/
skimmer.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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/*
* skimmer.js library
*/
(function (factory) {
if (typeof define === 'function' && define.amd) {
define(factory)
} else if (typeof module !== 'undefined' && module.exports) {
module.exports = factory()
} else {
window.skimmer = factory.call(this)
}
})(() => {
const lib = ({
rate = 500,
delay = 2,
multiple = false,
trigger = () => {},
update = () => {},
}) => {
const SECOND = 1000
let triggered = false
let ignoredFirst = false
const data = {
scroll: {
previous: 0,
net: 0,
},
time: {
previous: 0,
net: 0,
start: 0,
},
}
let ticking = false
const raf = window.requestAnimationFrame
|| function(callback) { return setTimeout(callback, 1000 / 60) }
const fix = (number) => +number.toFixed(2)
const reset = () => {
data.scroll.net = 0
data.time.net = 0
data.time.start = new Date().getTime()
data.time.previous = new Date().getTime()
update({ rate: 0, distance: 0, elapsed: 0 })
}
// const onResize = () => {
// viewportHeight = window.innerHeight
// reset()
// }
const updateScroll = () => {
ticking = false
if (ignoredFirst) {
const currentScrollPos = window.pageYOffset
const currentTime = new Date().getTime()
const scrollDiff = currentScrollPos - data.scroll.previous
const timeDiff = currentTime - data.time.previous
data.scroll.net += scrollDiff
data.time.net = currentTime - data.time.start
data.time.previous = currentTime
data.scroll.previous = window.pageYOffset
// reset if they start going up OR the time jumped more than a second (stopped scrolling)
if (scrollDiff < 0 || timeDiff > SECOND / 2) {
reset()
return false
}
// test if we are skimming!
const secondsElapsed = (data.time.net / SECOND)
const currentRate = data.scroll.net / secondsElapsed
if (currentRate > rate && secondsElapsed > delay) {
if (!triggered) {
trigger({
rate: Math.round(currentRate),
distance: Math.round(data.scroll.net),
elapsed: fix(secondsElapsed),
})
}
if (!multiple) {
triggered = true
window.removeEventListener('scroll', onScroll, false)
}
} else {
update({
rate: Math.round(currentRate),
distance: Math.round(data.scroll.net),
elapsed: fix(secondsElapsed),
})
}
} else {
ignoredFirst = true
}
return true
}
const onScroll = () => {
if (!ticking) raf(updateScroll)
ticking = true
}
const init = () => {
reset()
window.addEventListener('scroll', onScroll, false)
}
init()
}
return lib
})