How to Draw a Star with HTML5

by Larry Spencer Saturday, November 3, 2012 3:33 PM

I've started to learn HTML5, and my first topic has been the <canvas> element. A canvas is an area on which you can draw with JavaScript. With the presidential election just days away, what better exercise could I pose for myself than to draw an American flag?

The stripes and blue field are easy. The main challenge is the stars. As long as I was going to the trouble of figuring out where to go with my moveTo's and lineTo's, I thought I'd generalize to draw a star with any number of points, and in any color. Maybe you'll find it useful.

Here's the star we're going to draw.

Your browser does not support HTML5. It's time to get Chrome!

Now here's the source.

<canvas id="star" width="200" height="200" >
    Your browser does not support HTML5. Time to get Chrome!
</canvas>
<script>
    var ctx = document.getElementById("star").getContext("2d");

    ctx.beginPath();
    ctx.fillStyle = "#C40043";
    ctx.arc(100, 100, 100, 0, Math.PI * 2);
    ctx.fill();

    ctx.fillStyle = "yellow";
    drawStar(ctx, 100, 100, 9, 90, 50);
    ctx.fill();

    // Draw a star. This function just does does the lineTo's. It is up to the caller
    // to set the fillStyle and/or strokeStyle on the context, and call fill() or stroke()
    // after this function returns.
    // context     - The HTML5 canvas' context, obtained with getContext("2d").
    // xCenter     - The x coordinate of the center of the star, in the context.
    // yCenter     - The y coordinate of the center of the star, in the context.
    // nPoints     - The number of points the start should have.
    // outerRadius - The radius of a circle that would tightly fit the star's outer vertexes.
    // innerRadius - The radius of a circle that would tightly fit the star's inner vertexes.
    function drawStar(context, xCenter, yCenter, nPoints, outerRadius, innerRadius) {
        ctx.beginPath();
        for (var ixVertex = 0; ixVertex <= 2 * nPoints; ++ixVertex) {
            var angle = ixVertex * Math.PI / nPoints - Math.PI / 2;
            var radius = ixVertex % 2 == 0 ? outerRadius : innerRadius;
            context.lineTo(xCenter + radius * Math.cos(angle), yCenter + radius * Math.sin(angle));
        }
    }
</script>

 

We begin by creating the canvas on lines 1 through 3. Non-HTML5-compliant browsers won't recognize <canvas>, so they will just display its inner text. Compliant browsers will make the canvas available for drawing and ignore the inner text. Cool, eh?

On line 5, we get a drawing context for the canvas. The parameter value of "2d" is the only truly supported one right now, but you can see where they're going with that! Having obtained a context, we are ready to draw.

Lines 7 through 10 show how to make a circle with HTML5. You'd think there would be a circle() function, but no. A circle is just a big arc, so you use the arc() function! The (x,y) coordinate of the center of our arc (where we place the point of our compass, if you will) is the center of the canvas: (100,100). We also want the arc's radius to be 100, so that's the third parameter. The last 2 parameters give the starting and ending angle of the arc, in radians. There are 2*Pi radians in a circle, so we go from 0 to Math.PI*2.

We bracket all that with calls to beginPath() and fill(). Drawing on a canvas consists of specifying the points and curves on a "path" after calling beginPath() and then saying what you want to do with the path. You can draw a line with stroke(), fill the space the path encloses with fill(), or both. Here, we're filling the circle with a pleasing red.

Now for the star.

After resetting the context's fillStyle to "yellow" we call the method where all the work gets done. I could have designed the method so it would take a fillStyle as a parameter, but then what about a strokeStyle? Do I want that parameter, too, even though I'm not using it? Ultimately, I decided it was better design to let drawStar only create the path (Single Responsibility Principle!), and then let the caller decide what to do with the path: fill, stroke or whatever.

An n-pointed star has 2*n vertexes: n for the points and n more for the indentations. The drawStar method loops through them all, connecting them with lineTo calls. You may wonder whether the first lineTo will cause a line to be drawn to the star's first point, from wherever the context was before. The answer is No. The call to beginPath() at the top of the function causes the first lineTo to be treated as a moveTo.

If you're reading closely, you may also wonder why, on line 28, I subtracted Math.PI/2 from the angle. That's because angle 0 is at 3 o'clock, but I wanted the first point of my star to always be at 12 o'clock, which is Math.PI/2 radians away.

The only other point of interest is the conversion from polar coordinates (angle and radius) to cartesian (x and y) on line 30. For that, I refer you to good old Wikipedia.

Next time, we'll use the drawStar function as we create an American flag!

Tags:

All

About the Author

Larry Spencer

Larry Spencer develops software with the Microsoft .NET Framework for ScerIS, a document-management company in Sudbury, MA.