Question

I've hit a wall trying to figure this out. I'm new to OO Javascript and trying to put together my first class/object. I'm trying to create a canvas loader and it's not working. I've narrowed down the error to the requestAnimationWindow portion inside my animate function in my clock class. I get a Object [object global] has no method 'animate' error. Here is my code.

HTML:

<div id="loader"><canvas id="showLoader" width="250" height="250"></canvas><div id="showTimer"><p id="elapsedTime">
  <script>
    var clockTest = new clock(document.getElementById("showLoader"), 0, 100);
    clockTest.animate();
  </script>

</p></div></div>

Javascript:

function clock(canvas, curPerc, endPrecent){

var showPerc = document.getElementById("elapsedTime");
this.canvas = document.getElementById("showLoader");

var context = this.canvas.getContext('2d');
var x = this.canvas.width / 2;
var y = this.canvas.height / 2;
var radius = 75;
this.curPerc = 0;
this.endPercent = 110;
var counterClockwise = false;
var circ = Math.PI * 2;
var quart = Math.PI / 2;


context.lineWidth = 10;
context.strokeStyle = '#ed3f36';


this.animate = function(current) {

    this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
    this.context.beginPath();
    this.context.arc(x, y, radius, -(quart), ((circ) * current) - quart, false);
    this.context.stroke();
    this.curPerc++;

    if(this.curPerc < this.endPercent) {
        requestAnimationFrame(function () {
            this.animate(curPerc / 100);
            showPerc.innerHTML = this.curPerc + '%';
        });
    }
};

}

Any tips is appreciated. Thanks!

Was it helpful?

Solution

It is to do with the context of this in the anonymous function you pass to requestAnimationFrame, its not the this you think. Use a closure i.e.

this.animate = function(current) {
    var self = this; //<-- Create a reference to the this you want
    self.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
    /.. etc, etc..

    if(self.curPerc < self.endPercent) {
        requestAnimationFrame(function () {
            self.animate(self.curPerc / 100); //<-- and use it here
            showPerc.innerHTML = self.curPerc + '%'; //<-- and here
        });
    }
};

On a couple of other points, I would try to structure the object a bit better, you don't seem to be keeping reference to the properties correctly. The parameters you passed in , are not store on the object, and you are not storing the context correctly. Something like:

function clock(canvas, curPerc, endPrecent) {
    var self = this;
    // Set object properties here, i.e. from the parameters passed in
    // Note also, anything that is a property (i.e. this. ) is public, can be accessed from otuside this object,
    // whereas variable declared with var , are privte, can only be access within this object
    self.canvas = canvas;
    self.curPerc = curPerc;
    self.endPercent = endPrecent;
    self.context = self.canvas.getContext('2d'); //needs to be store like this, if you want to access below as this.context
    self.context.lineWidth = 10;
    self.context.strokeStyle = '#ed3f36';

    //Private variables
    var showPerc = document.getElementById("elapsedTime");   
    var x = self.canvas.width / 2;
    var y = self.canvas.height / 2;
    var radius = 75;  
    var counterClockwise = false;
    var circ = Math.PI * 2;
    var quart = Math.PI / 2;

    //Methods
    self.animate = function (current) {
        self.context.clearRect(0, 0, self.canvas.width, self.canvas.height);
        self.context.beginPath();
        self.context.arc(x, y, radius, -(quart), ((circ) * current) - quart, false);
        self.context.stroke();
        self.curPerc++;

        if (self.curPerc < self.endPercent) {
            requestAnimationFrame(function () {
                self.animate(curPerc / 100);
                showPerc.innerHTML = self.curPerc + '%';
            });
        }
    };
}

is starting to head in a better direction.

OTHER TIPS

I ran into the same problem using three.js while calling requestAnimationFrame from inside an ES6 class method and the way I ended up solving it was by:

animate() {
    requestAnimationFrame(() => this.animate());
    this.render();
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top