Files
TechRadarAJR/js/animation.js
2017-03-01 21:40:59 +01:00

119 lines
2.9 KiB
JavaScript

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) => {
if (animation instanceof Array) {
animation.map((a, index) => {
window.requestAnimationFrame(() => {
window.setTimeout(() => {
state = {
...state,
[name]: [
...(state[name].slice(0, index)),
a.stateB,
...(state[name].slice(index + 1, state[name].length)),
],
};
subscriber();
}, a.delay);
});
});
} else {
window.requestAnimationFrame(() => {
window.setTimeout(() => {
state = {
...state,
[name]: animation.stateB,
};
subscriber();
}, animation.delay);
});
}
}
return {
getState() {
return state;
},
run() {
Object.entries(animations).forEach(([name, animation]) => {
animate(name, animation)
});
},
awaitAnimationComplete(callback) {
window.setTimeout(callback, animationsDuration);
},
}
}