Last active
March 13, 2024 19:36
-
-
Save PeteTheHeat/aa10eb8c13413317bb16cdec10325e8f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useEffect, useRef, useState } from 'react' | |
/* | |
A simple FPS meter that displays the average FPS over the last 10 frames. | |
The FPS meter only updates when the average FPS changes by 10 or more to avoid flickering. | |
*/ | |
const FPSMeter: React.FC = () => { | |
const [fps, setFps] = useState<number>(0) | |
// Buffer to store the last 10 FPS values. | |
const fpsBufferRef = useRef<number[]>([]) | |
const lastFrameTimeRef = useRef<number>(performance.now()) | |
useEffect(() => { | |
let animationFrameId: number | |
// A function to update the FPS every frame, called recursively using requestAnimationFrame. | |
const updateFPS = () => { | |
const currentTime = performance.now() | |
const deltaTime = currentTime - lastFrameTimeRef.current | |
const newFps = Math.round(1000 / deltaTime) | |
// newFPS can occasionally be very large (ie: 1000+) due to fluctuations in performance.now(). | |
// Cap it at 120 to avoid FPS spikes. | |
if (newFps <= 120) { | |
fpsBufferRef.current.push(newFps) | |
if (fpsBufferRef.current.length > 10) { | |
fpsBufferRef.current.shift() | |
} | |
const averageFps = Math.round( | |
fpsBufferRef.current.reduce((acc, val) => acc + val, 0) / fpsBufferRef.current.length, | |
) | |
setFps((prevFps) => { | |
if (Math.abs(averageFps - prevFps) >= 10) { | |
return averageFps | |
} | |
return prevFps | |
}) | |
lastFrameTimeRef.current = currentTime | |
} | |
animationFrameId = requestAnimationFrame(updateFPS) | |
} | |
animationFrameId = requestAnimationFrame(updateFPS) | |
return () => { | |
// When the component is unmounted, cancel the animation frame to avoid a memory leak. | |
cancelAnimationFrame(animationFrameId) | |
} | |
}, []) // Empty dependency array to run effect only once on mount. | |
return <div>FPS: {fps}</div> | |
} | |
export default FPSMeter |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment