Canvas Smile

In this example we demonstrate how to draw on the canvas by using the low-level vector graphics API and how to animate the canvas. We draw a smile that blinks and rotates.

The HTML code only defines the canvas:

index.html.haml
%body                                     
  %div
    %span#FPS                             
      fps
    %canvas#canvas(width='350' height='350')      

The Javascript code:

index.html.haml
$(function() {
  var fps = 0, now, lastUpdate = (new Date)*1 - 1;
  // The higher this value, the less the FPS will be affected by quick changes
  // Setting this to 1 will show you the FPS of the last sampled frame only
  var fpsFilter = 50;
  var fpsEl = $("#FPS");

  function calculateFPS(){
    var thisFrameFPS = 1000 / ((now=new Date) - lastUpdate);
    fps += (thisFrameFPS - fps) / fpsFilter;
    lastUpdate = now * 1 - 1;
  }
  function showFPS() {
    fpsEl.html(fps.toFixed(1));
  }

  function drawSmile(ctx) {
    ctx.beginPath();
    ctx.arc(100, 100, 100, 0, 2 * Math.PI, false);
    ctx.closePath();
    ctx.fillStyle = "rgb(255, 255, 0)";
    ctx.fill();

    ctx.fillStyle = "rgb(0, 0, 0)";
    ctx.beginPath();
    ctx.arc(70, 80, 20, 0, 2 * Math.PI, false);
    ctx.closePath();
    ctx.fill();

    ctx.beginPath();
    ctx.arc(130, 80, 20, 0, 2 * Math.PI, false);
    ctx.closePath();
    ctx.fill();

    ctx.beginPath();
    ctx.arc(100, 100, 70, Math.PI/10, Math.PI*(1-1/10), false);
    ctx.lineWidth = 5;
    ctx.strokeStyle = "rgb(0,0,0)";
    ctx.stroke();
  }
  function drawSmileBlink(ctx) {
    ctx.beginPath();
    ctx.arc(100, 100, 100, 0, 2 * Math.PI, false);
    ctx.closePath();
    ctx.fillStyle = "rgb(255, 255, 0)";
    ctx.fill();

    ctx.fillStyle = "rgb(0, 0, 0)";
    ctx.lineWidth = 5;
    ctx.beginPath();
    ctx.moveTo(50,70);
    ctx.lineTo(90,90);
    ctx.closePath();
    ctx.stroke();

    ctx.beginPath();
    ctx.arc(130, 80, 20, 0, 2 * Math.PI, false);
    ctx.closePath();
    ctx.fill();

    ctx.beginPath();
    ctx.arc(100, 100, 70, Math.PI/10, Math.PI*(1-1/10), false);
    ctx.lineWidth = 5;
    ctx.strokeStyle = "rgb(0,0,0)";
    ctx.stroke();
  }

  function clear(ctx) {
    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
  }
  var ctx = document.getElementById('canvas').getContext('2d');
  function createCtx() {
    var canvas = document.createElement('canvas');
    canvas.width = 200;
    canvas.height = 200;
    return canvas.getContext('2d');
  }
  //Create all the contexts
  var smileCtx = createCtx();
  var smileBlinkCtx = createCtx(); 
  var mainCtx = createCtx();

  //Draw the smiles on their own canvas
  drawSmile(smileCtx);
  drawSmileBlink(smileBlinkCtx);

  //Translate the center of the main context
  mainCtx.translate(100,100);
  mainCtx.drawImage(smileCtx.canvas, 0, 0, 200, 200, -100, -100, 200, 200);
  ctx.drawImage(mainCtx.canvas, 0, 0);

  var current = smileCtx.canvas;
  var timer1 = setInterval(function() {
    current = smileBlinkCtx.canvas;
    var timer2 = setTimeout(function() {
      current = smileCtx.canvas;
    }, 300);
  }, 5000);

  //Draw on the canvas every 50ms 
  var timer3 = setInterval(function() {
    clear(ctx);
    mainCtx.rotate(Math.PI/180*5);
    mainCtx.drawImage(current, 0, 0, 200, 200, -100, -100, 200, 200);
    ctx.drawImage(mainCtx.canvas, 0, 0);
  }, 50);
  //Calculate the FPS every 15ms.
  var timer = setInterval(function() {
    calculateFPS();
    showFPS();
  }, 15);
  
})