Home > Back-end >  How to know programmatically which is the last object that has the animation
How to know programmatically which is the last object that has the animation

Time:02-05

Is there a way for me to know programmatically on which object the CSS animation applies last

For example,

.r1 {
     animation-name: move1;
     animation-delay: 2.5s;
     animation-duration: 1s;
     animation-iteration-count: 1;
     animation-timing-function: ease-in;
     animation-direction: normal;
     animation-fill-mode: forwards;
}
 .c1 {
     animation-name: blink;
     animation-delay: 0.5s;
     animation-duration: 1s;
     animation-iteration-count: 2;
     animation-timing-function: ease-in;
     animation-direction: normal;
     animation-fill-mode: forwards;
}
 /*.text1 {
     animation-name: scl;
     animation-delay: 5.5s;
     animation-duration: 1s;
     animation-iteration-count: 2;
     animation-timing-function: ease-in;
     animation-direction: normal;
     animation-fill-mode: forwards;
}*/
 .r2 {
     transform-origin: center;
     transform-box: fill-box;
     animation-name: gr;
     animation-delay: 3.5s;
     animation-duration: 2s;
     animation-iteration-count: 1;
     animation-timing-function: ease-in;
     animation-direction: normal;
     animation-fill-mode: forwards;
}
 .r3 {
     animation-name: move2;
     animation-delay: 7.5s;
     animation-duration: 1s;
     animation-iteration-count: 1;
     animation-timing-function: ease-in;
     animation-direction: normal;
     animation-fill-mode: forwards;
}
 @keyframes move1 {
     to {
         transform: translateX(200px);
    }
}
 @keyframes blink {
     from {
         opacity: 0;
    }
     to {
         opacity: 1;
    }
}
 @keyframes gr {
     from {
         transform: rotate(0deg);
    }
     to {
         transform: rotate(359deg);
    }
}
 @keyframes scl {
     to {
         transform: scale(1.1);
    }
}  
 @keyframes move2 {
     to {
         transform: translateY(400px);
    }
}  
        }
  <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
  <rect id="r1"  x="10" y="20" width="100" height="100" fill="red" />
  <rect id="r2"  x="10" y="130" width="100" height="100" fill="green" />
  <rect id="r3"  x="10" y="240" width="100" height="100" fill="blue" />

  <circle id="c1"  cx="50" cy="400" r="40" fill="orange" />
  <text  id="text1" x="80" y="500" font-size="30" fill="red">I love SVG!</text>
</svg>

In this, I have 5 elements and I am applying animation on 4 of them and r3 is the last element on which the animation applies. Is there a way I can detect the animation-delay animation-duration for r3- the last element on which the animation applies with javascript.

CodePudding user response:

The Web Animations API can inspect animations.

document.getAnimations() returns all animations found in the document. Each of them has an effect property, and in your case, they are all of the type KeyframeEffect.

  • animation.animationName returns the animation name as stated in the CSS @keyframes declaration.
  • animation.effect.target returns the element targeted by the animation.
  • animation.effect.getComputedTiming().endTime returns the time the animation ends.

From there you can compare and filter the information you need.

