Site Update in progress. Please excuse any potential mess. 😊
Menu

FadeTween

About

FadeTween is a simple component that wraps three Tweens: FadeIn, WaitTime and FadeOut. Those Tweens are called in order and repeated forever, so you can create an effect like this:

fadeTween example

Code used in the example

The code to create this example (AnnouncementText), is:

const texts = [
    "This is a test",
    "This is another test",
    "This is a third test",
    "This is a fourth test",
    "This is a fifth test",
];
export const AnnouncementText = () => {

    const [currentText, setCurrentText] = useState(texts[0]);

    const changeText = () => {
        const nextText = texts[Math.floor(Math.random() * texts.length)];
        setCurrentText(nextText);
    };

    return (
        <FadeTween waitTime={1000} fadeDuration={300} onFadeIn={null} onFadeOut={changeText}> 
            <label text={currentText}></label>
        </FadeTween>
    )
}

Steps to implement FadeTween:

1- Create a file called fade-tween.tsx

2- Copy this code:

import { Dom } from "OneJS/Dom";
import { h } from "preact";
import { useEffect } from "preact/hooks";
import { useRef } from "preact/hooks";
import { Tween, update } from "tweenjs/tween";

let tweenedOpacity = { value: 0 };

let fadeInTween: Tween<{ value: number }>;
let waitTween: Tween<{ value: number }>;
let fadeOutTween: Tween<{ value: number }>;
let currentFadeDuration = 0;
let currentWaitTime = 0;
export const FadeTween = (props: { children?: any, onFadeIn?: Function, onFadeOut?: Function, fadeDuration?: number, waitTime?: number }) => {

    const divRef = useRef<Dom>();


    const stopAllTweens = () => {
        if (fadeInTween) {
            fadeInTween.stopChainedTweens();
            fadeInTween.stop();
        }
        if (waitTween) {
            waitTween.stopChainedTweens();
            waitTween.stop();
        }
        if (fadeOutTween) {
            fadeOutTween.stopChainedTweens();
            fadeOutTween.stop();
        }

        fadeInTween = undefined;
        waitTween = undefined;
        fadeOutTween = undefined;
    }

    useEffect(() => {
        return () => {
            stopAllTweens();
        }
    }, []);

    // Fade is already running
    if (typeof fadeInTween !== "undefined") {

        // Fade duration or wait time changed. Need to restart the fade
        if (currentFadeDuration !== props.fadeDuration || currentWaitTime !== props.waitTime) {
            stopAllTweens();
        }
    }




    if (typeof fadeInTween === "undefined") {
        currentFadeDuration = props.fadeDuration;
        currentWaitTime = props.waitTime;

        // Fade in tween (Will call onFadeIn when complete & updates opacity style onUpdate)
        fadeInTween = new Tween(tweenedOpacity).to({ value: 1 }, props.fadeDuration ? props.fadeDuration : 700)
            .onUpdate(() => {
                divRef.current.style.opacity = tweenedOpacity.value.toString();
            })
            .onComplete(() => {
                if (props.onFadeIn) {
                    props.onFadeIn();
                }
            });

        // Wait tween (Just a delay)
        waitTween = new Tween(tweenedOpacity).delay(props.waitTime ? props.waitTime : 0);

        // Fade out tween (Will call onFadeOut when complete & updates opacity style onUpdate)
        fadeOutTween = new Tween(tweenedOpacity).to({ value: 0 }, props.fadeDuration ? props.fadeDuration : 700)
            .onUpdate(() => {
                divRef.current.style.opacity = tweenedOpacity.value.toString();
            })
            .onComplete(() => {
                if (props.onFadeOut) {
                    props.onFadeOut();
                }
            });


        if (currentWaitTime > 0) {
            fadeInTween.chain(waitTween.chain(fadeOutTween.chain(fadeInTween))).start();
        } else {
            fadeInTween.chain(fadeOutTween.chain(fadeInTween)).start();
        }
    }

    return (
        <div ref={divRef}>
            {props.children as any}
        </div>
    )
}

function animate(time) {
    requestAnimationFrame(animate)
    update(time)
}
requestAnimationFrame(animate);

3- Use it like this:

<FadeTween>
    // any children here
</FadeTween>

Where:

  • waitTime: Time between fadeIn and fadeOut effect
  • fadeDuration: Time that takes to animate the fadeIn and fadeOut animation
  • onFadeIn: A function that will be called when the children are completly visible
  • onFadeOut: A function that will be called when the children are completly invisible

Ideas for the future:

  • Implement a prop to set the default state (start fadeIn or fadeOut)
  • Implement a prop to decide if the fadeIn and out should be infinite
  • ???