-
Notifications
You must be signed in to change notification settings - Fork 3
/
index.es6
146 lines (125 loc) · 5.17 KB
/
index.es6
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
export const FRAMES = 60;
import * as easings from "./easings";
import {sanitizeProperties, unsanitizeProperties, placeholdNumbers, extractNumbers, interpolateNumbers} from "./tools/number-interpolation";
import {default as mergeObj} from "./tools/merge";
//given an initial start and end state...
export var tween = (from, to) =>
//...return a function, that for any float 0<t<1...
t => Object.keys(from).reduce(
//...for all the properties(width, height, opacity) of the initial state...
(state, property) => {
//...will extract numbers from the string("12px" => 12)
var strFrom = from[property] + "";
var numbersPlaceholder = placeholdNumbers(strFrom);
var fromNumbers = extractNumbers(strFrom);
var strTo = to[property] + "";
var toNumbers = extractNumbers(strTo);
//...will compute the intermediary state of each number at t and will merge them into a CSS string again
state[property] = interpolateNumbers(numbersPlaceholder, fromNumbers.map((number, index) =>
number + (toNumbers[index] - number) * t));
return state;
}, {});
export var transition = (property, from, to) => tween({ [property]: from }, { [property]: to });
export var ensure = state =>
() => state;
export var ensureProperty = (property, value) => ensure({[property] : value});
export var reverse = (animation) =>
t => animation(1 - t);
export var linger = (t, animation) => chain({
0: animation,
[t]: ensure(animation(1))
});
export var foreshadow = (t, animation) => chain({
0: ensure(animation(0)),
[t]: animation
});
export var imposePresence = (from, to, animation) => chain({
0: ensure(animation(0)),
[from]: animation,
[to]: ensure(animation(1))
});
export var toAndFrom = animation => chain({
0: animation,
.5: reverse(animation)
});
export var repeat = (times, animation) => {
var animations = {};
for(var counter = 1; counter <= times; counter++){
animations[1 - counter/times] = animation;
}
return chain(animations);
};
export var chain = animations =>
t => {
//get the keys(starting time) of all the animations, ensure they're floats, then find all that precede t or start at t
//the animation with the max starting time of those will be current animation
var currentanimationIndex = Math.max.apply(null, Object.keys(animations).map(parseFloat).filter(time => time <= t));
var currentanimation = animations[currentanimationIndex];
var animationDuration =
/*
get the keys(starting time) of all the animations, ensure they're all floats, then find all that succeed t
(but not those that start at t, because without that condition we might get the current animation itself)
Add 1(end of the chain) in case current animation is the last one. The lowest number of those will be the t
when current animation ends, we subtract the current animation's starting t to get its duration.
*/
Math.min.apply(null, Object.keys(animations).map(parseFloat).filter(time => time > t).concat(1.0)) - currentanimationIndex;
var relativeT = (t - currentanimationIndex) / animationDuration;
return currentanimation(relativeT);
};
export function chainEvenly(){
var timings = {};
Object.keys(arguments).forEach(index => {
timings[index/arguments.length] = arguments[index];
});
return chain(timings);
}
export function merge(){
var _arguments = arguments;
return t => mergeObj.apply(null, Object.keys(_arguments).map(key => _arguments[key](t)));
}
export var prerender = (time, animation) => {
var totalFrames = time / 1000 * FRAMES;
var frames = [];
for(var frame = 0; frame <= totalFrames; frame++){
frames[frame] = animation(frame / totalFrames);
}
return t => frames[Math.round(totalFrames * t)];
};
export function stream(duration, animation, cb, onEnd){
cb(animation(0));
var start = new Date();
var doFrame = () => {
var now = new Date();
var elapsed = now - start;
var t = elapsed / duration;
cb(animation(t <= 1 ? t : 1));
if(elapsed < duration){
requestAnimationFrame(doFrame);
} else if("function" == typeof onEnd){
onEnd();
}
};
requestAnimationFrame(doFrame);
}
export function infiniteStream(duration, animation, cb){
var ended = false;
var restartLoop = function(){
stream(duration, animation, cb, restartLoop);
};
stream(duration, animation, cb, restartLoop);
return function(){
ended = true;
}
}
export function toCss(name, nrFrames, animation){
var str = `@keyframes ${name}{\n`;
for(var frame = 0; frame <= nrFrames; frame++){
var state = animation(frame/nrFrames);
var strState = Object.keys(state).map(key => `${key}:${state[key]}`).join(";");
str += `\t${frame / nrFrames * 100}%{${strState}}\n`;
}
return str + '}';
}
export var intoDom = DOMElement =>
state => Object.keys(state).forEach(property => DOMElement.style[property] = state[property]);
export {easings as easings};