Neovici/cosmoz-omnitable

View on GitHub
lib/use-tween-array.js

Summary

Maintainability
A
1 hr
Test Coverage
A
95%
import { useCallback, useEffect, useRef, useState } from '@pionjs/pion';

export const isCloseEnough = (a = 0, b = 0) => Math.abs(a - b) < 0.1,
    // eslint-disable-next-line max-lines-per-function
    useTweenArray = (target, speedFactor = 1.9) => {
        const state = useRef({
                request: undefined,
                target,
                running: false,
            }),
            [tween, setTween] = useState(target),
            animate = useCallback(() => {
                if (!state.current.running) {
                    return;
                }

                state.current.request = requestAnimationFrame(animate);

                setTween((tween) => {
                    const target = state.current.target;

                    if (target.every((t, idx) => tween[idx] === t)) {
                        state.current.running = false;
                        return tween;
                    }

                    return target.map((t, idx) =>
                        isCloseEnough(tween[idx], t)
                            ? t
                            : (tween[idx] ?? 0) +
                                    ((t ?? 0) - (tween[idx] ?? 0)) / speedFactor || 0,
                    );
                });
            }, []);

        useEffect(() => {
            state.current.request = requestAnimationFrame(animate);
            return () => cancelAnimationFrame(state.current.request);
        }, []);

        useEffect(() => {
            if (state.current.target.length === 0 && target.length > 0) {
                setTween(target);
            }

            state.current.target = target;

            if (state.current.running) return;

            state.current.running = true;
            state.current.request = requestAnimationFrame(animate);
        }, [target]);

        return tween;
    };