-
Notifications
You must be signed in to change notification settings - Fork 92
/
Copy pathraf-admin.js
156 lines (140 loc) · 3.84 KB
/
raf-admin.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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
import RafPool from 'raf-pool';
import isInViewport from 'ember-in-viewport/utils/is-in-viewport';
/**
* ensure use on requestAnimationFrame, no matter how many components
* on the page are using this class
*
* @class RAFAdmin
*/
export default class RAFAdmin {
/** @private **/
constructor() {
this._rafPool = new RafPool();
this.elementRegistry = new WeakMap();
}
add(...args) {
return this._rafPool.add(...args);
}
flush() {
return this._rafPool.flush();
}
remove(...args) {
return this._rafPool.remove(...args);
}
reset(...args) {
this._rafPool.reset(...args);
this._rafPool.stop(...args);
}
/**
* We provide our own element registry to add callbacks the user creates
*
* @method addEnterCallback
* @param {HTMLElement} element
* @param {Function} enterCallback
*/
addEnterCallback(element, enterCallback) {
this.elementRegistry.set(
element,
Object.assign({}, this.elementRegistry.get(element), { enterCallback })
);
}
/**
* We provide our own element registry to add callbacks the user creates
*
* @method addExitCallback
* @param {HTMLElement} element
* @param {Function} exitCallback
*/
addExitCallback(element, exitCallback) {
this.elementRegistry.set(
element,
Object.assign({}, this.elementRegistry.get(element), { exitCallback })
);
}
}
/**
* This is a recursive function that adds itself to raf-pool to be executed on a set schedule
*
* @method startRAF
* @param {HTMLElement} element
* @param {Object} configurationOptions
* @param {Function} enterCallback
* @param {Function} exitCallback
* @param {Function} addRAF
* @param {Function} removeRAF
*/
export function startRAF(
element,
{ scrollableArea, viewportTolerance, viewportSpy = false },
enterCallback,
exitCallback,
addRAF, // bound function from service to add elementId to raf pool
removeRAF // bound function from service to remove elementId to raf pool
) {
const domScrollableArea =
typeof scrollableArea === 'string' && scrollableArea
? document.querySelector(scrollableArea)
: scrollableArea instanceof HTMLElement
? scrollableArea
: undefined;
const height = domScrollableArea
? domScrollableArea.offsetHeight +
domScrollableArea.getBoundingClientRect().top
: window.innerHeight;
const width = scrollableArea
? domScrollableArea.offsetWidth +
domScrollableArea.getBoundingClientRect().left
: window.innerWidth;
const boundingClientRect = element.getBoundingClientRect();
if (boundingClientRect) {
const viewportEntered = element.getAttribute('data-in-viewport-entered');
triggerDidEnterViewport(
element,
isInViewport(boundingClientRect, height, width, viewportTolerance),
viewportSpy,
enterCallback,
exitCallback,
viewportEntered
);
if (viewportSpy || viewportEntered !== 'true') {
// recursive
// add to pool of requestAnimationFrame listeners and executed on set schedule
addRAF(
startRAF.bind(
this,
element,
{ scrollableArea, viewportTolerance, viewportSpy },
enterCallback,
exitCallback,
addRAF,
removeRAF
)
);
} else {
removeRAF();
}
}
}
function triggerDidEnterViewport(
element,
hasEnteredViewport,
viewportSpy,
enterCallback,
exitCallback,
viewportEntered = false
) {
const didEnter =
(!viewportEntered || viewportEntered === 'false') && hasEnteredViewport;
const didLeave = viewportEntered === 'true' && !hasEnteredViewport;
if (didEnter) {
element.setAttribute('data-in-viewport-entered', true);
enterCallback();
}
if (didLeave) {
exitCallback();
// reset so we can call again
if (viewportSpy) {
element.setAttribute('data-in-viewport-entered', false);
}
}
}