Skip to content

Instantly share code, notes, and snippets.

@ShayDavidson
Created October 28, 2019 08:59
Show Gist options
  • Save ShayDavidson/da2fdc93d9512eef3e77df1e505d479a to your computer and use it in GitHub Desktop.
Save ShayDavidson/da2fdc93d9512eef3e77df1e505d479a to your computer and use it in GitHub Desktop.
UseAnimation hook
import { useMemo } from 'react';
import { easing } from 'ts-easing';
import { useTween } from 'react-use';
import { clampedInverseLerp, lerp } from '../utils/math';
export type EasingName = keyof typeof easing;
export interface Animation {
from: number;
to: number;
duration: number;
delay: number;
easing: EasingName;
}
export interface PropertyAnimation {
property: string;
animations: Animation[];
}
export interface PropertiesAnimationsValues {
[prop: string]: number;
}
export interface AnimationOptions {
reversed?: boolean;
}
export default function useAnimation(
propertyAnimations: PropertyAnimation[],
{ reversed }: AnimationOptions = {}
): PropertiesAnimationsValues {
const totalDuration = useMemo(
() =>
Math.max(
...propertyAnimations.flatMap(propertyAnimation =>
propertyAnimation.animations.map(animation => animation.delay + animation.duration)
)
),
[propertyAnimations]
);
let t = useTween('linear', totalDuration);
if (reversed) t = 1 - t;
return propertyAnimations.reduce<PropertiesAnimationsValues>((result, propertyAnimation) => {
const animationsTimes = propertyAnimation.animations.map(animation => {
const fromT = totalDuration === 0 ? 0 : animation.delay / totalDuration;
const toT = totalDuration === 0 ? 0 : (animation.delay + animation.duration) / totalDuration;
const relativeT = clampedInverseLerp(fromT, toT, t);
return { fromT, toT, relativeT, animation };
});
// this piece of code relies on the animations to be ordered by their time.
let matchingAnimationTime = animationsTimes[0];
for (let i = 0; i < animationsTimes.length; i++) {
const { toT } = animationsTimes[i];
matchingAnimationTime = animationsTimes[i];
if (t <= toT) {
// matching the animation time frame (or before it), no longer need to look.
break;
}
}
const { animation: matchingAnimation, relativeT } = matchingAnimationTime;
const value = lerp(matchingAnimation.from, matchingAnimation.to, easing[matchingAnimation.easing](relativeT));
return { ...result, [propertyAnimation.property]: value };
}, {});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment