Sunday 11 February 2024

Web Tutorial: Valentine's Day jQuery Animation (Part 2/2)

Welcome back, and let's get back to creating the transition() method!

We begin by declaring contents as an array of all elements styled using the CSS class square_contents. And imgURL as the string returned by getRandomImage().
transition: function(ms, squareSize)
{
  var contents = $(".square_contents");
  var imgUrl = this.getRandomImage();

}


animationType and sequenceType are defined as random numbers between 0 and 3 and 5, respectively.
transition: function(ms, squareSize)
{
  var contents = $(".square_contents");
  var imgUrl = this.getRandomImage();

  var animationType = Math.floor(Math.random() * 3);
  var sequenceType = Math.floor(Math.random() * 5);

}


We then want to iterate through contents using a For loop. We could do a Foreach loop, but we'll be using the value of i, so...
transition: function(ms, squareSize)
{
  var contents = $(".square_contents");
  var imgUrl = this.getRandomImage();

  var animationType = Math.floor(Math.random() * 3);
  var sequenceType = Math.floor(Math.random() * 5);

  for(var i = 0; i < contents.length; i++)
  {

  }

}


Each element in contents will have a data-row and data-col attribute. Define row and col so that they take on those values.
for(var i = 0; i < contents.length; i++)
{
  var row = $(contents[i]).attr("data-row");
  var col = $(contents[i]).attr("data-col");

}


Then use a Switch statement on animationType. Let's set the default case first.
for(var i = 0; i < contents.length; i++)
{
  var row = $(contents[i]).attr("data-row");
  var col = $(contents[i]).attr("data-col");

  switch (animationType)
  {
    default:
  }

}


Now we will declare transitionTime as a random integer between 0 and ms.
switch (animationType)
{
  default:
    var transitionTime = Math.floor(Math.random() * ms);
}


We then declare sequenceTime and set its value using the getSequenceTime() method, passing in the values of i, transitionTime and sequenceType as arguments.
switch (animationType)
{
  default:
    var transitionTime = Math.floor(Math.random() * ms);
    var sequenceTime = this.getSequenceTime(i, transitionTime, sequenceType);
}


We will, of course, have to declare the getSequenceTime() method. It will have the parameters index, ms and type.
getRandomImage: function()
{
  var index = Math.floor(Math.random() * 9);

  return "'img" + index + ".jpg'";
},
getSequenceTime: function(index, ms, type)
{

},   
   
