├── .gitignore
├── LICENSE
├── README.md
├── examples
├── index.js
└── package.json
├── lib
└── rx.easing.js
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | lib-cov
2 | *.seed
3 | *.log
4 | *.csv
5 | *.dat
6 | *.out
7 | *.pid
8 | *.gz
9 |
10 | pids
11 | logs
12 | results
13 |
14 | npm-debug.log
15 | node_modules
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013 Paul Taylor
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | rx-js-easing
2 | ============
3 |
4 | Robert Penner's easing functions as Observables.
5 |
6 | ```javascript
7 |
8 | // All easing functions take a begin value, end value, and duration (in ms).
9 | // A few take extra arguments, which I've documented
10 |
11 | Observable.backIn = function(begin, end, duration, overshoot) {};
12 | Observable.backOut = function(begin, end, duration, overshoot) {};
13 | Observable.backInOut = function(begin, end, duration, overshoot) {};
14 | Observable.bounceIn = function(begin, end, duration) {};
15 | Observable.bounceOut = function(begin, end, duration) {};
16 | Observable.bounceInOut = function(begin, end, duration) {};
17 | Observable.circIn = function(begin, end, duration) {};
18 | Observable.circOut = function(begin, end, duration) {};
19 | Observable.circInOut = function(begin, end, duration) {};
20 | Observable.cubicIn = function(begin, end, duration) {};
21 | Observable.cubicOut = function(begin, end, duration) {};
22 | Observable.cubicInOut = function(begin, end, duration) {};
23 | Observable.elasticOut = function(begin, end, duration, amplitude, period) {};
24 | Observable.elasticIn = function(begin, end, duration, amplitude, period) {};
25 | Observable.elasticInOut = function(begin, end, duration, amplitude, period) {};
26 | Observable.expoIn = function(begin, end, duration) {};
27 | Observable.expoOut = function(begin, end, duration) {};
28 | Observable.expoInOut = function(begin, end, duration) {};
29 | Observable.linear = function(begin, end, duration) {};
30 | Observable.quadIn = function(begin, end, duration) {};
31 | Observable.quadOut = function(begin, end, duration) {};
32 | Observable.quadInOut = function(begin, end, duration) {};
33 | Observable.quartIn = function(begin, end, duration) {};
34 | Observable.quartOut = function(begin, end, duration) {};
35 | Observable.quartInOut = function(begin, end, duration) {};
36 | Observable.quintIn = function(begin, end, duration) {};
37 | Observable.quintOut = function(begin, end, duration) {};
38 | Observable.quintInOut = function(begin, end, duration) {};
39 | Observable.sineIn = function(begin, end, duration) {};
40 | Observable.sineOut = function(begin, end, duration) {};
41 | Observable.sineInOut = function(begin, end, duration) {};
42 | Observable.circleIn = function(begin, end, duration) {};
43 | Observable.circleOut = function(begin, end, duration) {};
44 | Observable.circleInOut = function(begin, end, duration) {};
45 | Observable.linearNone = function(begin, end, duration) {};
46 | Observable.linearIn = function(begin, end, duration) {};
47 | Observable.linearOut = function(begin, end, duration) {};
48 | Observable.linearInOut = function(begin, end, duration) {};
49 |
50 | ```
51 |
--------------------------------------------------------------------------------
/examples/index.js:
--------------------------------------------------------------------------------
1 | var $ = require("jquery"),
2 | transform_property = require("transform-property"),
3 | translate = function(el, x, y, z) {
4 | el.style[transform_property] = "translate3d(" +
5 | (x || 0) + "px, " +
6 | (y || 0) + "px, " +
7 | (z || 0) + "px)";
8 | return el;
9 | },
10 | Rx = require("rx") &&
11 | require("rx-dom") &&
12 | require("rx-jquery") &&
13 | require("rxjs-gestures") &&
14 | require("../lib/rx.easing"),
15 |
16 | animationTime = 650 /*ms*/;
17 |
18 | $(window)
19 | .loadAsObservable()
20 | .map(function() {
21 |
22 | $("body").append("
tap anywhere to animate the box
");
23 |
24 | return $("").css({
25 | "width": "200px",
26 | "height": "200px",
27 | "border": "1px solid #333",
28 | "border-radius": "5px",
29 | "position": "absolute",
30 | "top": "50%",
31 | "left": "50%",
32 | "margin-top": "-100px",
33 | "margin-left": "-100px"
34 | }).appendTo("body");
35 | })
36 | .flatMap(function(box) {
37 | return $(window)
38 | .tapAsObservable()
39 | .repeat()
40 | .flatMapLatest(function(tap) {
41 |
42 | var boxW = box.width(),
43 | boxH = box.height(),
44 | offsetX = (($(window).width() - boxW) * 0.5),
45 | offsetY = (($(window).height() - boxH) * 0.5),
46 | coords = box.offset(),
47 | startX = coords.left - offsetX,
48 | startY = coords.top - offsetY,
49 | endX = tap.global.x - offsetX - (boxW * 0.5),
50 | endY = tap.global.y - offsetY - (boxH * 0.5);
51 |
52 | // Animate the box coordinates in parallel:
53 | return Rx.Observable.zip(
54 | Rx.Observable.quadOut(startX, endX, animationTime),
55 | Rx.Observable.quadOut(startY, endY, animationTime),
56 | translate.bind(null, box[0])
57 | );
58 |
59 | // Animate the box coordinates in series:
60 | return Rx.Observable.concat(
61 | Rx.Observable
62 | .quadOut(startX, endX, animationTime * 0.5)
63 | .map(function(x) { return { x: x } }),
64 | Rx.Observable
65 | .quadOut(startY, endY, animationTime * 0.5)
66 | .map(function(y) { return { y: y }; })
67 | ).scan({x: startX, y: startY}, function(coords, newCoords) {
68 | for(var prop in newCoords) {
69 | coords[prop] = newCoords[prop];
70 | }
71 | translate(box[0], coords.x, coords.y);
72 | return coords;
73 | });
74 | });
75 | })
76 | .publish().connect();
77 |
--------------------------------------------------------------------------------
/examples/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rxjs-easing-examples",
3 | "version": "1.0.0",
4 | "description": "Examples that use the rxjs-easing Observables.",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "start": "beefy index.js --debug=false"
9 | },
10 | "keywords": [
11 | "RxJS",
12 | "Easing",
13 | "Streams",
14 | "Observables"
15 | ],
16 | "author": "Paul Taylor ",
17 | "license": "MIT",
18 | "dependencies": {
19 | "beefy": "^2.1.5",
20 | "browserify": "^9.0.8",
21 | "jquery": "^2.1.3",
22 | "rx": "^2.5.2",
23 | "rx-dom": "^5.0.3",
24 | "rx-jquery": "^1.1.7",
25 | "rxjs-gestures": "^0.1.0",
26 | "transform-property": "0.0.1"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/lib/rx.easing.js:
--------------------------------------------------------------------------------
1 | var Rx = require('rx');
2 |
3 | var Observable = Rx.Observable;
4 | var observableProto = Rx.Observable.prototype;
5 |
6 | var frame_rate = 30;
7 | var interval_len = 1000/frame_rate;
8 |
9 | var timer = Observable
10 | .timer(0, interval_len, Rx.Scheduler.requestAnimationFrame || Rx.Scheduler.timeout)
11 | .select(function(i) {
12 | return i * interval_len;
13 | });
14 |
15 | Observable.backIn = make_ease_observable(curry_ease_time(backIn));
16 | Observable.backOut = make_ease_observable(curry_ease_time(backOut));
17 | Observable.backInOut = make_ease_observable(curry_ease_time(backInOut));
18 | Observable.bounceIn = make_ease_observable(curry_ease_time(bounceIn));
19 | Observable.bounceOut = make_ease_observable(curry_ease_time(bounceOut));
20 | Observable.bounceInOut = make_ease_observable(curry_ease_time(bounceInOut));
21 | Observable.circIn = make_ease_observable(curry_ease_time(circIn));
22 | Observable.circOut = make_ease_observable(curry_ease_time(circOut));
23 | Observable.circInOut = make_ease_observable(curry_ease_time(circInOut));
24 | Observable.cubicIn = make_ease_observable(curry_ease_time(cubicIn));
25 | Observable.cubicOut = make_ease_observable(curry_ease_time(cubicOut));
26 | Observable.cubicInOut = make_ease_observable(curry_ease_time(cubicInOut));
27 | Observable.elasticOut = make_ease_observable(curry_ease_time(elasticOut));
28 | Observable.elasticIn = make_ease_observable(curry_ease_time(elasticIn));
29 | Observable.elasticInOut = make_ease_observable(curry_ease_time(elasticInOut));
30 | Observable.expoIn = make_ease_observable(curry_ease_time(expoIn));
31 | Observable.expoOut = make_ease_observable(curry_ease_time(expoOut));
32 | Observable.expoInOut = make_ease_observable(curry_ease_time(expoInOut));
33 | Observable.linear = make_ease_observable(curry_ease_time(linear));
34 | Observable.quadIn = make_ease_observable(curry_ease_time(quadIn));
35 | Observable.quadOut = make_ease_observable(curry_ease_time(quadOut));
36 | Observable.quadInOut = make_ease_observable(curry_ease_time(quadInOut));
37 | Observable.quartIn = make_ease_observable(curry_ease_time(quartIn));
38 | Observable.quartOut = make_ease_observable(curry_ease_time(quartOut));
39 | Observable.quartInOut = make_ease_observable(curry_ease_time(quartInOut));
40 | Observable.quintIn = make_ease_observable(curry_ease_time(quintIn));
41 | Observable.quintOut = make_ease_observable(curry_ease_time(quintOut));
42 | Observable.quintInOut = make_ease_observable(curry_ease_time(quintInOut));
43 | Observable.sineIn = make_ease_observable(curry_ease_time(sineIn));
44 | Observable.sineOut = make_ease_observable(curry_ease_time(sineOut));
45 | Observable.sineInOut = make_ease_observable(curry_ease_time(sineInOut));
46 | Observable.circleIn = Observable.circIn;
47 | Observable.circleOut = Observable.circOut;
48 | Observable.circleInOut = Observable.circInOut;
49 | Observable.linearNone = Observable.linear;
50 | Observable.linearIn = Observable.linear;
51 | Observable.linearOut = Observable.linear;
52 | Observable.linearInOut = Observable.linear;
53 |
54 | module.exports = Rx;
55 |
56 | function make_ease_observable(easing_func) {
57 |
58 | return function(begin, end, duration) {
59 |
60 | var args = Array.prototype.slice.call(arguments);
61 |
62 | // The easing functions use the difference
63 | // between the start and end values.
64 | args[1] = end - begin;
65 |
66 | return timer
67 | .takeWithTime(duration)
68 | .select(easing_func.apply(null, args))
69 | .concat(Observable.returnValue(end));
70 | }
71 | }
72 |
73 | function curry_ease_time(easing_func) {
74 |
75 | return function() {
76 |
77 | var args = Array.prototype.slice.call(arguments);
78 |
79 | return function(time) {
80 | return easing_func.apply(null, [time].concat(args));
81 | }
82 | }
83 | }
84 |
85 | // Shamlessly pulled from Jim Jeffers's Easie: https://github.com/jimjeffers/Easie
86 | // who in turn pulled it from Robert Penner's easing equations: http://robertpenner.com/easing/
87 | // Thanks you guys <3.
88 |
89 | function backIn(time, begin, change, duration, overshoot) {
90 | if (overshoot == null) overshoot = 1.70158;
91 |
92 | return change * (time /= duration) * time * ((overshoot + 1) * time - overshoot) + begin;
93 | }
94 |
95 | function backOut(time, begin, change, duration, overshoot) {
96 | if (overshoot == null) overshoot = 1.70158;
97 |
98 | return change * ((time = time / duration - 1) * time * ((overshoot + 1) * time + overshoot) + 1) + begin;
99 | }
100 |
101 | function backInOut(time, begin, change, duration, overshoot) {
102 | if (overshoot == null) overshoot = 1.70158;
103 |
104 | if ((time = time / (duration / 2)) < 1) {
105 | return change / 2 * (time * time * (((overshoot *= 1.525) + 1) * time - overshoot)) + begin;
106 | } else {
107 | return change / 2 * ((time -= 2) * time * (((overshoot *= 1.525) + 1) * time + overshoot) + 2) + begin;
108 | }
109 | }
110 |
111 | function bounceOut(time, begin, change, duration) {
112 | if ((time /= duration) < 1 / 2.75) {
113 | return change * (7.5625 * time * time) + begin;
114 | } else if (time < 2 / 2.75) {
115 | return change * (7.5625 * (time -= 1.5 / 2.75) * time + 0.75) + begin;
116 | } else if (time < 2.5 / 2.75) {
117 | return change * (7.5625 * (time -= 2.25 / 2.75) * time + 0.9375) + begin;
118 | } else {
119 | return change * (7.5625 * (time -= 2.625 / 2.75) * time + 0.984375) + begin;
120 | }
121 | }
122 |
123 | function bounceIn(time, begin, change, duration) {
124 | return change - bounceOut(duration - time, 0, change, duration) + begin;
125 | }
126 |
127 | function bounceInOut(time, begin, change, duration) {
128 | if (time < duration / 2) {
129 | return bounceIn(time * 2, 0, change, duration) * 0.5 + begin;
130 | } else {
131 | return bounceOut(time * 2 - duration, 0, change, duration) * 0.5 + change * 0.5 + begin;
132 | }
133 | }
134 |
135 | function circIn(time, begin, change, duration) {
136 | return -change * (Math.sqrt(1 - (time = time / duration) * time) - 1) + begin;
137 | }
138 |
139 | function circOut(time, begin, change, duration) {
140 | return change * Math.sqrt(1 - (time = time / duration - 1) * time) + begin;
141 | }
142 |
143 | function circInOut(time, begin, change, duration) {
144 | if ((time = time / (duration / 2)) < 1) {
145 | return -change / 2 * (Math.sqrt(1 - time * time) - 1) + begin;
146 | } else {
147 | return change / 2 * (Math.sqrt(1 - (time -= 2) * time) + 1) + begin;
148 | }
149 | }
150 |
151 | function cubicIn(time, begin, change, duration) {
152 | return change * (time /= duration) * time * time + begin;
153 | }
154 |
155 | function cubicOut(time, begin, change, duration) {
156 | return change * ((time = time / duration - 1) * time * time + 1) + begin;
157 | }
158 |
159 | function cubicInOut(time, begin, change, duration) {
160 | if ((time = time / (duration / 2)) < 1) {
161 | return change / 2 * time * time * time + begin;
162 | } else {
163 | return change / 2 * ((time -= 2) * time * time + 2) + begin;
164 | }
165 | }
166 |
167 | function elasticOut(time, begin, change, duration, amplitude, period) {
168 | var overshoot;
169 | if (amplitude == null) {
170 | amplitude = null;
171 | }
172 | if (period == null) {
173 | period = null;
174 | }
175 | if (time === 0) {
176 | return begin;
177 | } else if ((time = time / duration) === 1) {
178 | return begin + change;
179 | } else {
180 | if (!(period != null)) {
181 | period = duration * 0.3;
182 | }
183 | if (!(amplitude != null) || amplitude < Math.abs(change)) {
184 | amplitude = change;
185 | overshoot = period / 4;
186 | } else {
187 | overshoot = period / (2 * Math.PI) * Math.asin(change / amplitude);
188 | }
189 | return (amplitude * Math.pow(2, -10 * time)) * Math.sin((time * duration - overshoot) * (2 * Math.PI) / period) + change + begin;
190 | }
191 | }
192 |
193 | function elasticIn(time, begin, change, duration, amplitude, period) {
194 | var overshoot;
195 | if (amplitude == null) {
196 | amplitude = null;
197 | }
198 | if (period == null) {
199 | period = null;
200 | }
201 | if (time === 0) {
202 | return begin;
203 | } else if ((time = time / duration) === 1) {
204 | return begin + change;
205 | } else {
206 | if (!(period != null)) {
207 | period = duration * 0.3;
208 | }
209 | if (!(amplitude != null) || amplitude < Math.abs(change)) {
210 | amplitude = change;
211 | overshoot = period / 4;
212 | } else {
213 | overshoot = period / (2 * Math.PI) * Math.asin(change / amplitude);
214 | }
215 | time -= 1;
216 | return -(amplitude * Math.pow(2, 10 * time)) * Math.sin((time * duration - overshoot) * (2 * Math.PI) / period) + begin;
217 | }
218 | }
219 |
220 | function elasticInOut(time, begin, change, duration, amplitude, period) {
221 | var overshoot;
222 | if (amplitude == null) {
223 | amplitude = null;
224 | }
225 | if (period == null) {
226 | period = null;
227 | }
228 | if (time === 0) {
229 | return begin;
230 | } else if ((time = time / (duration / 2)) === 2) {
231 | return begin + change;
232 | } else {
233 | if (!(period != null)) {
234 | period = duration * (0.3 * 1.5);
235 | }
236 | if (!(amplitude != null) || amplitude < Math.abs(change)) {
237 | amplitude = change;
238 | overshoot = period / 4;
239 | } else {
240 | overshoot = period / (2 * Math.PI) * Math.asin(change / amplitude);
241 | }
242 | if (time < 1) {
243 | return -0.5 * (amplitude * Math.pow(2, 10 * (time -= 1))) * Math.sin((time * duration - overshoot) * ((2 * Math.PI) / period)) + begin;
244 | } else {
245 | return amplitude * Math.pow(2, -10 * (time -= 1)) * Math.sin((time * duration - overshoot) * (2 * Math.PI) / period) + change + begin;
246 | }
247 | }
248 | }
249 |
250 | function expoIn(time, begin, change, duration) {
251 | if (time === 0) {
252 | return begin;
253 | }
254 | return change * Math.pow(2, 10 * (time / duration - 1)) + begin;
255 | }
256 |
257 |
258 | function expoOut(time, begin, change, duration) {
259 | if (time === duration) {
260 | return begin + change;
261 | }
262 | return change * (-Math.pow(2, -10 * time / duration) + 1) + begin;
263 | }
264 |
265 | function expoInOut(time, begin, change, duration) {
266 | if (time === 0) {
267 | return begin;
268 | } else if (time === duration) {
269 | return begin + change;
270 | } else if ((time = time / (duration / 2)) < 1) {
271 | return change / 2 * Math.pow(2, 10 * (time - 1)) + begin;
272 | } else {
273 | return change / 2 * (-Math.pow(2, -10 * (time - 1)) + 2) + begin;
274 | }
275 | }
276 |
277 | function linear(time, begin, change, duration) {
278 | return change * time / duration + begin;
279 | }
280 |
281 | function quadIn(time, begin, change, duration) {
282 | return change * (time = time / duration) * time + begin;
283 | }
284 |
285 | function quadOut(time, begin, change, duration) {
286 | return -change * (time = time / duration) * (time - 2) + begin;
287 | }
288 |
289 | function quadInOut(time, begin, change, duration) {
290 | if ((time = time / (duration / 2)) < 1) {
291 | return change / 2 * time * time + begin;
292 | } else {
293 | return -change / 2 * ((time -= 1) * (time - 2) - 1) + begin;
294 | }
295 | }
296 |
297 | function quartIn(time, begin, change, duration) {
298 | return change * (time = time / duration) * time * time * time + begin;
299 | }
300 |
301 | function quartOut(time, begin, change, duration) {
302 | return -change * ((time = time / duration - 1) * time * time * time - 1) + begin;
303 | }
304 |
305 | function quartInOut(time, begin, change, duration) {
306 | if ((time = time / (duration / 2)) < 1) {
307 | return change / 2 * time * time * time * time + begin;
308 | } else {
309 | return -change / 2 * ((time -= 2) * time * time * time - 2) + begin;
310 | }
311 | }
312 |
313 | function quintIn(time, begin, change, duration) {
314 | return change * (time = time / duration) * time * time * time * time + begin;
315 | }
316 |
317 | function quintOut(time, begin, change, duration) {
318 | return change * ((time = time / duration - 1) * time * time * time * time + 1) + begin;
319 | }
320 |
321 | function quintInOut(time, begin, change, duration) {
322 | if ((time = time / (duration / 2)) < 1) {
323 | return change / 2 * time * time * time * time * time + begin;
324 | } else {
325 | return change / 2 * ((time -= 2) * time * time * time * time + 2) + begin;
326 | }
327 | }
328 |
329 | function sineIn(time, begin, change, duration) {
330 | return -change * Math.cos(time / duration * (Math.PI / 2)) + change + begin;
331 | }
332 |
333 | function sineOut(time, begin, change, duration) {
334 | return change * Math.sin(time / duration * (Math.PI / 2)) + begin;
335 | }
336 |
337 | function sineInOut(time, begin, change, duration) {
338 | return -change / 2 * (Math.cos(Math.PI * time / duration) - 1) + begin;
339 | }
340 |
341 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rxjs-easing",
3 | "version": "0.0.5",
4 | "description": "Robert Penner's easing functions as Observables.",
5 | "main": "lib/rx.easing.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git://github.com/trxcllnt/rx-js-easing.git"
12 | },
13 | "keywords": [
14 | "rx",
15 | "rxjs",
16 | "easing"
17 | ],
18 | "dependencies": {
19 | "rx": "*",
20 | "rx-dom": "*"
21 | },
22 | "author": "Paul Taylor ",
23 | "license": "MIT",
24 | "bugs": {
25 | "url": "https://github.com/trxcllnt/rxjs-easing/issues"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------