Ad

Wait For Canvas Animation AND Fetch To Be Completed

So I am fetching data (with $.ajax) while animating a canvas (to create some sort of transition) and I'm looking to wait for both the data to be fetched AND the animation to be done to do something else.

I can easily wait for fetch to be completed, but the second function launching the canvas animation is calling another function, which is the one checking if the animation is done.

So I was thinking about a promise, but I get an error 'Uncaught TypeError: resolve is not a function" which is probably due to requestAnimationFrame.

I've tried many things (await etc) but cannot seem to get my head around it.

Any idea why or how I could achieve that in maybe, a simpler way ? Thanks a lot in advance !

function draw() {

    return new Promise( function drawing(resolve, reject) {

        ctx.clearRect(0, 0, canvas.width, canvas.height); 
        ctx.fillStyle = "rgba(255, 255, 255," + opacity + ")";
        ctx.fillRect(0, 0, canvasWidth, canvasHeight) ;

        for (var i = particles.length - 1; i >= 0; i--) {

            particles[i].drawParticle(img); 

            if (particles[i].outOfCanvas) { 
                particles.splice(i, 1);
            }

        }

        fogAnimation = requestAnimationFrame(drawing);

        if(particles.length === 0) {
            cancelAnimationFrame(fogAnimation);
            // below is the error 
            resolve();
        }

    });

};

function launchTransition() {

    img.onload = function()  {     
        draw().then(function() {
            //here is my issue
            console.log("done !");
        })
    };

    img.src = particle_image;

    // doing more stuff...

}



$('.button').on("click", function() {

    fetchData();

    launchTransition();

    //here I want to wait for the two functions above to be done and do something else


});
Ad

Answer

The problem with your code is that when drawing function gets called by requestAnimationFrame callback, the params resolve and reject are not passed. That's why you got the error Uncaught TypeError: resolve is not a function (because it is undefined).

To fix it we need to have another variable that is dedicated for handling promise (I would called it drawingTracker). I also have a snippet for you to get an idea.

var drawingTracker  = {
    resolve: undefined, // this will point to promise resolve
    draw() {
        return new Promise(resolve, reject) {
            this.resolve = resolve // this.resolve (or drawTracker.resolve) is pointing to promise resolve
            draw(); // call draw function below
        }
    },
    finish() {
        this.resolve(); // will resolve promise
    }
};

function draw() { // this function will be called many times by requestAnimationFrame callback
  ctx.clearRect(0, 0, canvas.width, canvas.height); 
  ctx.fillStyle = "rgba(255, 255, 255," + opacity + ")";
  ctx.fillRect(0, 0, canvasWidth, canvasHeight) ;

  for (var i = particles.length - 1; i >= 0; i--) {

    particles[i].drawParticle(img); 

    if (particles[i].outOfCanvas) { 
      particles.splice(i, 1);
    }

  }

  fogAnimation = requestAnimationFrame(draw);

  if(particles.length === 0) {
    cancelAnimationFrame(fogAnimation);
    drawingTracker.finish(); // this line will resolve promise without errors
  }
};


function launchTransition() {

    img.onload = function()  {     
        drawingTracker.draw().then(function() { // this line do the trick!!
            console.log("done !");
        })
    };

    img.src = particle_image;

    // doing more stuff...

}

Hope it helps.

Ad
source: stackoverflow.com
Ad