How to control fps with requestAnimationFrame?


The fps word is generally associated with videos and games where we require to use animations. The fps is an abbreviation of frames per second, and it means how many times it’s rerendering the current screen.

For example, a video is a continuous row of images. It means it shows images in very short intervals so that users can’t know it's showing images individually. If we decrease the fps for video, it can look like image animation rather than video. So, with more fps as it gives better results. Basically, fps tells us how many times it should update the screen in one second.

Sometimes, we require to control the fps using JavaScript. We can use different approaches, which we will learn in this tutorial.

Use the SetTime() Funciton

The setTimeout() function takes a callback function as a first parameter and time interval as a second parameter. Here, we can rerender the screen after every time interval to control the fps.

Syntax

Users can follow the syntax below to use the setTimeout() function to control the fps.

setTimeout(() => {
   requestAnimationFrame(animate);
}, interval);

We have called the animate() function in the above syntax using the requestAnimationFrame() method.

Steps

  • Step 1 − define the totalFrames variable and initialize with zero. It will keep count of the total frames.

  • Step 2 − Also, define the fps variable and store the value of the fps.

  • Step 3 − Define the intervalOffps variables and store the interval into that. It stores the 1000/fps, where 1000 is milliseconds, and we get the time interval by dividing it by fps.

  • Step 4 − Store the current time in the startTime variable.

  • Step 5 − Call the animate() function.

  • Step 5.1 − Use the setTimeout() function to call the requestAnimationFrame() function after every internvalOffps.

  • Step 5.2 − In the callback function of the setTimeout() function, users can write code to rerender the screen or draw a shape on Canvas.

  • Step 5.3 − Use the Date() object and get the current time. Subtract the starting time from the current time to get elapsed time.

  • Step 5.4 − Use the mathematical functions, and get the total fps and total time.

Example 1

In the example below, we used the setTimeout() function to control the fps. We used the ‘3’ as a value of fps. So, our fps interval is equal to 1000/3. So, we will call the requestAnimationFrame() method after every 1000/3 milliseconds.

<html>
<body>
   <h3> Using the <i> setTimeOut() method </i> to control the fps with requestAnimationFrame </h3>
   <div id="output"> </div>
   <script>
      let output = document.getElementById("output");
      // Initial frame count set to zero
      var totalFrames = 0;
      var current, consumedTime;
      
      // Set the fps at which the animation will run (say 10 fps)
      var fps = 3;
      var intervalOffps = 1000 / fps;
      var AfterTime = Date.now();
      var starting = AfterTime;
      animate();
      function animate() {
         setTimeout(() => {
         
            //  call the animate function recursively
            requestAnimationFrame(animate);
            
            // get current time
            current = Date.now();
            
            // get elapsed time since the last frame
            var elapsed = current - starting;
            
            //Divide elapsed time with frame count to get fps
            var currentFps =
            Math.round((1000 / (elapsed / ++totalFrames)) * 100) / 100;
            output.innerHTML = "Total elapsed time is equal to = " + Math.round((elapsed / 1000) * 100) / 100 + "<br>" + " secs @ ";
            output.innerHTML += currentFps + " fps.";
         }, intervalOffps);
      }
   </script>
</body>
</html>

Use the Date() Object

We can get the difference between the current time and the last frame time using the Date() object. If the time difference exceeds the frame interval, we rerender the screen. Otherwise, we will wait to complete the single frame.

Syntax

Users can follow the syntax below to use the time interval to control fps.

consumedTime = current - AfterTime;
if (consumedTime > intervalOffps) {
   // rerender screen
}

In the above syntax, consumed time is the difference between the current time and the time at the last frame finished.

Example 2

In the example below, we take the time difference between the current and last frames. If the time difference is greater than the interval of time, we rerender the screen.

<html>
<body>
   <h3> Using the <i> Date() object </i> to control the fps with requestAnimationFrame. </h3>
   <div id = "output"> </div>
   <script>
      let output = document.getElementById("output");
      // Initial framecount set to zero
      var totalFrames = 0;
      var current, consumedTime;
      
      // Set the fps at which the animation will run (say 10 fps)
      var fps = 50;
      var intervalOffps = 1000 / fps;
      var AfterTime = Date.now();
      var starting = AfterTime;
      animate();
      function animate() {
      
         // use date() object and requestAnimationFrame() to control fps
         requestAnimationFrame(animate);
         current = Date.now();
         consumedTime = current - AfterTime;
         
         // if the consumed time is greater than the interval of fps
         if (consumedTime > intervalOffps) {
         
            // draw on canvas here
            AfterTime = current - (consumedTime % intervalOffps);
            var elapsed = current - starting;
            
            //Divide elapsed time with frame count to get fps
            var currentFps =
            Math.round((1000 / (elapsed / ++totalFrames)) * 100) / 100;
            output.innerHTML = "Total elapsed time is equal to = " + Math.round((elapsed / 1000) * 100) / 100 + "<br>" + " secs @ ";
            output.innerHTML += currentFps + " fps.";
         }
      }
   </script>
</body>
</html>

Example 3

In the example below, users can set the fps using the input range. After that, when users click on the button, it executes the startAnimation() function, which sets the fps interval and calls the animate() function. The animate() function calls the drawShape() function to draw the shape on the canvas and controls the fps.

Here, we have used some methods to draw the shape on the canvas. Users can change the fps using the input range, try to animate the shape and observe the difference in animation.

<html>
<body>
   <h3>Using the <i> Date() object </i> to control the fps with requestAnimationFrame. </h3>
   <!-- creating an input range for fps -->
   <input type = "range" min = "1" max = "100" value = "10" id = "fps" />
   <button onclick = "startAnimation()"> Animate </button> <br><br>
   <!-- canvas to draw shape -->
   <canvas id = "canvas" width = "250" height = "250"> </canvas>
   <script>
      let canvas = document.getElementById("canvas");
      let context = canvas.getContext("2d");
      let animation;
      let intervalOffps, current, after, elapsed;
      let angle = 0;
      // drawing a sha[e]
      function drawShape() {
         context.save();
         context.translate(100, 100);
         
         // change angle
         context.rotate(Math.PI / 180 * (angle += 11));
         context.moveTo(0, 0);
         
         // draw line
         context.lineTo(250, 250);
         context.stroke();
         context.restore();
         
         // stop animation
         if (angle >= 720) {
            cancelAnimationFrame(animation);
         }
      }
      function animate() {
      
         // start animation and store its id
         animation = requestAnimationFrame(animate);
         current = Date.now();
         elapsed = current - after;
         
         // check if elapsed time is greater than interval, if yes, draw shape again
         if (elapsed > intervalOffps) {
            after = current - (elapsed % intervalOffps);
            drawShape();
         }
      }
      function startAnimation() {
      
         // get fps value from input
         let fpsInput = document.getElementById("fps");
         let fps = fpsInput.value;
         
         // calculate interval
         intervalOffps = 1000 / fps;
         after = Date.now();
         requestAnimationFrame(animate);
      }
   </script>
</body>
</html>

Updated on: 04-May-2023

572 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements