Adding more vertices
There are many flags that contain stars that just cannot be created by overlapping triangles. In this recipe, we will figure out how to create a star that contains an arbitrary number of points We will use the same key concept we discovered in the previous recipe by taking advantage of a virtual circle to calculate positions, this time with only two virtual circles. In this recipe, we will create the flag of Somalia and in the process figure out how to create a function that will enable us to create stars.
Getting ready
Please continue working on the sample from the previous recipe. If you haven't worked on it yet, I strongly encourage you to do so as this recipe is the next logical step of the previous recipe. As in the previous recipe, we will be skipping the HTML portion of this sample. Please review the first recipe in the book to refresh on the required HTML code.
How to do it...
Let's jump right in and create the flag of Somalia.
Create the canvas standard logic:
var canvas = document.getElementById("somalia"); var wid = canvas.width; var hei = canvas.height; var context = canvas.getContext("2d");
Fill the background color of canvas:
context.fillStyle = "#4189DD"; context.fillRect(0,0,wid,hei);
Draw the star by calling the
createStar
function:createStar(context,wid/2,hei/2,7,20,5,"#ffffff",null,0);
Create the
createStart
function:function createStar(context,baseX,baseY, innerRadius,outerRadius, points,fillColor, strokeColor,tilt){ // all the rest of the code in here }
From this point on we will be working within the
createStart
function. Add a few helper variables:function createStar(context,baseX,baseY,innerRadius,outerRadius,points,fillColor,strokeColor,tilt){ var radian = Math.PI/180; var radianStepper = radian * ( 360/points) /2; var currentRadian =0; var radianTilt = tilt*radian;
Call the
beginPath
method before starting to draw any shape:context.beginPath();
Move the drawing pointer to the angle
0
in the internal circle:context.moveTo(baseX+ Math.sin(currentRadian + radianTilt) * innerRadius,baseY+ Math.cos(currentRadian + radianTilt) * innerRadius);
Loop through the total points of the star and draw a line back and forth between the outer circle and inner circle to create a star:
for(var i=0; i<points; i++){ currentRadian += radianStepper; context.lineTo(baseX+ Math.sin(currentRadian + radianTilt) * outerRadius,baseY+ Math.cos(currentRadian + radianTilt) * outerRadius); currentRadian += radianStepper; context.lineTo(baseX+ Math.sin(currentRadian + radianTilt) * innerRadius,baseY+ Math.cos(currentRadian + radianTilt) * innerRadius); }
Close the path of the drawing and fill or stroke according to the function parameters:
context.closePath(); if(fillColor){ context.fillStyle = fillColor; context.fill(); } if(strokeColor){ context.strokeStyle = strokeColor; context.stroke(); } }
When you run your HTML wrapper, you will find your first star and with it another flag will be under your belt.
How it works...
Let's start by understanding what the function we are going to create expects. The idea is simple, to create a star we want to have a virtual inner circle and a virtual outer circle. We can then draw lines between the circles back and forth to create the star. To do so, we need some basic parameters.
function createStar(context,baseX,baseY, innerRadius,outerRaduis,points,fillColor, strokeColor,tilt){
Our regular context, baseX
and baseY
don't need further introductions. The virtual innerRadius
and outerRadius
are there to help define the length of the line segments that create a star and their positions. We want to know how many points our star will have. We do so by adding in the points
parameters. We want to know the fillColor
and/or strokeColor
so we can define the actual colors of the star. We top it with a tilt
value (it can be useful as we've seen when creating the Star of David for the flag of Israel).
var radian = Math.PI/180; var radianStepper = radian * ( 360/points) / 2; var currentRadian =0; var radianTilt = tilt*radian;
We then move on to configure our facilitator variables for our star. It's not the first time we see the radian variable, but it is our first radianStepper
. The goal of the radian stepper is to simplify calculations in our loop. We divided 360 degrees by the number of points our triangle will have. We divided the value by 2
, as we will have two times the number of points as lines. Last but not least, we want to convert this value into radians so we are duplicating the full results by our radian variable. We then create a simple currentRadian
variable to store the current step we are in and finish off by converting the tilt
value to be a radian value, so we can add it into all our lines without extra calculations within the loop.
As always, we start and complete our shapes with the beginPath
and closePath
methods. Let's take a deeper look at the starting position for our soon-to-be shape:
context.moveTo(baseX+ Math.sin(currentRadian + radianTilt) * innerRadius,baseY+ Math.cos(currentRadian + radianTilt) * innerRadius);
Although at first glance this probably looks a bit scary, it's actually very similar to how we created the Star of David. We are starting at currentRadian
(that is currently 0
) using innerRadius
as our start point.
In our loop, our goal will be to weave back and forth between the inner and external circles. To do so we will need to progress the currentRadian
value each time the loop cycles by a radianStepper
:
for(var i=0; i<points; i++){
currentRadian += radianStepper;
context.lineTo(baseX+ Math.sin(currentRadian + radianTilt) * outerRadius,baseY+ Math.cos(currentRadian + radianTilt) * outerRadius);
currentRadian += radianStepper;
context.lineTo(baseX+ Math.sin(currentRadian + radianTilt) * innerRadius,baseY+ Math.cos(currentRadian + radianTilt) * innerRadius);
}
We start a loop based on the number of points in our parameter. In this loop, we go back and forth between the external radius and the internal one each time we draw two lines between the inner circle and the external one. Our step size is defined by the number of points (the value we configured with the radianStepper
variable).
We covered the rest of the functions when we created the createTriangle
function in an earlier recipe. There you have it! You can now run the app and find our seventh flag. With this new complex function, we can create all solid stars and all non-solid stars that are hollow within.
OK I hope you are sitting down... with the newly-acquired star powers, you can now create at least 109 flags including the United States of America and all the other countries that have stars in their flag (57 percent of the countries in the world and counting!).