Drawing a canvas star with javaScript

Time for yet another canvas example this time I think I will do a quick example of drawing a star using javaScript and canvas. There are many ways of doing so with a canvas HTML element, many solutions that I see involve making a draw method that will draw a star directly to the canvas. Although these kinds of solutions work I think a better way of doing so is to create a method that will create an array of points, and then have a draw method that will just render that array of points to the canvas. That way the process of drawing a start is just a matter of working out logic that will create an array of points that are to be rendered in a connect the dots type fashion. By doing so I am also pulling the state of these points away from logic that is used to render the state of such points.

1 - A basic canvas star example using a module and external draw methods.

So here is a canvas example that will draw stars to a canvas element. In makes use of a module that is used to create an array of points, and then another module that is used to draw those points to the canvas.

1.1 - The module to make a canvas star

First off there is the module that I worked out that creates arrays of points that when drawn in order end up drawing stars. There is more than one method provided by this module to create these point arrays, and some internal helper methods to parse options and get a point when given a radian, and radius from a given origin.

One method that creates an array of points that makes up a star I called just simply create1. This method works by having not one but to radius from a center point. There is one set of points at one radius, and another set of points at another radius, and both sets of points are spaced out between each other half way. When the array of points is drawn the line will be drawn from a point at one radius to the next point at the other radius, thus forming a star like shape that way.

The other method that I worked out is called just create2, this method creates an array of points by way of having a single set of points at a single given radius, the oder in which points are added to the array is just set by a point skip argument that defaults to 2.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
var starMod = (function () {
// get a point with a given radian, radius, and origin point
var getPoint = function (radian, radius, ox, oy) {
return {
x: Math.cos(radian) * radius + ox,
y: Math.sin(radian) * radius + oy
};
};
// parse options
var parseOptions = function (opt) {
opt = opt || {};
opt.pointCount = opt.pointCount || 5;
opt.radius = opt.radius === undefined ? 50 : opt.radius;
opt.radiusInner = opt.radiusInner === undefined ? 25 : opt.radiusInner;
opt.radianAjust = opt.radianAjust === undefined ? 0 : opt.radianAjust;
opt.ox = opt.ox || 0;
opt.oy = opt.oy || 0;
opt.pointSkip = opt.pointSkip || 2;
return opt;
};
// public API
return {
// create a star points array by pointCount, and inner and outer radius
create1: function (opt) {
opt = parseOptions(opt);
var i = 0,
pt,
r,
rd = Math.PI * 2 / opt.pointCount,
points = [];
while (i < opt.pointCount) {
pt = getPoint(rd * i + opt.radianAjust, opt.radius, opt.ox, opt.oy);
points.push(pt.x, pt.y);
pt = getPoint(rd * i + rd / 2 + opt.radianAjust, opt.radiusInner, opt.ox, opt.oy);
points.push(pt.x, pt.y);
i += 1;
}
return points;
},
// create a star by point count radius and point skip
create2: function (opt) {
opt = parseOptions(opt);
var i = 0,
pt,
r,
rd = Math.PI * 2 / opt.pointCount * opt.pointSkip,
points = [];
while (i < opt.pointCount) {
pt = getPoint(rd * i + opt.radianAjust, opt.radius, opt.ox, opt.oy);
points.push(pt.x, pt.y);
i += 1;
}
return points;
}
}
}
());

There are many many ideas that come to mind when it comes to further expanding a module like this. Such as having a method that returns not just an array of points, but an object where the array of points is just an argument, and then there are a bunch of methods that can eb used to update the state of those points. However for this section I will be keeping this simple for now.

1.2 - The draw methods

I then have some draw methods that I worked out that I made as part of an additional module following just th simple object literal pattern. One is to just draw a plain black background, and another is to draw an array of points.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var draw = {};
draw.background = function (ctx, canvas) {
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.strokeStyle = 'white';
};
draw.points = function (ctx, points, cx, cy) {
cx = cx === undefined ? 0 : cx;
cy = cy === undefined ? 0 : cy;
ctx.save();
ctx.translate(cx, cy);
var i = 2,
len = points.length;
ctx.beginPath();
ctx.moveTo(points[0], points[1]);
while (i < len) {
ctx.lineTo(points[i], points[i + 1])
i += 2;
}
ctx.closePath();
ctx.stroke();
ctx.fill();
ctx.restore();
};

