-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscrollit-1.js
More file actions
174 lines (153 loc) · 5.56 KB
/
Copy pathscrollit-1.js
File metadata and controls
174 lines (153 loc) · 5.56 KB
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
// Browser support:
// Chrome >= 24
// Firefox >= 23
// IE >= 10
// Opera >= 15
// Safari >= 8 (on previous versions it breaks on 'now' in window.performance)
// Android 4.4
// Firefox >= 23
// IE Mobile >= 10
// Opera Mobile >= 15
// Safari iOS >= 9
// Chrome for Android >= 35
/**
*
* @param {(number|HTMLElement)} destination - Destination to scroll to (DOM element or number)
* @param {number} duration - Duration of scrolling animation
* @param {string} easing - Timing function name (Allowed values: 'linear', 'easeInQuad', 'easeOutQuad', 'easeInOutQuad', 'easeInCubic', 'easeOutCubic', 'easeInOutCubic', 'easeInQuart', 'easeOutQuart', 'easeInOutQuart', 'easeInQuint', 'easeOutQuint', 'easeInOutQuint')
* @param {function} callback - Optional callback invoked after animation
*/
function scrollIt(destination, duration = 200, easing = 'linear', callback) {
// Predefine list of available timing functions
// If you need more, tween js is full of great examples
// https://github.com/tweenjs/tween.js/blob/master/src/Tween.js#L421-L737
const easings = {
linear(t) {
return t;
},
easeInQuad(t) {
return t * t;
},
easeOutQuad(t) {
return t * (2 - t);
},
easeInOutQuad(t) {
return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
},
easeInCubic(t) {
return t * t * t;
},
easeOutCubic(t) {
return (--t) * t * t + 1;
},
easeInOutCubic(t) {
return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
},
easeInQuart(t) {
return t * t * t * t;
},
easeOutQuart(t) {
return 1 - (--t) * t * t * t;
},
easeInOutQuart(t) {
return t < 0.5 ? 8 * t * t * t * t : 1 - 8 * (--t) * t * t * t;
},
easeInQuint(t) {
return t * t * t * t * t;
},
easeOutQuint(t) {
return 1 + (--t) * t * t * t * t;
},
easeInOutQuint(t) {
return t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * (--t) * t * t * t * t;
}
};
// Store initial position of a window and time
// If performance is not available in your browser
// It will fallback to new Date().getTime() - thanks IE < 10
const start = window.pageYOffset;
const startTime = 'now' in window.performance ? performance.now() : new Date().getTime();
// const startTime = typeof(window.performance['now']) == 'function' ? performance.now() : new Date().getTime();
// Take height of window and document to sesolve max scrollable value
// Prevent requestAnimationFrame() from scrolling below maximum scollable value
// Resolve destination type (node or number)
const documentHeight = Math.max(document.body.scrollHeight, document.body.offsetHeight, document.documentElement.clientHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight);
const windowHeight = window.innerHeight || document.documentElement.clientHeight || document.getElementsByTagName('body')[0].clientHeight;
const destinationOffset = typeof destination === 'number' ? destination : destination.offsetTop;
const destinationOffsetToScroll = Math.round(documentHeight - destinationOffset < windowHeight ? documentHeight - windowHeight : destinationOffset);
// If requestAnimationFrame is not supported
// Move window to destination position and trigger callback function
if ('requestAnimationFrame' in window === false) {
window.scroll(0, destinationOffsetToScroll);
if (callback) {
callback();
}
return;
}
// function resolves position of a window and moves to exact amount of pixels
// Resolved by calculating delta and timing function choosen by user
function scroll() {
const now = 'now' in window.performance ? performance.now() : new Date().getTime();
const time = Math.min(1, ((now - startTime) / duration));
const timeFunction = easings[easing](time);
window.scroll(0, Math.ceil((timeFunction * (destinationOffsetToScroll - start)) + start));
// Stop requesting animation when window reached its destination
// And run a callback function
if (window.pageYOffset === destinationOffsetToScroll) {
if (callback) {
callback();
}
return;
}
// If window still needs to scroll to reach destination
// Request another scroll invokation
requestAnimationFrame(scroll);
}
// Invoke scroll and sequential requestAnimationFrame
scroll();
}
// Scroll to section 1
document.querySelector('.js-btn1').addEventListener('click', () => {
scrollIt(
document.querySelector('.js-section1'),
300,
'easeOutQuad',
() => console.log(`Just finished scrolling to ${window.pageYOffset}px`)
);
});
// Scroll to section 2
document.querySelector('.js-btn2').addEventListener('click', () => {
scrollIt(
document.querySelector('.js-section2'),
300,
'easeOutQuad',
() => console.log(`Just finished scrolling to ${window.pageYOffset}px`)
);
});
// Scroll to section 3
document.querySelector('.js-btn3').addEventListener('click', () => {
scrollIt(
document.querySelector('.js-section3'),
300,
'easeOutQuad',
() => console.log(`Just finished scrolling to ${window.pageYOffset}px`)
);
});
// Scroll to 500px from top
document.querySelector('.js-btn500').addEventListener('click', () => {
scrollIt(
500,
300,
'easeOutQuad',
() => console.log(`Just finished scrolling to ${window.pageYOffset}px`)
);
});
// Scroll to 50000px from top (on purpose longer than document)
document.querySelector('.js-btn50000').addEventListener('click', () => {
scrollIt(
50000,
300,
'easeOutQuad',
() => console.log(`Just finished scrolling to ${window.pageYOffset}px`)
);
});