Drawing in the Browser (2009).

Introduction.

I once wrote a trivial Windows program to draw the 'Dragon Curve'. The source code got lost along the way, and I could not remember exactly how I had done it. This was annoying me, so I attempted to retrace my steps, and I think I got, more or less, to the same algorithm. When it came to drawing it though, I didn't fancy creating yet another Windows executable, but wanted to draw it on a web page.

The Canvas element.

At that point I discovered something I did not know - that HTML5 has a '<canvas>' tag that is very straightforward to use. The snag is that it isn't supported by IE - Microsoft have their own invention VML. This is mildly annoying, and has obviously annoyed others, since there is a piece of Javascript called ExplorerCanvas, that aims to make it simple to use the canvas tag in pages destined for IE.

All you need is a line in your file like:

<!--[if IE]><script type="text/javascript" src="./excanvas.js"></script><![endif]-->
What? I hear you cry - what's with the [if IE] bit? Well that's something else I didn't know. Microsoft - way back in IE5 - invented the 'conditional comment'. You'll see that the above is a valid comment for most browsers, but in IE it can be used to isolate sections of your page that correspond to IE's non-standard ways of doing things. Microsoft must have been prescient - having the non-standard browser support this non-standard behaviour is ideal ;=)

The Dragon Curve implementation.

So anyway you include the funny line, but otherwise your page can be just as it would be for Firefox el al. Here's the Dragon Curve:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> Dragon Curve </TITLE>
<!--[if IE]><script type="text/javascript" src="excanvas.js"></script><![endif]-->
<script>
function flip(s)
{
   if (s == "1")
      return "0";
   var t = (s.length-1)/2;
   var c = s.charAt(t);
   c = (c == "0")? "1": "0";
   return s.substr(0, t)+c+s.substr(t+1);
}

function draw(order, step, startx, starty)
{
   var seq = "1";
   var direction = 1;
   var x = startx;   // trial and error here
   var y = starty;
   var left = [ 3, 0, 1, 2];
   var right = [ 1, 2, 3, 0 ];
   var i = 0;

   for (; i < order; i++)
      seq = seq+"1"+flip(seq);;

   var canvas = document.getElementById('canvas');
   var ctx = canvas.getContext('2d');
   ctx.beginPath();
   ctx.moveTo(x, y);

   for (i = 0; i < seq.length; i++)
   {
      direction = (seq.charAt(i) == "1")? left[direction]: right[direction];
      if (direction & 1)
         x += (direction-1)? -step: step;
      else
         y += direction? step: -step;
      ctx.lineTo(x, y);
   }
   ctx.stroke();
}
</script>
</HEAD>

<BODY onload="draw(13, 3, 280, 200)">
  <canvas style="border:1px solid black" id="canvas" width="800" height="800"></canvas>
</BODY>
</HTML>

Demo.

The only snag with this appproach is that if you draw a Dragon Curve of greater that order 12, IE6 crashes - I can't speak for later versions. Also it's a bit slow compared to the genuine canvas tag.

Here's what it does - order 12, so it should work in IE:

Since the actual graphics coding is trivial - moveTo(), lineTo() ... I may use the [if IE] trick to draw the curve directly using VML and see how that works with a higher order. But anyway, I learned some new things.