5

I'm trting to do the following:

I'm running through a for loop and each time I get a new information and want to draw it on the canvas. The problem is that the canvas is being drawn just after the loop finish, and I can't see no animation. If I step in with debug, or with alert messages, it will draw to the canvas immediatly. How can I do it?

Here is my code, as you can see I've already tried with setTimeout in multiple ways but didn't worked.

for(var i=0;i<1000; i ++)
    {
        addLines(ga.getBestCreature());   // This method draw on the canvas 
        
        setTimeout(function() {
        ga.startEvolution(1);       // This method change the best creature
        }, 10);   
    }

The drowing method:

function addLines(best) {
    
    if(!best) {
        return;
    }
    var global_path = best.data;
    
    redraw(); // Clear off the canvas

    var cityA;
    var cityB;
    for (var i = 0; i < (global_path.length - 1); i++) {
        
        cityA = ga.cities[global_path[i]];
        cityB = ga.cities[global_path[i+1]];
        
        ctx.moveTo(cityA.x,cityA.y);
        ctx.lineTo(cityB.x,cityB.y);
        ctx.stroke();
    }
}

Any Ideas??

Update: After was advised to use the requestAnimationFrame, I've came out with something like this. Is this the best approach? I'm updating a global variable called 'run' on click events

var run = 0;
function animate() {
    
    if(run > 0) {
        ga.startEvolution(1);
        run--;
    }
  
addLines(ga.getBestCreature());
    requestAnimationFrame(animate);
}

animate();

2 Answers 2

4

Your best take is to separate concerns : have an animation loop continuously running, and, "each time [you] get a new information", update your scene description, it will draw as soon as the display is ready.

So a first very simple demo : here the 'new information' is a user click.

var cv = document.getElementById('cv');
var ctx = cv.getContext('2d');
var cvWidth = cv.width;
var cvHeight = cv.height;

// Simple scene description : an array of colored rects
var everyObject = [
  [60, 70, 30, 30, 'yellow']
];

// animation : always running loop.

function animate() {
  // call again next time we can draw
  requestAnimationFrame(animate);
  // clear canvas
  ctx.clearRect(0, 0, cvWidth, cvHeight);
  // draw everything
  everyObject.forEach(function(o) {
    ctx.fillStyle = o[4];
    ctx.fillRect(o[0], o[1], o[2], o[3]);
  });
  // 
  ctx.fillStyle = '#000';
  ctx.fillText('click to add random rects', 10, 10);
}

animate();


// click handler to add random rects
window.addEventListener('click', function() {
  addRandRect();
});

function addRandRect() {
  var randColor = Math.random() > 0.5 ? 'blue' : 'red';
  everyObject.push([Math.random() * cvWidth, Math.random() * cvHeight, 10 + Math.random() * 40, 10 + Math.random() * 40, randColor]);
}
<canvas id='cv' width=400 height=200></canvas>

Now if you want some kind of animation, or a simple version using setTimeOut would be :

var cv = document.getElementById('cv');
var ctx = cv.getContext('2d');
var cvWidth = cv.width;
var cvHeight = cv.height;

// Simple scene description : an array of colored rects
var everyObject = [
  [60, 70, 30, 30, 'yellow']
];

// animation : always running loop.

function animate() {
  // call again next time we can draw
  requestAnimationFrame(animate);
  // clear canvas
  ctx.clearRect(0, 0, cvWidth, cvHeight);
  // draw everything
  everyObject.forEach(function(o) {
    ctx.fillStyle = o[4];
    ctx.fillRect(o[0], o[1], o[2], o[3]);
  });
  // 
  ctx.fillStyle = '#000';
  ctx.fillText('click to add 4 random rects with a delay', 10, 10);
}

animate();


// click handler to add random rects
window.addEventListener('click', function() {
  addRandRect();
  setTimeout(addRandRect, 300);
  setTimeout(addRandRect, 600);
  setTimeout(addRandRect, 900);
});

function addRandRect() {
  var randColor = Math.random() > 0.5 ? 'blue' : 'red';
  everyObject.push([Math.random() * cvWidth, Math.random() * cvHeight, 10 + Math.random() * 40, 10 + Math.random() * 40, randColor]);
}
  <canvas id='cv' width=400 height=200></canvas>

(By the way i wrote about animation here if interested : http://codepen.io/gamealchemist/post/animationcanvas1 )

Sign up to request clarification or add additional context in comments.

1 Comment

Ok that worked but I had to modify it, and now I don't think this is the best practice. I've noticed that wihtin a for loop, requestAnimationFrame won't fire and will wait for the loop to finish. So what I did is basically adding my logic to the animate() method. You can check my in the end of my question, I've added it there
1

You could take a look at requestAnimationFrame: https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame

And us it something like this:

function loop() {
    addLines(ga.getBestCreature());

    // execute loop function over and over
    requestAnimationFrame(loop);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.