The draw points method will be used to draw my array of points that compose a star, however it could of course be used to draw any such array of points in general.

1.3 - Testing this all out real quick with a little more javScript and html

So then it is just a matter of using the methods to create point arrays, and then pass those point arrays to my draw points method. Apart from the usual with any canvas project such as creating a canvas element and getting a reference to it, as well as linking to my start module that I worked out above.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<html>
<head>
<title>canvas star</title>
</head>
<body>
<canvas id="the-canvas" width="320" height="240"></canvas>
<script src="./lib/draw.js"></script>
<script src="./lib/star.js"></script>
<script>
var canvas = document.getElementById('the-canvas'),
ctx = canvas.getContext('2d');
var star1 = starMod.create1({
radius: 60,
radiusInner: 30
});
var star2 = starMod.create2({
pointCount: 7,
radius: 60,
pointSkip: 3
});
ctx.lineWidth = 3;
draw.background(ctx, canvas);
ctx.strokeStyle = 'white';
draw.points(ctx, star1, 80, canvas.height / 2);
draw.points(ctx, star2, 240, canvas.height / 2);
</script>
</body>
</html>

This results in two stars created with the two separate methods drawn at two locations in the canvas. The important thing here is that I am keeping the state of the starts separate from that of the methods that are used to draw that state. I could expand on the canvas star module by adding additional methods that can be used to manipulate the star point arrays. Another option though would be to make an example that just creates new stars each time.

2 - Now for an example that involves creating an animation with this star module

So now that I have my start module and my draw points method I now want to make another example that will be a basic canvas animation of sorts. This example will involve using the create1 start method to create an array of points on each loop of a loop method. Each time i create a new array of points I will be tweaking the options that are use to create it resulting in an animation.

The values that I want to tweak are the number of points and the inner radius, each time the loop is called I will be increasing or decreasing the inner radius. In addition when the radius reaches a lower bound I will be stepping the point count.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<html>
<head>
<title>canvas star</title>
</head>
<body>
<canvas id="the-canvas" width="320" height="240"></canvas>
<script src="./lib/draw.js"></script>
<script src="./lib/star.js"></script>
<script>
var canvas = document.getElementById('the-canvas'),
ctx = canvas.getContext('2d');
var pointCount = 5,
inner = 20,
deltaInner = 1;
var loop = function () {
requestAnimationFrame(loop);
var star = starMod.create1({
pointCount: pointCount,
radius: 40,
radiusInner: inner
});
// step inner and point count
inner += deltaInner;
deltaInner = inner >= 80 ? -1 : deltaInner;
deltaInner = inner <= 20 ? 1 : deltaInner;
if (inner === 20) {
pointCount += 1;
pointCount = pointCount >= 20 ? 5 : pointCount;
}
// draw
ctx.lineWidth = 7;
draw.background(ctx, canvas);
ctx.strokeStyle = 'white';
ctx.fillStyle = 'green';
draw.points(ctx, star, canvas.width / 2, canvas.height / 2);
ctx.fill();
};
loop();
</script>
</body>
</html>

This results in the animation I more or less hand in mind, but I am having a low of idea of other projects that might use this star module that might make for a more interesting example.

3 - Conclusion

So this canvas example of a star module worked out pretty well, it was a nice little exercise at making stars for use in a canvas element. There is more than one method for making them both of which have to do with Math.cos and Math.sin that are used to find out points around a given origin point.

In this post I also touched basic on a number of other topics also, such as separating a module from a view by having the star module septate from the model that is used to draw the array of points to the canvas. With that said I hope that you picked up one or two ore interesting things when it comes to canvas, and javaScriopt in general that can be applied to your own projects in the future.