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.