DrawStars

An AngularJS way to draw stars on a canvas

Created by Richard Eigenmann / richard.eigenmann@gmail.com

Draw a star

<drawstars 
        maxstars="1" 
        points="{{points}}"
        radius="{{radius}}"
        offcolor="#{{color}}"
></drawstars>


color:

Rating stars


<drawstars 
        maxstars="{{maxstars}}" 
        highlightstars="{{highlightstars}}"
        highlightcolor="#{{highlightcolor}}"
        offcolor="#{{offcolor}}"
></drawstars>

highlightcolor: offcolor:

All Options







highlightcolor:
offcolor:

Star gallery

4 Stars: 3 Stars: 2 Stars: 1 Star: 0 Stars:
4/4 Stars: 3/4 Stars: 2/4 Stars: 1/4 Stars: 0/4 Stars:
5/5 Stars: 4/5 Stars: 3/5 Stars: 2/5 Stars: 1/5 Stars: 0/5 Stars:
2/2 Stars: 1/2 Stars: 0/2 Stars:
2/2 Stars:

A runnable example

<!DOCTYPE html>
<html ng-app="drawStarsApp">
<body>
    <drawstars highlightstars="3" maxstars="4"></drawstars>
    <script src="//ajax.googleapis.com/.../angular.min.js"></script>
    <script src="drawStars.js"></script>
    <script>
        angular.module('drawStarsApp', ['drawStars']);
    </script>
</body>
</html>
Download Code

The Math

Divide the circumference by the number of peaks and toughs:
The whole circle in radians is 2 * Math.PI
Each point is therefore rotated by an angle of
2 * Math.PI / ( OuterPoints + InnerPoints ) from the prior one
= 2 * Math.PI / ( 2 * Points) = Math.PI / Points

Drawing the star in JavaScript


var ctx = document.getElementById("canvas").getContext("2d");
ctx.fillStyle = "gold";
star(ctx, 100, 100, 85, 4, 0.5);
function star(ctx, x, y, outerRadius, points, innerRadiusFraction) {
    var angle = Math.PI / points; // = 2 * PI / 2 * points
    var innerRadius = outerRadius * innerRadiusFraction;
    ctx.save(); ctx.beginPath();
    ctx.translate(x, y);
    ctx.moveTo(0, 0 - outerRadius);
    for (var i = 0; i < points; i++) {
        ctx.rotate(angle);
        ctx.lineTo(0, 0 - innerRadius);
        ctx.rotate(angle);
        ctx.lineTo(0, 0 - outerRadius);
    }
    ctx.fill(); ctx.restore();
}
Credits to: Programming Thomas

Canvas Gotcha

Make sure you specify width and height as elements of the canvas tag. If not you will get a default size of 300x150 as per the HTML5 spec.

Do not specify the width and height as a CSS style for a canvas tag. This specifies the layout size and effectively scales the element width and height to the CSS defined size.

Source: Video from Keith Peters

Under the hood

function drawVariableSizeStar(ctx, x, y, outerRadius, 
        innerRadius, points) {
    var angle = Math.PI / points; // = 2 * PI / 2 * points
    ctx.save();
    ctx.beginPath();
    ctx.translate(x, y);
    ctx.moveTo(0, 0 - outerRadius);
    for (var i = 0; i < points; i++) {
        ctx.rotate(angle);
        ctx.lineTo(0, 0 - innerRadius);
        ctx.rotate(angle);
        ctx.lineTo(0, 0 - outerRadius);
    }
    ctx.fill();
    ctx.restore();
}
function drawStars(ctx, points, maxStars, offColor, highlightStars,
         highlightColor, radius, innerRadiusFraction) {
    ctx.fillStyle = offColor;
    var innerRadius = radius * innerRadiusFraction;
    var y = radius + 1;

    for (var i = maxStars; i > 0; i--) {
        if (highlightStars >= i) {
            ctx.fillStyle = highlightColor;
        }
        var x = ((i - 1) * 2 * radius) + radius + 1;
        drawVariableSizeStar(ctx, x, y, radius, innerRadius, points);
    }
}

The Directive

angular.module('drawStars', [])
    .directive("drawstars", function () {
            function drawStar(...) { ... }
            function drawStars(...) { ... }
            return {
                restrict: "E",
                scope: {
                    highlightstars: '@highlightstars',
                    maxstars: '@maxstars',
                    points: '@points',
                    radius: '@radius',
                    offcolor: '@offcolor',
                    highligtcolor: '@hilightcolor',
                },
                template: "",
                link: function (scope, element) {
                    var canvas = element.find('canvas')[0];
                    var ctx = canvas.getContext('2d');

                    scope.$watch('highlightstars', function () {
                        drawThem();
                    });
                    scope.$watch('maxstars', function () {
                        drawThem();
                    });
                    scope.$watch('points', function () {
                        drawThem();
                    });
                    scope.$watch('radius', function () {
                        drawThem();
                    });
                    scope.$watch('offcolor', function () {
                        drawThem();
                    });
                    scope.$watch('highligtcolor', function () {
                        drawThem();
                    });

                    function drawThem() {
                        var maximumStars;
                        if (!scope.maxstars) {
                            maximumStars = 4; // default to 4 stars if nothing is defined
                        } else {
                            maximumStars = parseInt(scope.maxstars);
                        }

                        var points;
                        if (!scope.points) {
                            points = 5; // defaults to 5 points
                        } else {
                            points = parseInt(scope.points);
                        }

                        var radius;
                        if (!scope.radius) {
                            radius = 10; // defaults to a radius of 10
                        } else {
                            radius = parseInt(scope.radius);
                        }

                        var offColor;
                        if (!scope.offcolor) {
                            offColor = "gold"; // defaults to color gold
                        } else {
                            offColor = scope.offcolor;
                        }

                        var highlightColor;
                        if (!scope.highligtcolor) {
                            highlightColor = "red";  // defaults to color red
                        } else {
                            highlightColor = scope.highligtcolor;
                        }

                        // set the CANVAS width and height (not the CSS width and height)
                        // see https://egghead.io/lessons/javascript-introduction-to-html-canvas-element
                        canvas.width = maximumStars * 2 * radius + 2;
                        canvas.height = radius * 2 + 1;
                        drawStars(ctx, points, maximumStars, offColor, parseInt(scope.highlightstars), highlightColor, radius, 0.5);
                    }
                    ;  // closes funtion drawThem
                    drawThem();
                } // link
            };
        }) // directive
        ; // angular.module

Free Software

References

Impressum