Introduction
HTML5 is rapidly increasing in popularity so I thought I would take it for a spin and try out the new canvas element. The canvas element is basically a rectangular area in which you can draw the usual 2D graphical elements like lines, paths, text, etc. and with the ability to specify fill, gradients, line styles and push and pop transforms for doing things like rotation. It's much lighter weight than SVG and allows the user to manipulate every pixel within that rectangular area, making it great for writing games.
Background
As a first step in playing with canvas, I chose a very simple program I wrote decades ago when my kids were playing around with a Spirograph. I could see the simplest patterns were essentially one circular path being rotated on the end of another circular path with a specific ratio between the two diameters of the circular paths and the ratio of their rotational velocities. With that in mind, I created a very simply GDI Windows application that could achieve something similar. Surprisingly, I was able to almost copy and paste the drawing part of the original C++ code into my JavaScript and with some minor modifications, make it run (e.g. change int
to var
). Another reason that few changes were required is that both GDI and canvas have the origin at the top left, i.e. larger X values are to the right and larger Y values are towards the bottom of the drawing area.
The web page is shown below. It has four selectors at the top of the page. The first two are the ratios I mentioned earlier, the third sets the number of steps in a complete circuit and the fourth selector is for the colour. Changing any of these causes an immediate redraw. I tested the page on all the usual browsers: IE9, Chrome, Firefox, Opera, Safari and it worked identically - the only slight difference being Safari which didn't draw the coloured background of the colour selector or its drop list items.
Using the Code
The main HTML code is shown below. I placed all the selectors in a div
so I could adjust the CSS to get the spacing and appearance I wanted. In case you didn't know hitting F12 in IE9 brings up a nice "developer tool" that allows you to inspect the HTML, CSS, Scripts, etc. and allows you to modify the CSS on the fly. Chrome has a similar tool (use right click "Inspect Element") which in some ways I find better. The main thing to note with the selectors is that they must all have an id (as the JavaScript will need this to find the element and read its attributes) and they have their onchange handler all set to call 'updateCanvas()
'.
<div id='params'>
Size Ratio:
<select id='sizeratio' onchange='updateCanvas()'>
<option>1</option>
<option>2</option>
<option>3</option>
<option selected="selected">4</option>
<option>5</option>
</select>
Speed Ratio:
<select id='speedratio' onchange='updateCanvas()'>
<option>2</option>
<option>3</option>
<option selected="selected">4</option>
<option>5</option>
</select>
Steps:
<select id='steps' onchange='updateCanvas()'>
<option>100</option>
<option>200</option>
<option selected="selected">300</option>
<option>400</option>
<option>500</option>
</select>
Colour:
<select id="color_menu0" name="color_menu0"
onchange="updateCanvas();" style="width: 60px">
<option style="background-color:#5f9ea0" value="#5f9ea0" selected="selected"/>
<option style="background-color:#d2691e" value="#d2691e"/>
<option style="background-color:#ffd700" value="#ffd700"/>
<option style="background-color:#7fff00" value="#7fff00"/>
<option style="background-color:#006400" value="#006400"/>
<option style="background-color:#a52a2a" value="#a52a2a"/>
<option style="background-color:#ff1493" value="#ff1493"/>
</select>
</div>
<div>
<canvas id='canvas1' width='700' height='700' >
Canvas is not supported by this browser.</canvas>
</div>
<script type="text/javascript">
updateCanvas();
</script>
The JavaScript code for the updateCanvas()
function is shown below. The code starts by getting all the selector controls using document.getElementById()
using a string
argument being the id of the HTML element. It then needs to get the selected index and use that to index the options attached to the control. We then get the text part of the selected option and for the first three selectors, convert the text to a floating point number using the Number()
method. For the fourth selector, we get the value rather than the text - reason being the options don't have any text as we just want the background colour displayed. Note the format of the value text is the standard colour format #rrggbb
which is the same format used in HTML and for setting canvas values like fillstyle.
function updateCanvas() {
var c = document.getElementById("canvas1");
var ctlSpeedRatio = document.getElementById("speedratio");
var ctlSizeRatio = document.getElementById("sizeratio");
var ctlSteps = document.getElementById("steps");
var ctlColour = document.getElementById("color_menu0");
var speedRatio =
Number(ctlSpeedRatio.options[ctlSpeedRatio.selectedIndex].text);
var sizeRatio = Number(ctlSizeRatio.options[ctlSizeRatio.selectedIndex].text);
var steps = Number(ctlSteps.options[ctlSteps.selectedIndex].text);
var colour = ctlColour.options[ctlColour.selectedIndex].value;
var cxt = c.getContext("2d");
cxt.beginPath();
cxt.fillStyle = "#FFEEEE";
cxt.clearRect(0, 0, 700, 700);
cxt.fillRect(0, 0, 700, 700);
cxt.strokeStyle = colour;
var xOrigin = 350;
var yOrigin = 350;
var jSize = 320/(sizeRatio + 1);
var iSize = sizeRatio * jSize;
var n = steps * speedRatio;
for (var i = 0; i <= n; i++) {
var f = i * 3.14159265358979 * 2;
var xi = (iSize * Math.sin(f / n)) + xOrigin;
var yi = (iSize * Math.cos(f / n)) + yOrigin;
var xj = (jSize * Math.sin(f / speedRatio));
var yj = (jSize * Math.cos(f / speedRatio));
if (i == 0)
cxt.moveTo(xi + xj, yi + yj);
else
cxt.lineTo(xi + xj, yi + yj);
}
cxt.stroke();
}
Points of Interest
One thing I did learn is that you need to start your drawing by calling the context's beginpath()
method or the canvas won't be erased. I was also surprised by how good the intellisense was in VS2010 in many cases though I note it failed badly in some areas, e.g. listing all the drawing context's methods.
History
This is my first play around with HTML5's canvas element. I hope to bring out some further articles regarding canvas and also SVG.