HTML5 Game - Canvas Animation Mechanical Gears

Animating mechanical gears

The following code creates a system of interconnected rotating gears.

Demo

ResultView the demo in separate window

<!DOCTYPE HTML>
<html>
    <head>
        <script>
            /*ww  w  .ja v  a  2s.  co m*/
class MyObject{
   draw(animationController){
      let canvas = animationController.getCanvas();
      let context = animationController.getContext();

                context.save();
                context.translate(this.x, this.y);
                context.rotate(this.theta);
                
                // draw gear teeth
                context.beginPath();
                context.lineJoin = "bevel";
                
                let numPoints = this.numTeeth * 2;
                for (let n = 0; n < numPoints; n++) {
                    let radius = null;
                    
                    // draw tip of teeth on even iterations
                    if (n % 3 == 0) {
                        radius = this.outerRadius;
                    }
                    else {
                        radius = this.innerRadius;
                    }
                    
                    let theta = ((Math.PI * 2) / numPoints) * (n + 1);
                    let x = (radius * Math.sin(theta));
                    let y = (radius * Math.cos(theta));
                    
                    if (n == 0) {
                        context.moveTo(x, y);
                    }else {
                        context.lineTo(x, y);
                    }
                }
                
                context.closePath();
                
                // define the line width and stroke color
                context.lineWidth = 5;
                context.strokeStyle = this.darkColor;
                context.stroke();
 
                context.stroke();
                context.restore();

   }
   constructor(config){
       this.x = config.x;
       this.y = config.y;
       this.outerRadius = config.outerRadius;
       this.innerRadius = config.innerRadius;
       this.holeRadius = config.holeRadius;
       this.numTeeth = config.numTeeth;
       this.theta = config.theta;
       this.thetaSpeed = config.thetaSpeed;
       this.clockwise = config.clockwise;
       this.midRadius = config.outerRadius - 10;
   }
}    
class MyAnimation {
   constructor(canvasId){
        this.canvas = document.getElementById(canvasId);
        this.context = this.canvas.getContext("2d");
        this.t = 0;
        this.timeInterval = 0;
        this.startTime = 0;
        this.lastTime = 0;
        this.frame = 0;
        this.animating = false;

        window.requestAnimFrame = (function(callback){
            return window.requestAnimationFrame ||
            window.webkitRequestAnimationFrame ||
            window.mozRequestAnimationFrame ||
            window.oRequestAnimationFrame ||
            window.msRequestAnimationFrame ||
            function(callback){
                window.setTimeout(callback, 1000 / 60);
            };
        })();
   }
   getContext(){
      return this.context;
   };

   getCanvas(){
      return this.canvas;
   };

   clear(){
       this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
   };

   setDrawStage(func){
       this.drawStage = func;
   };

   isAnimating = function(){
       return this.animating;
   };

   getFrame(){
      return this.frame;
   };

   start(){
        this.animating = true; 
        let date = new Date();
        this.startTime = date.getTime();
        this.lastTime = this.startTime;
        
        if (this.drawStage !== undefined) {
            this.drawStage();
        }
        
        this.animationLoop();
   };

   stop(){
       this.animating = false;
   };

   getTimeInterval(){
       return this.timeInterval;
   };

   getTime(){
    return this.t;
   };

   getFps(){
      return this.timeInterval > 0 ? 1000 / this.timeInterval : 0;
   };

   animationLoop(){
        let that = this;
        
        this.frame++;
        let date = new Date();
        let thisTime = date.getTime();
        this.timeInterval = thisTime - this.lastTime;
        this.t += this.timeInterval;
        this.lastTime = thisTime;
        
        if (this.drawStage !== undefined) {
            this.drawStage();
        }
        
        if (this.animating) {
            requestAnimFrame(function(){
                that.animationLoop();
            });
        }
    }   
} 
            window.onload = function(){
                let myAnimation = new MyAnimation("myCanvas");
                let canvas = myAnimation.getCanvas();
                let context = myAnimation.getContext();
                
                let gears = [];
                
                // add blue gear
                gears.push(new MyObject({
                    x: 270,
                    y: 105,
                    outerRadius: 90,
                    innerRadius: 50,
                    holeRadius: 10,
                    numTeeth: 24,
                    theta: 0,
                    thetaSpeed: 1 / 1000,
                    clockwise: false
                }));
                
                // add red gear
                gears.push(new MyObject({
                    x: 372,
                    y: 190,
                    outerRadius: 50,
                    innerRadius: 15,
                    holeRadius: 10,
                    numTeeth: 12,
                    theta: 0.14,
                    thetaSpeed: 2 / 1000,
                    clockwise: true
                }));
                
                myAnimation.setDrawStage(function(){
                    // update
                    for (let i = 0; i < gears.length; i++) {
                        let gear = gears[i];
                        let thetaIncrement = gear.thetaSpeed * this.getTimeInterval();
                        gear.theta += gear.clockwise ? thetaIncrement : -1 * thetaIncrement;
                    }
                    
                    // clear
                    this.clear();
                    
                    // draw
                    for (let i = 0; i < gears.length; i++) {
                        gears[i].draw(myAnimation);
                    }
                });
                

                myAnimation.start();
            };
        </script>
    </head>
    <body>
        <canvas id="myCanvas" width="600" height="250" style="border:1px solid black;">
        </canvas>
    </body>
</html>