JSFiddle - React, Tailwind, and code Playground

HTML

<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/c3/0.4.10/c3.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.0/d3.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/c3/0.4.10/c3.js"></script>
<h3>Throttling requestAnimationFrame to a FPS</h3>
<div>
    <input id="fps" type="number" value="24"/> FPS: 
    <span id="results"></span>
</div>
<div>
    <input id="period" type="number" value="1000"/> Sample period (ms)
</div>
<div>
    <input id="samples" type="number" value="10"/> Max # samples to graph
</div>
<canvas id="c"></canvas>
<div id="graph"></div>

CSS

#c {
    border: solid 1px black;
}

JavaScript

// Input/output DOM elements
var $results = $("#results");
var $fps = $("#fps");
var $period = $("#period");
var $samples = $("#samples");

// Array of FPS samples for graphing
var samples = ['fps'];
var maxSamples = +$samples.val();

// Animation state/parameters
var fpsInterval, lastDrawTime, frameCount, lastSampleTime;
var intervalID, requestID;

// Setup canvas being animated
var canvas = document.getElementById("c");
canvas.width = 100;
canvas.height = 100;
var ctx = canvas.getContext("2d");

// Setup FPS samples graph (transitions disabled for speed)
var graph = c3.generate({
    bindto: "#graph", 
    size: {
        height: 200
    },
    data: {
        columns: [samples],
        type: 'spline'
    },
    axis: {
        y: { min: 0 },
        x: { show: false }
    },
    transition: { duration: 0 }
});

// Setup input event handlers

$fps.on('click change keyup', function() {
    if (this.value > 0) {
        fpsInterval = 1000 / +this.value;
    }
});

$period.on('click change keyup', function() {
    if (this.value > 0) {
        if (intervalID) {
            clearInterval(intervalID);
        }
        intervalID = setInterval(sampleFps, +this.value);
    }
});

$samples.on('click change keyup', function() {
    if (this.value > 0) {
        maxSamples = +this.value;
    }
});

function startAnimating(fps, sampleFreq) {
    fpsInterval = 1000 / fps;
    lastDrawTime = performance.now();
    lastSampleTime = lastDrawTime;
    frameCount = 0;
    
    animate();
    
    intervalID = setInterval(sampleFps, sampleFreq);
}

function sampleFps() {
    // sample FPS
    var now = performance.now();
    if (frameCount > 0) {
        var currentFps =
            (frameCount / (now - lastSampleTime) * 1000).toFixed(2);
        $results.text(currentFps + " fps");
        
        frameCount = 0;
        
        // Save the FPS sample for graphing
        samples.push(currentFps);
        console.log(maxSamples);
        if (samples.length > maxSamples + 1)...