Trig Demo

The first thing that should be shown in any Trigonometry class, done in Canvas. Compare to: http://www.reddit.com/tb/bnzgx.
trig.js
(function () {

var unit = 100,
    drawSeconds = 0,
    t = 0,
    canvas, context, canvas2, context2,
    height, width, xAxis, yAxis,
    draw;

init();

/**
 * Init function.
 * 
 * Initialize variables and begin the animation.
 */
function init() {
    
    canvas = document.getElementById("sineCanvas");
    
    canvas.width = 800;
    canvas.height = 300;
    
    context = canvas.getContext("2d");
    context.font = '18px sans-serif';
    context.strokeStyle = '#000';
    context.lineJoin = 'round';
    
    height = canvas.height;
    width = canvas.width;
    
    xAxis = Math.floor(height/2);
    yAxis = Math.floor(width/4);
    
    context.save();
    draw();
}

/**
 * Draw animation function.
 * 
 * This function draws one frame of the animation, waits 20ms, and then calls
 * itself again.
 */
function draw () {
    
    // Clear the canvas
    context.clearRect(0, 0, width, height);

    // Draw the axes in their own path
    context.beginPath();
    drawAxes();
    context.stroke();
    
    // Set styles for animated graphics
    context.save();
    context.strokeStyle = '#00f';
    context.fillStyle = '#fff';
    context.lineWidth = 2;

    // Draw the sine curve at time t, as well as the circle.
    context.beginPath();
    drawSine(t);
    drawCircle();
    context.stroke();
    
    // Draw the arrow at time t in its own path.
    drawArrow(t);
    
    // Restore original styles
    context.restore();
    
    // Draw the xAxis PI tick and the time
    context.fillText("π", xAxis + 59+3*unit, 18+xAxis);
    context.fillText("t = "+Math.floor(Math.abs(drawSeconds)), 10, 20);
    
    // Update the time and draw again
    drawSeconds = drawSeconds - .01;
    t = drawSeconds*Math.PI;
    setTimeout(draw, 1000 / 60);
};

/**
 * Function to draw axes
 */
function drawAxes() {
    
    // Draw X and Y axes
    context.moveTo(0, xAxis);
    context.lineTo(width, xAxis);
    context.moveTo(yAxis, 0);
    context.lineTo(yAxis, height);
    
    // Draw X axis tick at PI
    context.moveTo(yAxis+Math.PI*unit, xAxis+5);
    context.lineTo(yAxis+Math.PI*unit, xAxis-5);
}

/**
 * Function to draw sine
 * 
 * The sine curve is drawn in 10px segments starting at the origin. 
 */
function drawSine(t) {

    // Set the initial x and y, starting at 0,0 and translating to the origin on
    // the canvas.
    var x = t;
    var y = Math.sin(x);
    context.moveTo(yAxis, unit*y+xAxis);
    
    // Loop to draw segments
    for (i = yAxis; i <= width; i += 10) {
        x = t+(-yAxis+i)/unit;
        y = Math.sin(x);
        context.lineTo(i, unit*y+xAxis);
    }
}

/*
 * Function to draw circle
 */
function drawCircle() {
    context.moveTo(yAxis+unit, xAxis);
    context.arc(yAxis, xAxis, unit, 0, 2*Math.PI, false);
}

/**
 * Function to draw arrow
 */
function drawArrow(t) {
    
    // Cache position of arrow on the circle
    var x = yAxis+unit*Math.cos(t);
    var y = xAxis+unit*Math.sin(t);
    
    // Draw the arrow line
    context.beginPath();
    context.moveTo(yAxis, xAxis);
    context.lineTo(x, y);
    context.stroke();
    
    // Draw the arrow bead
    context.beginPath();
    context.arc(x, y, 5, 0, 2*Math.PI, false);
    context.fill();
    context.stroke();
    
    // Draw dashed line to yAxis
    context.beginPath();
    var direction = (Math.cos(t) < 0) ? 1 : -1;
    var start = (direction==-1) ? -5 : 0;
    for (var i = x;  direction*i < direction*yAxis-5; i = i+direction*10) {
        context.moveTo(i+direction*5, y);
        context.lineTo(i+direction*10, y);
    }
    context.stroke();
    
    // Draw yAxis bead
    context.beginPath();
    context.arc(yAxis, y, 5, 0, 2*Math.PI, false);
    context.fill();
    context.stroke();
}

})();