0

I am trying to create a timer alongside some canvas animations. The animation is using a function loop set at 60 fps to refresh the canvas and redraw the objects. The only way I can think of making the stopwatch is by using the same loop to take the milliseconds per frame and add it to the text object. I'm just wondering if there is a more efficient way of doing this?

var frame = 0;
canvas.setLoop(function() {
    if(particle.x < 1080 && particle.x > 0){
        frame++;
        particle.x = 540 + (acc*frame*frame)/120;
        gField.t.text = "g = 9.81ms⁻²\nMass = "+particle.mass+"kg\nF = ma\nFrame: " + frame + "\nDistance: " + (particle.x - 540).toFixed(1);
        stopwatch();
    }else{
        canvas.timeline.stop();
    }
})
var sec = 0;
var tsec = 0;
var hsec = 0;
function stopwatch(){
    hsec+= (5/3);
    if(hsec >= 10){
        tsec++;
        hsec = hsec -10;
    }
    if(tsec >= 10){
        sec++;
        tsec = tsec-10;
    }
    time.text = (sec)+":"+(tsec)+(hsec).toFixed(0);
}
var clicks = 0
control.button.bind("click tap", function() {
    clicks++;
    if(clicks == 1){
        canvas.timeline.start();
    }else{
        clicks = 0;
        canvas.timeline.stop();
    }
})

P.s. this is for a dynamics simulation program. I am using the oCanvas library for the canvas animation.

JimiiBee
  • 159
  • 4
  • 14
  • keep in mind that u dont have 60fps by guarantee. It can drop if f.e. ur client pc is slow. U have do check the time with Date() to get a propper time. – Cracker0dks Nov 25 '14 at 19:24
  • perhaps this might help for getting the FPS of the client: http://stackoverflow.com/a/4787460/648350 – haxxxton Nov 26 '14 at 00:18

1 Answers1

2

Use requestAnimationFrame as this is the most accurate timer you'll get with JavaScript, and bonus is it will provide you with a high-resolution time-stamp:

var ctx = canvas.getContext('2d'),
  startTime = null,
  lastTime = null,  // for scale
  isRunning = false,
  FPS = 1000/60,
  x = 0,
  dx = 4; // ideal frame rate

function loop(timeStamp) {

  if (!startTime) startTime = timeStamp;
    

  var timeDiff = lastTime ? timeStamp - lastTime : FPS,
      timeElapsed = timeStamp - startTime,
      timeScale = timeDiff / FPS; // adjust variations in frame rates

  lastTime = timeStamp;
  
  ctx.clearRect(0,0,canvas.width, canvas.height);

  // do your stuff using timeScale, ie:
  // pos.x += velocity.x * timeScale
  x += dx * timeScale;
  if (x < 0 || x > canvas.width-1) dx = -dx;
  
  ctx.fillRect(x,0,8,8);
  ctx.fillText((timeElapsed*0.001).toFixed(4), 10, 50);
  ctx.fillText(timeScale.toFixed(1), 10, 90);

  if (isRunning) requestAnimationFrame(loop);
}

ctx.font = "40px sans-serif";

btnToggle.addEventListener("click", function() {
  if (isRunning) {
    isRunning = false;
    this.innerHTML = "Start";
  } else {
    startTime = lastTime = null;
    isRunning = true;
    requestAnimationFrame(loop)
    this.innerHTML = "Stop";
  }
}, false);
<canvas id=canvas width=360 height=100></canvas>
<br><button id="btnToggle">Start</button>

To reset start time initialize it with null (or 0). isRunning is used here just as an example on how you can stop the loop (by setting it to false).

Notice that timeScale is used to compensate for frame rate variations. If the loop is not running at 60 FPS then timeScale will compensate for this, ie. if FPS is 30 timeScale would be 2 and so, so that you can update the parameters correctly based on time.

  • Yes! This looks perfect for what I want to do. Thank you – JimiiBee Nov 26 '14 at 21:15
  • I don't see how timeStamp is initialized when calling the loop function – JimiiBee Nov 29 '14 at 18:54
  • Start the loop with `requestAnimationFrame(loop)`. rAF will initialize it. Hope this helps! –  Nov 30 '14 at 02:39
  • Thanks. So I'm guessing that the timestamp is the time between each call of raf? – JimiiBee Dec 02 '14 at 19:48
  • @JimiiBee it's the elapsed time from the loop started. Just subtract the start time when loop is stopped to get the diff. You can also use `performance.now()` instead (rAF uses this internally). Older browsers may not support this though. –  Dec 02 '14 at 19:52
  • When I set it to 30 fps, timescale becomes 0.5 not 2 – JimiiBee Dec 02 '14 at 20:13
  • @JimiiBee the system FPS is a constant, 60 fps. The scale attempts to compensate for *actual* frame rate relative to this (in case some code takes longer time to execute reducing the fps). Let me check double-check the math and update if I made a mistake. –  Dec 03 '14 at 04:37