document.getAnimations().forEach(animation => {
    console.log(
        animation.animationName,
        animation.effect.target,
        animation.effect.getComputedTiming().endTime
    );
});
.r1 {
     animation-name: move1;
     animation-delay: 2.5s;
     animation-duration: 1s;
     animation-iteration-count: 1;
     animation-timing-function: ease-in;
     animation-direction: normal;
     animation-fill-mode: forwards;
}
 .c1 {
     animation-name: blink;
     animation-delay: 0.5s;
     animation-duration: 1s;
     animation-iteration-count: 2;
     animation-timing-function: ease-in;
     animation-direction: normal;
     animation-fill-mode: forwards;
}
 /*.text1 {
     animation-name: scl;
     animation-delay: 5.5s;
     animation-duration: 1s;
     animation-iteration-count: 2;
     animation-timing-function: ease-in;
     animation-direction: normal;
     animation-fill-mode: forwards;
}*/
 .r2 {
     transform-origin: center;
     transform-box: fill-box;
     animation-name: gr;
     animation-delay: 3.5s;
     animation-duration: 2s;
     animation-iteration-count: 1;
     animation-timing-function: ease-in;
     animation-direction: normal;
     animation-fill-mode: forwards;
}
 .r3 {
     animation-name: move2;
     animation-delay: 7.5s;
     animation-duration: 1s;
     animation-iteration-count: 1;
     animation-timing-function: ease-in;
     animation-direction: normal;
     animation-fill-mode: forwards;
}
 @keyframes move1 {
     to {
         transform: translateX(200px);
    }
}
 @keyframes blink {
     from {
         opacity: 0;
    }
     to {
         opacity: 1;
    }
}
 @keyframes gr {
     from {
         transform: rotate(0deg);
    }
     to {
         transform: rotate(359deg);
    }
}
 @keyframes scl {
     to {
         transform: scale(1.1);
    }
}  
 @keyframes move2 {
     to {
         transform: translateY(400px);
    }
}
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
  <rect id="r1"  x="10" y="20" width="100" height="100" fill="red" />
  <rect id="r2"  x="10" y="130" width="100" height="100" fill="green" />
  <rect id="r3"  x="10" y="240" width="100" height="100" fill="blue" />

  <circle id="c1"  cx="50" cy="400" r="40" fill="orange" />
  <text  id="text1" x="80" y="500" font-size="30" fill="red">I love SVG!</text>
</svg>

Edit: I don't understand why this snippet doesn't work. The same in a Codepen does what it is supposed to.

CodePudding user response:

You can try to achieve this using animationend like so :-

const animatedElements = [];
const noOfElementsToAnimate = 4;
const svgLayer = document.querySelector('#Layer_1');

const onAnimationEnd = (e) => {
  animatedElements.push(e.target.id);
  if (animatedElements.length === noOfElementsToAnimate) {
    svgLayer.removeEventListener('animationend', onAnimationEnd);
    console.log(animatedElements[animatedElements.length - 1])
  }
}

svgLayer.addEventListener('animationend', onAnimationEnd);
.r1 {
  animation-name: move1;
  animation-delay: 2.5s;
  animation-duration: 1s;
  animation-iteration-count: 1;
  animation-timing-function: ease-in;
  animation-direction: normal;
  animation-fill-mode: forwards;
}

.c1 {
  animation-name: blink;
  animation-delay: 0.5s;
  animation-duration: 1s;
  animation-iteration-count: 2;
  animation-timing-function: ease-in;
  animation-direction: normal;
  animation-fill-mode: forwards;
}


/*.text1 {
     animation-name: scl;
     animation-delay: 5.5s;
     animation-duration: 1s;
     animation-iteration-count: 2;
     animation-timing-function: ease-in;
     animation-direction: normal;
     animation-fill-mode: forwards;
}*/

.r2 {
  transform-origin: center;
  transform-box: fill-box;
  animation-name: gr;
  animation-delay: 3.5s;
  animation-duration: 2s;
  animation-iteration-count: 1;
  animation-timing-function: ease-in;
  animation-direction: normal;
  animation-fill-mode: forwards;
}

.r3 {
  animation-name: move2;
  animation-delay: 7.5s;
  animation-duration: 1s;
  animation-iteration-count: 1;
  animation-timing-function: ease-in;
  animation-direction: normal;
  animation-fill-mode: forwards;
}

@keyframes move1 {
  to {
    transform: translateX(200px);
  }
}

@keyframes blink {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes gr {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(359deg);
  }
}

@keyframes scl {
  to {
    transform: scale(1.1);
  }
}

@keyframes move2 {
  to {
    transform: translateY(400px);
  }
}


}
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
  <rect id="r1"  x="10" y="20" width="100" height="100" fill="red" />
  <rect id="r2"  x="10" y="130" width="100" height="100" fill="green" />
  <rect id="r3"  x="10" y="240" width="100" height="100" fill="blue" />

  <circle id="c1"  cx="50" cy="400" r="40" fill="orange" />
  <text  id="text1" x="80" y="500" font-size="30" fill="red">I love SVG!</text>
