cssidy cssidy - 24 days ago 8
CSS Question

Javascript animations in timed sequence

I am manipulating a couple CSS classes with Javascript. My script is on a timed sequence, which all together plays an animation. I feel like I am close, but I am stuck, any insights?

Essentially, I need Step 1 and Step 2 to go together at the same time for duration of one second, Step 3 to go for duration of one second after Step 1 and 2, Step 4 and Step 5 to go together at the same time for duration of one second after Step 1, 2, 3 and 4....etc. At the end of Step 6, reset timer and repeat.

I have an SVG, which is made up of a bunch of lines. Some of these lines have to "turn on" at a certain time in the sequence, some have to get bigger, so I'm toggling their classes but only during that certain time, otherwise they are off.

This is what my code looks like (simple SVG is just a model for demonstration). It will manually add classes to elements, but won't reset its timer and repeat infinitely because I haven't been able to figure out how to clear the classes after I add them:

<!DOCTYPE html>
<html>
<head>
<style>
#line1, #line2, #line3, #line4, #line5, #line6 {
visiblity: hidden;
}

.showElement {
visibility: visible !important;
}

.growElement {
transform: scale(1.5) perspective(1px);
}
</style>
</head>

<body>

<svg height="210" width="500">
<line id="line1" class="first" x1="0" y1="0" x2="200" y2="200" style="stroke:red;stroke-width:2" />
<line id="line2" class="first" x1="0" y1="0" x2="200" y2="300" style="stroke:orange;stroke-width:2" />
<line id="line3" class="second" x1="0" y1="0" x2="200" y2="400" style="stroke:yellow;stroke-width:2" />
<line id="line4" class="third" x1="0" y1="0" x2="200" y2="500" style="stroke:green;stroke-width:2" />
<line id="line5" class="fourth" x1="0" y1="0" x2="200" y2="600" style="stroke:blue;stroke-width:2" />
<line id="line6" class="fifth" x1="0" y1="0" x2="200" y2="700" style="stroke:purple;stroke-width:2" />
<line id="line7" class="sixth" x1="0" y1="0" x2="200" y2="800" style="stroke:pink;stroke-width:2" />
</svg>

<script>
document.addEventListener('DOMContentLoaded', function() {

setInterval(function() {
// create array of all the elements with the class 'first', loop over each one
// in this case, ['
var firstClass = document.getElementsByClassName("first");
console.log(firstClass[0]);
console.log(firstClass[1]);
setInterval(function(){
firstClass[0].classList.add("showElement");
firstClass[1].classList.add("showElement");
}, 1000);

var secondClass = document.getElementsByClassName("second");
console.log(secondClass[0]);
console.log(secondClass[1]);
setInterval(function(){
secondClass[0].classList.add("showElement");
secondClass[1].classList.add("showElement");
}, 2000);

var thirdClass = document.getElementsByClassName("third");
console.log(thirdClass[0]);
setInterval(function(){
thirdClass[0].classList.add("showElement");
}, 3000);

var fourthClass = document.getElementsByClassName("fourth");
console.log(fourthClass[0]);
setInterval(function(){
fourthClass[0].classList.add("showElement");
}, 4000);
}, 4000);
});
</script>

</body>
</html>


I also need to figure out how to add multiple classes at once, for only some steps. For example, element .first, .second and .third I want to suddenly appear so I give them .showElement, but element .third I want to also add .growElement. How do I do that?

This is my Javascript code, that doesn't accept multiple things in tandem. It uses a counter, so not as gnarly looking as the previous. It looks through every item in the list and applies one style:

<script>
document.addEventListener('DOMContentLoaded', function() {

var connections = ['first', 'second', 'third', 'fourth', 'fifth', 'sixth'];
var i = 0; // index of the first item to show


setInterval(function(){
console.log(connections[i]);
document.getElementsByClassName(connections[i]).classList.add("showElement");

var counter = connections[i++]; // get the current item index and increment
if ((i == connections.length)) {
i = 0; // reset to first element if reach the end
}
}, 1000);

});




Note: I am not looking to use jQuery, just pure JavaScript. This animation exists on a single page web site with no other JavaScript with an external SVG, so it must exist inside the SVG file, and I don't see much point in installing a large library.

But I am looking into possible better ways to solve this problem. Someone told me this is the work of 'promises'. I am researching Snap.svg, Q, When, WinJS and RSVP.js libraries right now, and would welcome a suggestion if you thought it'd be better (even jQuery, if it truly is easier).

