Improve animations

This commit is contained in:
Tom Raithel
2017-03-01 20:34:08 +01:00
parent 5f20c00bec
commit 6d4f1d0c09
5 changed files with 315 additions and 42 deletions

134
js/animation.js Normal file
View File

@@ -0,0 +1,134 @@
export const createAnimationController = (animations, component) => {
return {
animations,
start: () => {
Object.entries(animations).map(([name, animation]) => animation.run((state) => {
component.setState({
...component.state,
[name]: state,
});
}));
},
prepare: () => {
Object.entries(animations).map(([name, animation]) => animation.prepare((state) => {
component.setState({
...component.state,
[name]: state,
});
}));
}
};
}
export const createAnimation = (stateA, stateB, delay) => ({
stateA,
stateB,
delay,
});
const getAnimationState = (animation, stateName = 'stateA') => {
if (animation instanceof Array) {
return animation.map(a => getAnimationState(a, stateName));
}
return animation[stateName];
};
const getMaxTransitionTime = (transition) => {
const re = /(\d+)ms/g;
const times = [];
let matches;
while ((matches = re.exec(transition)) != null) {
times.push(parseInt(matches[1], 10));
}
return Math.max.apply(null, times);
};
const getAnimationDuration = (animation) => {
if (animation instanceof Array) {
return animation.reduce((maxDuration, a) => {
const duration = getAnimationDuration(a);
if (duration > maxDuration) {
return duration;
}
return maxDuration;
}, 0);
}
const state = animation.stateB;
const maxTransition = state.transition ? getMaxTransitionTime(state.transition) : 0;
return maxTransition + animation.delay;
};
const getMaxAnimationsDuration = (animations) => (
getAnimationDuration(Object.values(animations))
);
export const createAnimationRunner = (animations, subscriber) => {
let state = Object.entries(animations).reduce((state, [name, animation]) => ({
...state,
[name]: getAnimationState(animation),
}), {});
const animationsDuration = getMaxAnimationsDuration(animations);
const animate = (name, animation, stateName, getDelay) => {
if (animation instanceof Array) {
animation.map((a, index) => {
window.requestAnimationFrame(() => {
window.setTimeout(() => {
state = {
...state,
[name]: [
...(state[name].slice(0, index)),
a[stateName],
...(state[name].slice(index + 1, state[name].length)),
],
};
subscriber();
}, getDelay(a))
});
});
} else {
window.requestAnimationFrame(() => {
window.setTimeout(() => {
state = {
...state,
[name]: animation[stateName],
};
subscriber();
}, getDelay(animation))
});
}
}
return {
getState() {
return state;
},
run() {
Object.entries(animations).forEach(([name, animation]) => {
animate(name, animation, 'stateB', a => a.delay)
})
},
runReverse() {
Object.entries(animations).reverse().forEach(([name, animation]) => {
animate(name, animation, 'stateA', a => animationsDuration - a.delay)
})
},
awaitAnimationComplete(callback) {
window.setTimeout(callback, animationsDuration);
},
}
}
// prepare(callback) {
// callback(stateA);
// },
// run(callback) {
// window,requestAnimationFrame(() => {
// window.setTimeout(() => {
// callback(stateB);
// }, delay)
// });
// },