如何使用requestAnimationFrame控制幀率(fps)
fps一詞通常與影片和遊戲相關,在這些領域需要使用動畫。fps是每秒幀數的縮寫,表示螢幕每秒重新渲染的次數。
例如,影片是由連續的影像序列組成的。這意味著它以非常短的間隔顯示影像,以至於使用者無法察覺到它是逐幀顯示的。如果降低影片的fps,它看起來可能更像動畫而不是影片。因此,更高的fps通常能帶來更好的效果。基本上,fps告訴我們螢幕每秒應該更新多少次。
有時,我們需要使用JavaScript來控制fps。我們可以使用不同的方法,我們將在本教程中學習這些方法。
使用setTimeout()函式
setTimeout()函式以回撥函式作為第一個引數,時間間隔作為第二個引數。在這裡,我們可以每隔一段時間重新渲染螢幕來控制fps。
語法
使用者可以按照以下語法使用setTimeout()函式來控制fps。
setTimeout(() => {
requestAnimationFrame(animate);
}, interval);
我們在上面的語法中使用requestAnimationFrame()方法呼叫了animate()函式。
步驟
步驟1 − 定義totalFrames變數並初始化為零。它將記錄總幀數。
步驟2 − 同樣,定義fps變數並存儲fps的值。
步驟3 − 定義intervalOffps變數並將間隔儲存到其中。它儲存1000/fps,其中1000是毫秒,我們透過將其除以fps來獲得時間間隔。
步驟4 − 將當前時間儲存在startTime變數中。
步驟5 − 呼叫animate()函式。
步驟5.1 − 使用setTimeout()函式在每個intervalOffps之後呼叫requestAnimationFrame()函式。
步驟5.2 − 在setTimeout()函式的回撥函式中,使用者可以編寫程式碼來重新渲染螢幕或在Canvas上繪製形狀。
步驟5.3 − 使用Date()物件獲取當前時間。從當前時間減去起始時間以獲得經過的時間。
步驟5.4 − 使用數學函式,獲取總fps和總時間。
示例1
在下面的示例中,我們使用setTimeout()函式來控制fps。我們使用'3'作為fps的值。因此,我們的fps間隔等於1000/3。所以,我們將每隔1000/3毫秒呼叫一次requestAnimationFrame()方法。
<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>
使用Date()物件
我們可以使用Date()物件獲取當前時間和上一幀時間之間的差值。如果時間差超過幀間隔,我們將重新渲染螢幕。否則,我們將等待完成單幀。
語法
使用者可以按照以下語法使用時間間隔來控制fps。
consumedTime = current - AfterTime;
if (consumedTime > intervalOffps) {
// rerender screen
}
在上面的語法中,消耗的時間是當前時間和上一幀完成時間之間的差值。
示例2
在下面的示例中,我們獲取當前幀和上一幀之間的時間差。如果時間差大於時間間隔,我們將重新渲染螢幕。
<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>
示例3
在下面的示例中,使用者可以使用輸入範圍設定fps。之後,當用戶點選按鈕時,它將執行startAnimation()函式,該函式設定fps間隔並呼叫animate()函式。animate()函式呼叫drawShape()函式在畫布上繪製形狀並控制fps。
在這裡,我們使用了一些方法在畫布上繪製形狀。使用者可以使用輸入範圍更改fps,嘗試動畫形狀並觀察動畫中的差異。
<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>
資料結構
網路
關係型資料庫管理系統(RDBMS)
作業系統
Java
iOS
HTML
CSS
Android
Python
C語言程式設計
C++
C#
MongoDB
MySQL
Javascript
PHP