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:
Code used in the example
The code to create this example (AnnouncementText), is:
TYPESCRIPT
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:
TYPESCRIPT
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:
TYPESCRIPT
<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
- ???