HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Class(es) for animating objects on a canvas

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
objectsanimatingforclasscanvas

Problem

I'm building a simple canvas animation engine as an exercise in learning ES6. Coming from C++ and Java, I miss static properties, but I've read that "Prototypes having data properties is generally considered an anti-pattern".

The animation engine simulates \$n\$ river waves (simple lines), flowing from right to left in an HTML5 canvas, using requestAnimationFrame. Waves come in three lengths, based on a baseLength that should be configurable and have a default: 1x, 5x, and 7x. When creating a new wave, I'm picking one of the lengths at random. All waves have a constant flowing velocity on the x axis. You can see this in motion on CodePen (ES5 approach; ignore the boats).

  • How should this simple universe be organized into classes? One "Wave" class with a constructor and draw method, and another "Waves" class with an animate method?



  • Should the velocity (same for all waves) be stored at the Wave, or Waves level?



  • Is the static config() method a good idea, or should each property be separate? Let's assume for simplicity we won't build an interface to modify these properties at runtime, but they are to be grouped at the top of the class for easy editing in the code.



  • Is it better to use just one class, Waves, and have a createWave method which the constructor will call \$n\$ times to create all waves? I don't imagine ever needing to create a Wave in isolation from its river / Waves.



Here's the first stab at this in ES6:



'use strict';

class Wave {
static config() {
const waveBaseLength = 5;
return {
color: '#4F5E5B',
waveLengths: [waveBaseLength, waveBaseLength 7, waveBaseLength 15],
velocity: 5
}
}

constructor(x, y, velocity) {
this.x = x;
this.y = y;
let waveLengths = Wave.config().waveLengths;
this.l = waveLengths[Math.floor(Math.random() * waveLengths.length)];
this.velocity = velocity || 0.5; // Chrome currently fails at
velocity=0.5` in the constructor decla

Solution

This is really cool! I do have a few small tips though.

First off, rather than creating an entire function, in this case, config, that returns configuration data, I'd store it as a public getter, like this:

class Wave {
  static get CONFIG() {
    const waveBaseLength = 5;
    return {
      color: '#4F5E5B',
      waveLengths: [waveBaseLength, waveBaseLength * 7, waveBaseLength * 15],
      velocity: 5
    }
  }
}


Using this, you can do stuff like Wave.CONFIG.color, and drop the un-needed parentheses.

Finally, you have a few, not so great variable names. A few include l and n. Names like these should be expanded for clarity and readability.

Code Snippets

class Wave {
  static get CONFIG() {
    const waveBaseLength = 5;
    return {
      color: '#4F5E5B',
      waveLengths: [waveBaseLength, waveBaseLength * 7, waveBaseLength * 15],
      velocity: 5
    }
  }
}

Context

StackExchange Code Review Q#96424, answer score: 2

Revisions (0)

No revisions yet.