JSFiddle - React, Tailwind, and code Playground

by Keith Poole

HTML

<canvas id='canvasArea' width='540' height='540'>No canvas support sorry</canvas>
<br />
<span id='fpsOutput'>0.00</span> fps
<br />
<span id='msOutput'>0.00</span> ms per frame

CSS

body {
    padding: 10px;
    font-family: sans-serif;
    background: #DDD;
}
canvas {
    background: #000;
    background-image: url('http://1.bp.blogspot.com/-iFRG9k3sNnc/TgpQHjA6ZnI/AAAAAAAAGjk/P0JxsaG8qXs/s1600/DSC_0029%2B-%2BArbeitskopie%2B2.jpg');
    background-size: cover;
}

JavaScript

/* setTimeout vs setInterval vs requestAnimationFrame 
So each has it's folleys;
  setTimeout has to be called each time, so there is the opportunity that something will happen and that call won't happen again.
  setInterval drifts by a few ms each call, tries to 'catch up' on missed milliseconds, and will call the function again regardless of the app state
  requestAnimationFrame has the habit of skipping frame, or just not executing as immediately as you want.
  Refs - http://stackoverflow.com/questions/13233672/properly-handling-timing-for-html5-canvas-engine
*/

/* modify these to affect performance and functionality */
var fpsOutput = document.getElementById('fpsOutput'); // where to send the FPS numbers
var fpsFilter = 1; // the low pass filter to apply to the FPS average, 1 = none
var fpsDesired = 100; // your desired FPS, also works as a max

/* don't touch these ;) */
var fpsAverage = fpsDesired;
var timeCurrent, timeLast = Date.now();
var drawing = false;

/* these are for demo code, not needed for FPS */
var sun = new Image();
var moon = new Image();
var earth = new Image();
var stars = new Image();

function fpsUpdate() {
    fpsOutput.innerHTML = fpsAverage.toFixed(2);
}

/* the main draw function */
function frameDraw() {
    /* Block in case of long draw */
    if(drawing) { return; } else { drawing = true; }
    
    /* Record the start time for draw time measurements */
    var timeStart = Date.now();

    /* execute drawing code. sample code inserted */
    draw();

    timeCurrent = Date.now();
    var fpsThisFrame = 1000 / (timeCurrent - timeLast);
    if (timeCurrent > timeLast) {
        fpsAverage += (fpsThisFrame - fpsAverage) / fpsFilter;
        timeLast = timeCurrent;
    }

    drawing = false;
    
    /* To test how long drawing takes for the demo */
    document.getElementById('msOutput').innerHTML = Date.now() - timeStart;
}

/* set the fps update interval */
setInterval(fpsUpdate, 1000);

/* call the first update so we don't start...