-
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathScrollManager.ts
93 lines (83 loc) · 2.87 KB
/
ScrollManager.ts
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
import { DOMPosition } from '../core/DOM/DOMElement'
/**
* Parameters used to create a {@link ScrollManager}
*/
export interface ScrollManagerParams {
/** Current scroll position */
scroll?: DOMPosition
/** Last scroll deltas */
delta?: DOMPosition
/** Whether the {@link ScrollManager} should listen to the window scroll event or not */
shouldWatch?: boolean
/** Callback to execute each time the {@link ScrollManager#scroll | scroll} values change */
onScroll?: (delta?: DOMPosition) => void
}
/**
* Used to keep track of our scroll position, scroll deltas and trigger an onScroll callback.<br>
* Could either listen to the native scroll event or be hooked to any scroll (natural or virtual) scroll event
*/
export class ScrollManager {
/** Current scroll position */
scroll: DOMPosition
/** Last scroll deltas */
delta: DOMPosition
/** Whether the {@link ScrollManager} should listen to the window scroll event or not */
shouldWatch: boolean
/** Callback to execute each time the {@link scroll} values change */
onScroll: (delta?: DOMPosition) => void
/**
* ScrollManager constructor
* @param parameters - {@link ScrollManagerParams | parameters} used to create this {@link ScrollManager}
*/
constructor({
scroll = { x: 0, y: 0 },
delta = { x: 0, y: 0 },
shouldWatch = true,
onScroll = (delta: DOMPosition = { x: 0, y: 0 }) => {
/* allow empty callback */
},
}: ScrollManagerParams = {}) {
this.scroll = scroll
this.delta = delta
this.shouldWatch = shouldWatch
this.onScroll = onScroll
if (this.shouldWatch) {
window.addEventListener('scroll', this.setScroll.bind(this), { passive: true })
}
}
/**
* Called by the scroll event listener
*/
setScroll() {
this.updateScrollValues({ x: window.pageXOffset, y: window.pageYOffset })
}
/**
* Updates the scroll manager X and Y scroll values as well as last X and Y deltas
* Internally called by the scroll event listener
* Could be called externally as well if the user wants to handle the scroll by himself
* @param parameters - {@link core/DOM/DOMElement.DOMPosition | scroll values}
*/
updateScrollValues({ x, y }: DOMPosition) {
// get our scroll delta values
const lastScroll = this.scroll
this.scroll = { x, y }
this.delta = {
x: lastScroll.x - this.scroll.x,
y: lastScroll.y - this.scroll.y,
}
if (this.onScroll) {
this.onScroll(this.delta)
}
}
/**
* Destroy our scroll manager (just remove our event listner if it had been added previously)
*/
destroy() {
if (this.shouldWatch) {
// passive triggers a typescript error
// https://github.com/microsoft/TypeScript/issues/32912#issuecomment-522142969
window.removeEventListener('scroll', this.setScroll.bind(this), { passive: true } as AddEventListenerOptions &
EventListenerOptions)
}
}
}