Animating coordinates in JavaScript - precalculated values vs. on-the-fly calculation

193 views Asked by At

I'm working on a looping animation using JavaScript and HTML5 <canvas>. The animation consists of using canvas' lineTo() method to connect between 10 and 200 coordinates to create an animated shape. The animation is looping and has a duration of 10-20 seconds. Using requestAnimationFrame() I'm looking at around 60fps, each iteration of which the position of each coordinate is updated.

What is the most efficient way of approaching this type of animation?

Approach 1 - on-the-fly calculations

Currently I'm just calculating and updating the position of each point in each iteration of requestAnimationFrame(). The performance is OK, but on older devices I've noticed the CPU usage spiking and occasional rendering lags. The calculations are pretty basic geometrical manipulations.

Approach 2 - pre-calculated positions

I have been toying with the idea of pre-calculating each possible position that a pointcould have, and storing that in memory. Then during the requestAnimationFrame() loop, I can simply access the coordinates for each point and update its position. But I'm unsure of the performance implications and whether this would really make an impact.

I plan on testing approach 2 to see if there is a noticeable difference. But I'm curious if there is another approach I should consider? Is canvas even the right tool for the job here, or should I be looking at something like WebGL?

*** Edit: here are the calculation & canvas drawing functions so you have an idea of the computation run on each frame:

Animation.prototype = {

  ... the rest of the prototype setup ...

  // This function runs once per `requestAnmiationFrame()` call:
  updateNodes: function() {
    let progress = this.getProgressRadians(); // simple time offset

    // This loops over between 10-200 node objects, updating their positions
    this.nodes.forEach(node => {
      let offset =
        ((Math.sin(progress - node.numberOffset) + 1) / 2) *
        this.pixelWaveHeight;

      if (this.waveGrows) {
        offset =
          offset * (node.index / (this.nodes.length - 1)) * this.waveGrows;
      }

      if (this.waveAngleRadians) {
        offset +=
          Math.tan(this.waveAngleRadians) * this.spaceBetweenNodes * node.index;
      }

      let yValue = this.canvas.height - offset - this.pixelBaseHeight;

      node.y = yValue;
    });
  },

  // This function runs at the end of each `requestAnimationFrame()` call
  draw: function() {
    let ctx = this.canvas.ctx;
    ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
    ctx.beginPath();
    ctx.moveTo(0, this.canvas.height);
    this.nodes.forEach(node => {
      ctx.lineTo(node.x, node.y);
    });
    ctx.lineTo(this.canvas.width, this.canvas.height);
    ctx.lineTo(0, this.canvas.height);
    ctx.closePath();
    ctx.fill();
  }
}

Most of those properties are static, e.g. calculated once at the beginning and then just accessed: pixelWaveHeight - Number waveGrows - Number

0

There are 0 answers