fillContainer: function()
{


In here, we use a Switch statement on type. Again, we declare the default case first. Since we're returning a value in every case, we don't need break statements. In this case, we return a formula based on index and ms. Basically, the higher the value of index, the greater the returned value. Adding ms to the end is just a way of randomizing the result.
getRandomImage: function()
{
  var index = Math.floor(Math.random() * 9);

  return "'img" + index + ".jpg'";
},
getSequenceTime: function(index, ms, type)
{
  switch (type)
  {
    default: return (index * 1.5) + ms;
  }

},      
fillContainer: function()
{


Where were we? Ah, yes. Inside the transition() method, fulfilling the first (and only, so far) case for animationType. We will run the animate() method on the current element of contents. Make sure to put that element in a jQuery wrapper so that animate() can be run on it.
switch (animationType)
{
  default:
  var transitionTime = Math.floor(Math.random() * ms);
  var sequenceTime = this.getSequenceTime(i, transitionTime, sequenceType);

  $(contents[i])
  .animate()

}


We want to animate the opacity attribute, to 0.
switch (animationType)
{
  default:
    var transitionTime = Math.floor(Math.random() * ms);
    var sequenceTime = this.getSequenceTime(i, transitionTime, sequenceType);

    $(contents[i])
    .animate(
       {
          opacity: 0
       }
    )
}


We want it to use sequenceTime as the duration of the animation.
switch (animationType)
{
  default:
    var transitionTime = Math.floor(Math.random() * ms);
    var sequenceTime = this.getSequenceTime(i, transitionTime, sequenceType);

    $(contents[i])
    .animate(
      {
        opacity: 0
      },
      sequenceTime
    )
}


Once the animation is done, we want to replace the background with the next image, represented by imgUrl. We then manipulate the background-position property using the data-col and data-row attributes of the current element, along with squareSize. squareSize also determines the width and height. We will also make sure the opacity property is still at 0.
switch (animationType)
{
  default:
    var transitionTime = Math.floor(Math.random() * ms);
    var sequenceTime = this.getSequenceTime(i, transitionTime, sequenceType);

    $(contents[i])
    .animate(
      {
        opacity: 0
      },
      sequenceTime,
      function() {
        $(this).attr("style", "background-image:url(" + imgUrl + ");background-position:-" + ($(this).attr("data-col") * squareSize) + "px -" + ($(this).attr("data-row") * squareSize) + "px;opacity:0;width:" + squareSize + "px;height:" + squareSize + "px")
      }
    )
}


Once that's done, we want a slight delay. I recommend double ms.
switch (animationType)
{
  default:
    var transitionTime = Math.floor(Math.random() * ms);
    var sequenceTime = this.getSequenceTime(i, transitionTime, sequenceType);

    $(contents[i])
    .animate(
      {
        opacity: 0
      },
      sequenceTime,
      function() {
        $(this).attr("style", "background-image:url(" + imgUrl + ");background-position:-" + ($(this).attr("data-col") * squareSize) + "px -" + ($(this).attr("data-row") * squareSize) + "px;opacity:0;width:" + squareSize + "px;height:" + squareSize + "px")
      }
     )
    .delay(ms * 2)
}


And after the delay, we want to animate the opacity property back to full opacity.
switch (animationType)
{
  default:
    var transitionTime = Math.floor(Math.random() * ms);
    var sequenceTime = this.getSequenceTime(i, transitionTime, sequenceType);

    $(contents[i])
    .animate(
      {
        opacity: 0
      },
      sequenceTime,
      function() {
        $(this).attr("style", "background-image:url(" + imgUrl + ");background-position:-" + ($(this).attr("data-col") * squareSize) + "px -" + ($(this).attr("data-row") * squareSize) + "px;opacity:0;width:" + squareSize + "px;height:" + squareSize + "px")
      }
    )
    .delay(ms * 2)
    .animate(
      {
        opacity: 1
      },
      sequenceTime
    );
}


Don't forget the break statement!
switch (animationType)
{
  default:
    var transitionTime = Math.floor(Math.random() * ms);
    var sequenceTime = this.getSequenceTime(i, transitionTime, sequenceType);

    $(contents[i])
    .animate(
      {
        opacity: 0
      },
      sequenceTime,
      function() {
      $(this).attr("style", "background-image:url(" + imgUrl + ");background-position:-" + ($(this).attr("data-col") * squareSize) + "px -" + ($(this).attr("data-row") * squareSize) + "px;opacity:0;width:" + squareSize + "px;height:" + squareSize + "px")
      }
    )
    .delay(ms * 2)
    .animate(
      {
        opacity: 1
      },
      sequenceTime
    );

    break;
}


So now, we first see the image appear.



Then it starts fading away in bits starting from the top.



Then it starts appearing again, in bits, from the top.



And you see that it's a different picture that is being assembled.



Viola!



More animations!

Now that you've set one up, let's experiment with more. The first one was merely fidding with the opacity property. Let's try something else! Make a copy of the code in the transition() method, and paste it as the first case, like so.
switch (animationType)
{
  case 0:
    var transitionTime = Math.floor(Math.random() * ms);
    var sequenceTime = this.getSequenceTime(i, transitionTime, sequenceType);  
    $(contents[i])
    .animate(
      {
        opacity: 0
      },
      sequenceTime,
      function() {
        $(this).attr("style", "background-image:url(" + imgUrl + ");background-position:-" + ($(this).attr("data-col") * squareSize) + "px -" + ($(this).attr("data-row") * squareSize) + "px;opacity:0;width:" + squareSize + "px;height:" + squareSize + "px")
      }
    )
    .delay(ms * 2)
    .animate(
      {
        opacity: 1
      },
      sequenceTime
    );

    break;

  default:
    var transitionTime = Math.floor(Math.random() * ms);
    var sequenceTime = this.getSequenceTime(i, transitionTime, sequenceType);  
    $(contents[i])
    .animate(
      {
        opacity: 0
      },
      sequenceTime,
      function() {
        $(this).attr("style", "background-image:url(" + imgUrl + ");background-position:-" + ($(this).attr("data-col") * squareSize) + "px -" + ($(this).attr("data-row") * squareSize) + "px;opacity:0;width:" + squareSize + "px;height:" + squareSize + "px")
      }
    )
    .delay(ms * 2)
    .animate(
      {
        opacity: 1
      },
      sequenceTime
    );

    break;
}


Then let's work on the default case. We want to alter the size this time. So in the first object inside the first call to animate(), we specify that width and height are both set to 0 pixels. In the second call to animate(), we want to set width and height back to squareSize pixels.
default:
  var transitionTime = Math.floor(Math.random() * ms);
  var sequenceTime = this.getSequenceTime(i, transitionTime, sequenceType);  
  $(contents[i])
  .animate(
    {
      width: "0px",
      height: "0px"
    },
    sequenceTime,
    function() {
      $(this).attr("style", "background-image:url(" + imgUrl + ");background-position:-" + ($(this).attr("data-col") * squareSize) + "px -" + ($(this).attr("data-row") * squareSize) + "px;opacity:0;width:" + squareSize + "px;height:" + squareSize + "px")
      }
   )
   .delay(ms * 2)
   .animate(
    {
      width: squareSize + "px",
      height: squareSize + "px"
    },
    sequenceTime
  );

  break;


And we need to make sure that at the part where the picture changes, opacity is full (because it's not opacity we're fiddling with this time) and width and height are both 0 pixels.
default:
  var transitionTime = Math.floor(Math.random() * ms);
  var sequenceTime = this.getSequenceTime(i, transitionTime, sequenceType);  
  $(contents[i])
  .animate(
  {
    width: "0px",
    height: "0px"
  },
  sequenceTime,
  function() {
    $(this).attr("style", "background-image:url(" + imgUrl + ");background-position:-" + ($(this).attr("data-col") * squareSize) + "px -" + ($(this).attr("data-row") * squareSize) + "px;opacity:1;width:0px;height:0px")
  }
  )
  .delay(ms * 2)
  .animate(
    {
      width: squareSize + "px",
      height: squareSize + "px"
    },
    sequenceTime
  );

  break;


We might want to do this for the time being, to ensure that the first case never gets triggered.
var animationType = Math.floor(Math.random() * 3) + 10;
var sequenceType = Math.floor(Math.random() * 5);


Again, the picture animates from the top, the squares all growing smaller...



...till it disappears...



...and reappears from the top.



Gradually, all the way down.



Till it forms another, different picture.



Right, so there's another animation. But what if you don't want it to always start from the top? Well, we've made a provision for it, so go to your getSequenceTime() method. Make a copy of the default case, and set it as the case for value 0.
getSequenceTime: function(index, ms, type)
{
  switch (type)
  {
    case 0: return (index * 1.5) + ms;
    default: return (index * 1.5) + ms;
  }
},


Then change the formula to this.
getSequenceTime: function(index, ms, type)
{
  switch (type)
  {
    case 0: return (index * 1.5) + ms;
    default: return ((index % 10) * 10) + ms;
  }
},


Again, for testing purposes, change the value of sequenceType in the transition() method so that the Switch statement in getSequenceTime() always hits the default case, which is currently anything but 0.
var animationType = Math.floor(Math.random() * 3) + 10;
var sequenceType = Math.floor(Math.random() * 5) + 10;


You see it starts off like this.



And the squares animate almost spread evenly.



They start reappearing, again almost evenly.



Until they almost form a picture...



..and there it is!



Now let's remove the temp stuff we did.
var animationType = Math.floor(Math.random() * 3); // + 10;
var sequenceType = Math.floor(Math.random() * 5); // + 10;


In the startTransition() method, we make sure that transition() is also called every ms milliseconds. Now you should have a varied animation sequence, depending on random animation and sequence type combinations! Of course, you may went to build on it as I have here.
startTransition: function(ms)
{
  this.transition(ms / 10, this.squareSize);

  setInterval(
    ()=>{
      this.transition(ms / 10, this.squareSize);
    },
    ms
  );
},


In your heart of hearts,
T___T

No comments:

Post a Comment