119 lines
2.9 KiB
JavaScript
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);
|
|
},
|
|
}
|
|
}
|