-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathnaturalScroll.js
140 lines (119 loc) · 4.68 KB
/
naturalScroll.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
/**
* @fileoverview naturalScroll - scrolls a viewport naturally
* @version 0.2.2
*
* @license MIT, see http://github.com/asvd/naturalScroll
* @copyright 2015 asvd <[email protected]>
*/
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
define(['exports'], factory);
} else if (typeof exports !== 'undefined') {
factory(exports);
} else {
factory((root.naturalScroll = {}));
}
}(this, function (exports) {
var allAnimations = [
[], // vertical scrolling animations, one for a viewport
[] // horizontal animations
];
// for better compression
var scrollTop = 'scrollTop';
var scrollLeft = 'scrollLeft';
// returns scrollTop() if argument is given, scrollLeft() otherwise
var genScroll = function(top) {
// exported method
return function(elem, target, time) {
elem = elem.scroller || elem; // needed for intence
time = time || 600;
// all animations for the particular direction
var dirAnimations = allAnimations[top ? 0 : 1];
var prop = top ? scrollTop : scrollLeft;
var animation,
tick,
i = 0,
f0 = elem[prop], // current coordinate
f1 = 0, // current speed
f2 = 0; // current acceleration
// searching for the element's animation
for (;i < dirAnimations.length; i++) {
animation = (dirAnimations[i].e == elem) ?
dirAnimations[i] : animation;
}
if (animation) {
// taking speed and accel. from the running animation
f1 = animation.f[1];
f2 = animation.f[2];
} else {
// generating a new animation which contains:
// .e - element on which the animation is performed
// .f - current animation frame data
// .n - remaining frames number
// .t - animation end timestamp
dirAnimations.push(animation = {e : elem});
}
animation.t = (new Date).getTime() + time;
// total number of frames (most will be dropped though)
var fnum = animation.n = time;
var fnum2 = fnum * fnum;
var fnum3 = fnum2 * fnum;
var f0_target = f0-target;
// calculating initial frame
animation.f = [
f0, // coordinate
f1, // speed
f2, // acceleration
// these magic formulae came from outer space
- ( 9 * f2 * fnum2 +
(36 * f1 -9 * f2) * fnum -
36 * f1 +
60 * f0_target
) / (fnum3 - fnum),
6 * ( 6 * f2 * fnum2 +
(32 * f1 -6 * f2) * fnum -
32 * f1 +
60 * f0_target
) / fnum / ( fnum3 + 2 * fnum2 - fnum - 2 ),
- 60 * ( f2 * fnum2 +
(6 * f1 - f2) * fnum -
6 * f1 +
12 * f0_target
) / fnum / (
fnum2*fnum2 + 5*(fnum3 + fnum2-fnum) - 6
)
];
// creating the timeout function
// and invoking it to apply the first frame instantly
// (if the animation is already running, another timeout
// is launched along with the existing, which is not a
// problem, since we are already spam with this function
// as fast as possible)
(tick = function(i) {
while (
// frames are not over
animation.n &&
// current frame is not yet reached
animation.n > animation.t - (new Date).getTime()
) {
// calculating the next frame (i+1 means i>=0)
for (i = 4; i+1;) {
animation.f[i] += animation.f[i--+1];
}
animation.n--;
}
elem[prop] = animation.f[0];
if (animation.n) {
// scheduling the next frame
(window.requestAnimationFrame || setTimeout)(tick, 1);
} else {
// stopping animation
animation.f[1] = animation.f[2] = 0;
}
})();
}
}
exports[scrollTop] = genScroll(
exports[scrollLeft] = genScroll()
);
}));