juliangarnier / anime

JavaScript animation engine
https://animejs.com
MIT License
50.42k stars 3.68k forks source link

can you run a for each loop in the targets? or refresh where the target is pointing to with the loopComplete callback? #874

Open ccbergstrom opened 11 months ago

ccbergstrom commented 11 months ago

I've got an animation where I'm trying to cycle through an array of strings, animating each one out and the other one in at the same time with opacity and transform: translateY, and it doesn't seem like there's a way to add targets in a for each loop as you

{
  items && (
    <div id="alternating-strings-wrapper" data-animation-type={animationType}>
      <span class:list={[classes, "alternating-string current-string"]} id="alternating-string-0">{items[0]}</span>
      <span class:list={[classes, "alternating-string next-string"]} id="alternating-string-1">{items[1]}</span>
      {items.slice(2).map((item, index) => (
        <span class:list={[classes, "alternating-string"]} id={"alternating-string-"+(index+2)} aria-hidden="true">
          {item}
        </span>
      ))}
    </div>
  )
}

As you can see I've set up each string with an id based index and my plan was to remove .current-string from the visible string add it to the next string, and same for .next-string, but I don't think the targets update per loop.

import anime from 'animejs';

    anime.timeline({
      loop: 4,
      loopComplete: function() {
        let prevString = document.querySelector('.current-string');
        let currentString = document.querySelector('.next-string') || prevString?.nextElementSibling || prevString?.parentNode?.firstElementChild;
        let nextString = currentString?.nextElementSibling || currentString?.parentNode?.firstElementChild;
        currentIndex = (currentIndex + 1) % stringsDOMList.length;

        prevString?.classList.remove('current-string');
        currentString?.classList.add('current-string');
        if ( currentString?.classList.contains('next-string')) {
          currentString?.classList.remove('next-string');
        }
        nextString?.classList.add('next-string');
      }
    })
      .add({
        targets: `.current-string`,
        opacity: 0,
        delay: 2000,
      })
      .add({
        targets: `.next-string`,
        opacity: 1,
        endDelay: 2000
      })

Is there a different way to target each individual string and run through an entrance and exit animation for the string, and then trigger the next string once the last one was completed?

I found this example on Moving Letters but each target is added individually, meaning it won't function correctly if you add or remove strings without then adding or removing the targets. Or is there another way to add the targets as a node list or through a loop and animate each separately?