0

I'm trying to get the following script working, but when it falls into the continueAnimation function it isn't updating the cPreloaderTimeout variable and it runs in a 'Uncaught RangeError: Maximum call stack size exceeded'.

    var loadingIcon = {

    cSpeed : 8,
    cWidth : 64,
    cHeight : 32,
    cTotalFrames : 7,
    cFrameWidth : 64,
    cImageSrc : 'sprites.png',

    cImageTimeout : false,
    cIndex : 0,
    cXpos : 0,
    cPreloaderTimeout : false,
    SECONDS_BETWEEN_FRAMES : 0,

    startAnimation : function() {
        document.getElementById('loaderImage').style.backgroundImage='url('+ this.cImageSrc+')';
        document.getElementById('loaderImage').style.width=this.cWidth+'px';
        document.getElementById('loaderImage').style.height=this.cHeight+'px';

        //FPS = Math.round(100/(maxSpeed+2-speed));
        FPS = Math.round(100/this.cSpeed);
        SECONDS_BETWEEN_FRAMES = 1 / FPS;

        this.cPreloaderTimeout = setTimeout( this.continueAnimation(), SECONDS_BETWEEN_FRAMES/1000);

    },

    continueAnimation : function() {
        this.cXpos += this.cFrameWidth;
        //increase the index so we know which frame of our animation we are currently on
        this.cIndex += 1;

        //if our cIndex is higher than our total number of frames, we're at the end and should restart
        if (this.cIndex >= this.cTotalFrames) {
            this.cXpos =0;
            this.cIndex=0;
        }

        if(document.getElementById('loaderImage'))
            document.getElementById('loaderImage').style.backgroundPosition=(-this.cXpos)+'px 0';


        this.cPreloaderTimeout = setTimeout(this.continueAnimation(), SECONDS_BETWEEN_FRAMES*1000);
    },

    stopAnimation : function(){//stops animation
        clearTimeout( this.cPreloaderTimeout );
        this.cPreloaderTimeout = false;
    }

}

jQuery( document ).ready(function() {

    jQuery( document ).on("click", "#test", function(){

        var loader = loadingIcon;

        loader.startAnimation();

        setTimeout( loader.stopAnimation(), 3000);

    });
});

It was a plain javascript script at first, but I'm trying to make an object from it so it can be re-used and multiple times at the same time. The problem is now that the cPreloaderTimeout variable isn't set correctly when startAnimation or continueAnimation is triggerd.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • 1
    Because you are not using `setTimeout` correctly. Remove the `()` from `setTimeout(this.continueAnimation(), ...)` and read more about `setTimeout`. – ibrahim mahrir Nov 13 '17 at 22:34
  • 1
    **Note:** When you fix the `setTimeout` issue, you'll fall into the [**`this` issue**](https://stackoverflow.com/questions/591269/settimeout-and-this-in-javascript). – ibrahim mahrir Nov 13 '17 at 22:40

1 Answers1

1

You have a couple issues.

First, your cPreloaderTimeout isn't going to be set like you think it is, as you're not creating an object with a prototype, so the scope of this inside that function is going to be the function itself, not the object.

Second, setTimeout takes a function, but you're calling the function when you try and use it, so the value sent to setTimeout will be the results of the function, not the function itself.

Consider instead the format:

function LoadIcon() {
  this.cSpeed = 8;
  // All your other properties
}

LoadIcon.prototype.startAnimation = function() { 
  // your startAnimation function, concluding with
  this.preloaderTimeout = setTimeout(this.continueAnimation.bind(this), SECONDS_BETWEEN_FRAMES/1000); 
}

// the rest of the methods built the same way

//then, your calling code would look like:

var loadIcon = new LoadIcon();
loadIcon.startAnimation();

EDIT I updated the setTimeout call as I'd forgotten about binding to this for correct scoping when the callback fires.

Paul
  • 35,689
  • 11
  • 93
  • 122