I have written quite a bit of code in my life. The languages
I used were all assembly or high level such as Cobol (yuck), Pascal, C,C++,
Java and some not so well known like Algol and Smalltalk 80. I have never done
much with HTML apart from poking around in other peoples stuff, changing some
bits just learning what I needed to make the necessary changes.
Today HTML5 is being pushed through all media channels -
maybe time for me to take a closer look?
Table of Contents
How was HTML's first impression?
But first I needed an idea
Let’s have a look at some bits of
This needs some optimising
Download Sample Code
Watch the sample code in action
- Additional Resources
I. How was HTML's first
am going to write HTML in the following when I mean the conglomerate of HTML,
and error or print messages along the way. It all appeared a big mess to me.
II. My latest look at HTML5 was much nicer!
Using the Chrome browser I have a debugger – it really
debugs my code with full single stepping and breakpoints. I can also set
breakpoints on events. The “developer tools” also give me an inspector for
elements and the styles used (with inheritance!), I can view the various
resources (or assets) used and more things I haven’t used in depth yet like
performance monitoring. Developing HTML has come a long way since I first tried
it out. Reading through some HTML5 articles, canvas pops out quite prominently.
Canvas allows web developers to dynamically draw graphics on the screen without
any plug-ins, what was not possible before HTML5 arrived. I decided to write
something to try canvas out.
III. But first I needed an idea
Looking around my home office, my old Spirograph box jutted
out of a shelf – my inspiration to write a spirograph app!
As you can see, most of the bits are still there and I was
amazed to find a stack of old drawings I made as a child:
If you don’t know Spirograph, it is basically a flat plastic
ring and some gearwheels. The ring is pinned to a sheet of paper on top of some
cardboard. Gear teeth are cut on both sides of the ring and the gearwheels have
holes for pens. You place the gearwheel on the paper with its teeth
intersecting with the teeth on the ring and, with a pen in one of the pen
holes, move the wheel around in circles. I used to do this for hours on end.
Here is a link to some more History
Spirograph is applied math based on cycloids. If the gear wheel is moved around
the outside of the ring you get an Epitrochoid, moved inside the ring you get a Hypotrochoid.
In my little test app I want to draw the hypotrochoid type
IV. Initial Design
I want a simple user interface allowing the user to:
Enter the radius of the ring and the wheel
Enter the distance between the pen and the wheels centre
Some buttons to easily change the above numbers (+-10, +-1)
A button to start drawing and a button to clear the drawing
I will also add some code to prepare for changing the color
of the pen and the pen thickness. This can be a future extension.
This is the site I took the math from: Mathematische Basteleien.
The author has a good explanation of the math involved.
The next step is to type it all in. For editing I used Notepad++ and here is the first incarnation of sprio:
V. Let’s have a look at some bits of the code
The canvas itself is defined done in line 90:
<canvas id="canvas" width="400" height="400"></canvas>
All the drawing happens in the function
in line 6.
First step in working with canvas is to get a context to
work with. All the drawing functions need a context – they don’t work on canvas
itself. My context is called
var objCanvas = document.getElementById("canvas");
var ctx = objCanvas.getContext("2d");
What I am additionally doing here is saving the current
context. This allows me to mess things up and restore the old context when my
function exits (
using ctx.restore()). That is not necessary
for this simple app, but I think it is a good thing to get used to for future,
more complex programs.
The maths requires the point of origin to be in the centre
of the drawing area. So I have to translate the canvas to that point. First I
look for the smallest side and then move the centre to the middle of the
size = objCanvas.width;
size = objCanvas.height;
Drawing lines on a canvas involves a thing called path. A
path is essentially a polygon made of lines and arcs. A path can also have
several sub paths. A context only has one path at a time. To draw some lines
you need to build a path using functions such as
moveTo. Then you
can change things like line colour and thickness and finally use stroke to draw
the path. The next steps in the code are quite straight forward:
calculate the starting point (the
StartX = and
StartY = lines)
using the maths
begin a path with
move the pen to that point:
Next is the main loop that terminates when it gets back to
the starting point. All the loop does is to calculate the next step (using the
same math as for the starting point) and draw to that point:
doesn’t bring any line to the screen, it adds the line to the path. To make it
visible I need this function:
canvas related function is
get a context
clear a rectangle:
context.clearRect(0, 0, canvas.width,canvas.height);
The other functions handle the +-10 and +-1 buttons to
The app worked but I was not really happy
VI. This needs some optimising
Yes it works but:
it is very slow
the +-10 and +-1 button functions are messy
the main loop has a lot of maths that can be optimised
Before I started to optimise the app I first measured the
time it takes to draw a curve using the profiling tool in Chrome to measure the
time DrawSpiro takes:
Test parameters: 175, 50, 130
Sprio1: 810ms for DrawSpiro
First step: move the stroke function call outside of
the main loop:
} while ((x != StartX) && (y != StartY));
Quite a difference! One big path is much better than many
2nd step: optimise some of the math in the main loop.
Some of the statements never change and could be calculated once outside the
var OmI = OuterRadius-InnerRadius;
var IdO = InnerRadius / OuterRadius;
var IdO1 = 1 - IdO;
StartX = OmI*Math.cos(IdO*Angle)+PenOffset*Math.cos(IdO1*Angle);
StartY = OmI*Math.sin(IdO*Angle)-PenOffset*Math.sin(IdO1*Angle);
I needed some new test parameters to get a longer drawing
Test parameters: 181, 47, 130
Spiro1-1: 310ms on 1st run and 190ms on every other run
- Spiro1-2: 180ms on 1st run, 43ms on every other run
Again, a large performance boost. It shows that the
the loop and make them a constant. This is one of the main differences between
a dynamic interpreted language and a compiled language where the optimiser can
work its wonders. Odd is that the 2nd and following runs are faster than the
very first. I don’t have an explanation for that – maybe you have? Another area
for speeding up the app is the resolution I am calculating the steps. Instead
of every degree (Step = Math.PI/180) every 10th degree is also very sufficient
(Step = Math.PI/180*10).
Spiro1-2: fresh load 128ms, 2nd try 5ms
Now I have the speed I want – next step clean up the +-10
and +-1 button functions. I started out with one function per plus or minus
(just two buttons & one function shown here):
All this can be written much more elegantly:
Now I have quite a nice little app. The formatting of the
buttons and surrounding text could be neater and it would be cool to change the
pen colour and thickness – that will be something for an extension or you can add on your own.
VII. Watch the sample code in action (click to see