</svg>

Explanation: - Here I attached the event listener for animationend event to the parent element i.e. Layer_1 svg. Whenever the animation will end for its children elements, I push the id of that element to an array and compare it with an existing no which denote the no of animated elements that are in the DOM (can use a unique class to fetch these dynamically as well). When the animatedElements and noOfElementsToAnimate are equal, I remove the listener and log/use the last value of animatedElements array.

Alternatively, you can also ditch the array and just use one variable to keep track of last animated element, say, lastAnimatedElement and decrement noOfElementsToAnimate and log the lastAnimatedElement when noOfElementsToAnimate is 0.

CodePudding user response:

I came up with this which calculates the Delay (Duration*Iteration-Count) for each of the svg elements and at the end returns the max value of that expression, which would be the total duration of the last element on which the animation ran. The last element with the animation logically will have the longest Delay (Duration*Iteration-Count) which I need to pass on as an animation-delay for my next element for animation.

var _layer1 = document.querySelectorAll('svg > *');
var _max = -1;
for (const el of _layer1) {
    var __del = getComputedStyle(el).animationDelay;
    var __del = __del.split(',');
    var __delLast = parseFloat(__del[__del.length - 1]);
    var __duration = getComputedStyle(el).animationDuration;
    var __duration = __duration.split(',');
    var __durationLast = parseFloat(__duration[__del.length - 1]);
    var __iterationCount = getComputedStyle(el).animationIterationCount;
    var __iterationCount = __iterationCount.split(',');
    var __iterationCountLast = parseFloat(__iterationCount[__iterationCount.length - 1]);

    function alternate(a, b) {
        if (isNaN(a)) {
            return b
        } else {
            return a
        }
    };
    var modified = alternate(__iterationCountLast, __durationLast);
    var _expression = __delLast   (__durationLast * modified); //Delay (Duration*Iteration-Count)
    _max = Math.max(_max, _expression);
};
.r1 {
     animation-name: move1;
     animation-delay: 2.5s;
     animation-duration: 1s;
     animation-iteration-count: 1;
     animation-timing-function: ease-in;
     animation-direction: normal;
     animation-fill-mode: forwards;
}
 .c1 {
     animation-name: blink;
     animation-delay: 0.5s;
     animation-duration: 1s;
     animation-iteration-count: 2;
     animation-timing-function: ease-in;
     animation-direction: normal;
     animation-fill-mode: forwards;
}
 /*.text1 {
     animation-name: scl;
     animation-delay: 5.5s;
     animation-duration: 1s;
     animation-iteration-count: 2;
     animation-timing-function: ease-in;
     animation-direction: normal;
     animation-fill-mode: forwards;
}*/
 .r2 {
     transform-origin: center;
     transform-box: fill-box;
     animation-name: gr;
     animation-delay: 3.5s;
     animation-duration: 2s;
     animation-iteration-count: 1;
     animation-timing-function: ease-in;
     animation-direction: normal;
     animation-fill-mode: forwards;
}
 .r3 {
     animation-name: move2;
     animation-delay: 7.5s;
     animation-duration: 2s;
     animation-iteration-count: infinite;
     animation-timing-function: ease-in;
     animation-direction: normal;
     animation-fill-mode: forwards;
}
 @keyframes move1 {
     to {
         transform: translateX(200px);
    }
}
 @keyframes blink {
     from {
         opacity: 0;
    }
     to {
         opacity: 1;
    }
}
 @keyframes gr {
     from {
         transform: rotate(0deg);
    }
     to {
         transform: rotate(359deg);
    }
}
 @keyframes scl {
     to {
         transform: scale(1.1);
    }
}  
 @keyframes move2 {
     to {
         transform: translateY(400px);
    }
}  
        }
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
</svg>

  •  Tags:  
  • Related