DEV Community

Alex Kashuba
Alex Kashuba

Posted on

React timeline animation component

timeline animation
Hi!
In this post, I'd like to introduce a react component, that was designed for animating the timelines and the scroll-dependent animations.

Firstly I try to find existing solutions, but they work with a solid timeline. In my case, I have a banner in the middle of the timeline. It gives me an idea to create a wrapper component for any part of the timeline, sticks or step circles whatever. You can see the full demo

The main idea is to change the background gradient of timeline elements smoothly, during the scroll.

const depthPx = rect.bottom - halfScreenHeight;
const depthPercent = (depthPx * 100) / rect.height;
entry.target.style.background = `linear-gradient(to top, #e5e5e5 ${depthPercent}%, #53b374 ${depthPercent}% 100%)`;
entry.target.style.transform = "translateZ(0)";
Enter fullscreen mode Exit fullscreen mode

The component uses the "render prop" pattern.

<TimelineObserver
  initialColor="#e5e5e5"
  fillColor="#53b374"
  handleObserve={(setObserver) => (
    <Timeline
      className="timeline"
      setObserver={setObserver}
    />
  )}
/>
Enter fullscreen mode Exit fullscreen mode

And we pass a ref to the setObserver function:

 const timeline1 = useRef(null);

 useEffect(() => {
    setObserver(timeline1.current);
  }, []);

<div id="timeline1" ref={timeline1} className="timeline" />
Enter fullscreen mode Exit fullscreen mode

In order to filter already filled elements and prevent further position recalculations, we use the "id" prop.

In terms of optimization, we use the "IntersectionObserver" to interact with elements only if they are in the viewport. And the requestAnimationFrame to handle the color fill animation.

  const callback = entries => {
    entries?.forEach(entry => {
      if (entry.isIntersecting) {
        setObservable({
          obs: entry,
          observableList: observablesStore.current,
          callbacks: callbacks.current,
        });
      }
    });
  };
  const observer = useRef(new IntersectionObserver(callback, options));
Enter fullscreen mode Exit fullscreen mode

You also can add a callback that fired after the element will fully cross the middle of the screen. (watch the demo)

 const someCallback3 = () => {
    setMessage3("Finish");
    fireConfetti();
  };

  useEffect(() => {
    setObserver(circle3.current, someCallback3);
  }, []);
Enter fullscreen mode Exit fullscreen mode

This is react-timeline-animation at first glance. Be free to suggest ideas or contributions, contacts in github below.
Code can be found in github.
And npm package.

Discussion (0)