I went to Google IO this past week, and they had a whole long spiel about the wonders of html5. Well... i've gotta admit - some of the stuff looked kinda cool, so i decided to play with it. I wrote a web serivice in bistro that returned a list of fibonacci numbers, and then a corresponding page that requested that list through jquery, and generated a tiling and then drew a fibonacci spiral over it:

The code for both was remarkably simple. On the service side, all i had to do was define a recursive function for generating fibonacci numbers (yes, it's not tail-recursive, i know, but i was lazy), and a simple controller for binding to the appropriate REST method:

 
let rec fibonacci a b rem =
    if (rem = 0) then [a]
    else [a] @ fibonacci b (a+b) (rem-1)
 
[<ReflectedDefinition>]
[<Bind("get /fib/{numbers}")>]
[<RenderWith(@"Templates\fibResult.django")>]
let fibCt (ctx: IExecutionContext) numbers =
    let fibNbrs = fibonacci 0 1 numbers
    fibNbrs
 

Prest-o change-o, we're done.

Now for the javascript. The majority of the code here is a rather weak attempt to figure out the tiling. My math skillZ are kinda rusty, and i know i should have defined objects for the squares, and dealt with alternating corners that way, but this did the trick:

 
function load() {
    var url = "/fib/" + $("input[name=iterations]").val();
    $.get(url, function(data) { render(data); }, "xml");
}
 
function render(data) {
    var drawFactor = parseInt($("input[name=magnification]").val());
 
    var canvas = $("#golden").get(0);
    var ctx = canvas.getContext("2d");
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.strokeStyle = "#CCCC99";
    ctx.fillStyle = "#FFFFEE";
 
    var x = canvas.width / 2;
    var y = canvas.height / 2;
    var offsetX = 0;
    var offsetY = 0;
    var arcX = x, arcY = y;
 
    var elems = $(data).find("number");
 
    if (drawFactor == 0)
        drawFactor = Math.min(canvas.width, canvas.height) / (2 * (parseInt($(elems.get(elems.length - 1)).text()) + 1));
 
    for (var i = 1; i < elems.length; i++) {
        ctx.strokeStyle = "#CCCC99";
        ctx.fillStyle = "#FFFFEE";
 
        var last = elems.get(i - 1);
        var current = elems.get(i);
 
        var num = parseInt($(current).text()) * drawFactor;
        var lastNum = parseInt($(last).text()) * drawFactor;
        var idx = i-2;
 
        var startAngle, endAngle = 0;
        switch (idx % 4) {
            case 0:
                x += lastNum;
                y += lastNum - num;
                arcX = x, arcY = y;
                startAngle = Math.PI / 2;
                endAngle = Math.PI * 2;
                break;
            case 1:
                x -= num - lastNum;
                y -= num;
                arcX = x, arcY = y + num;
                startAngle = Math.PI * 2;
                endAngle = Math.PI * 3 / 2;
                break;
            case 2:
                x -= num;
                arcX = x + num, arcY = y + num;
                startAngle = Math.PI * 3 / 2;
                endAngle = Math.PI;
                break;
            case 3:
                y += lastNum;
                arcX = x + num, arcY = y;
                startAngle = Math.PI;
                endAngle = Math.PI / 2;
                break;
        }
 
        ctx.strokeRect(x, y, num, num);
        ctx.fillRect(x, y, num, num);
 
        if (idx < 0)
            continue;
 
        ctx.strokeStyle = "gray";
 
        ctx.beginPath();
        ctx.arc(arcX, arcY, num, startAngle, endAngle, true);
        ctx.stroke();
    }
}
 

Pretty straightforward, really. Notice the lack of work on getting the F# service up and running - just 4 lines of code and you're good.

I'm stoked.

I threw the whole "project" up under bistro samples - you can find the info here under the Examples tree.