Ben Ben
Answer Source

Here is a little cleaner version which does the animations on a 1-second interval and gives you a little more obvious control over what's happening on each frame.

For adding multiple classes, you can add whatever you like all at once like: classList.Add('showElement', 'growElement') (and the same goes for removing. See examples)

Animation will repeat on a loop by setting the frame back to 0 in the last frame (0 because the frame counter increments after the switch statement). Then in the first frame make sure to clear the styles from the last frame.

<html>
<head>
    <style>
      #line1, #line2, #line3, #line4, #line5, #line6, #line7 {
        visibility: hidden;
        transform: scale(1) perspective(1);
        transition: .5s transform;
      }

      .showElement {
          visibility: visible !important;
      }   

      .growElement {
          transform: scale(3.5) perspective(1px);
      }
    </style>
</head>

<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.2/plugins/CSSPlugin.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.2/easing/EasePack.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.2/TweenLite.min.js"></script>
  
<svg height="210" width="500">
  <line id="line1" class="first" x1="0" y1="0" x2="200" y2="200" style="stroke:red;stroke-width:2" />
  <line id="line2" class="first" x1="0" y1="0" x2="200" y2="300" style="stroke:orange;stroke-width:2" />
  <line id="line3" class="second" x1="0" y1="0" x2="200" y2="400" style="stroke:yellow;stroke-width:2" />
  <line id="line4" class="third" x1="0" y1="0" x2="200" y2="500" style="stroke:green;stroke-width:2" />
  <line id="line5" class="fourth" x1="0" y1="0" x2="200" y2="600" style="stroke:blue;stroke-width:2" />
  <line id="line6" class="fifth" x1="0" y1="0" x2="200" y2="700" style="stroke:purple;stroke-width:2" />
  <line id="line7" class="sixth" x1="0" y1="0" x2="200" y2="800" style="stroke:pink;stroke-width:2" />
</svg>

<script>
                
var frame = 1;

// create array of all the elements with the class 'first', loop over each one
// in this case, ['
var firstClass = document.getElementsByClassName("first");
var secondClass = document.getElementsByClassName("second");
var thirdClass = document.getElementsByClassName("third");
var fourthClass = document.getElementsByClassName("fourth");
var fifthClass = document.getElementsByClassName("fifth");
var sixthClass = document.getElementsByClassName("sixth");
var seventhClass = document.getElementsByClassName("seventh");

function hideUnusedClasses(p_classesArray) {
  p_classesArray.forEach(function(array, index){
    for(var i=0;i<array.length;++i) {
      array[i].classList.remove('showElement', 'growElement');
    }
  });
}

var interval = setInterval(function(){
  //console.log('Run every 1 second');
  switch(frame) {
    case 1:
      //console.log('frame', frame);
      hideUnusedClasses([sixthClass]);
      for(var i=0;i<firstClass.length;++i) { 
        firstClass[i].classList.add('showElement');
      }
      break;
    case 2:
      //console.log('frame', frame);
      //console.log('Delete 1 class');
      hideUnusedClasses([firstClass]); 
      for(var i=0;i<secondClass.length;++i) {
        secondClass[i].classList.add('showElement');
      }
      break;
    case 3:
      //console.log('frame', frame);
      //console.log('Delete 2 class');
      hideUnusedClasses([secondClass]);
      for(var i=0;i<thirdClass.length;++i) {
        thirdClass[i].classList.add('showElement', 'growElement');
      }
      break;
    case 4:
      //console.log('frame', frame);
      hideUnusedClasses([thirdClass]);
      //console.log('Delete 3 class');
      for(var i=0;i<fourthClass.length;++i) {
        fourthClass[i].classList.add('showElement');
      }
      break;
    case 5:
      //console.log('frame', frame);
      hideUnusedClasses([fourthClass]);
      for(var i=0;i<fifthClass.length;++i) {
        fifthClass[i].classList.add('showElement');
      }
      break;
    case 6:
      //console.log('frame', frame);
      hideUnusedClasses([fifthClass]);
      for(var i=0;i<sixthClass.length;++i) {
        sixthClass[i].classList.add('showElement');
      }
      frame = 0;
      break;  
    default:
      //console.log('all done');
      //clearInterval(interval);
  }
  ++frame;
}, 1000);
</script>

</body>
</html>