2013-05-25

Canvas, circular motions and networks

Intro

Here's another post in the "canvas drawing series". The previous posts usually had only one example, this one will be about three examples. You can look up the basics of drawing etc. in the previous posts:

  1. Canvas Crossroad
  2. Canvas Balloons
  3. Canvas Bus
  4. Canvas Trains

Oil pump jack

The parts are named after this wiki page describing the functioning of an oil pump jack. On every animation frame the angle of an engine is increased by a fixed amount making the circular motions of the engine. The engine rotation is pretty simple and is using just the cos and the sin mathematical function.

Determining the height of a walking beam is a bit more complicated and needs to be done in two steps. In the first one the joint on the engine crank is found by this code:

  var crankJoinX = engineX + Math.cos(angle) * engineCrankL * 0.7;
  var crankJoinY = engineY + Math.sin(angle) * engineCrankL * 0.7;
The second is to determine the pitman arm position. With engineX and engineY being the center of the rotation for the crank. The pitman arm always has a fixed x coordinate. With having a fixed rod length the height is determined by this formula:
  var pitmanY = crankJoinY - Math.sqrt(Math.pow(rodLength, 2) 
   - Math.pow(crankJoinX - engineX, 2));

Pump jack's head has a certain curve enabling it to always pull the polished rod straight up. The math behind it is a bit more complicated than calculating the pitman arm position:

  ctx.arc(
   samsonPostX,
   samsonPostY,
   beamHalfLength + headWidth,
   Math.asin((samsonPostY - pitmanY) / beamHalfLength),
   Math.asin((samsonPostY - pitmanY + headNoseHeight) / beamHalfLength)
  );

Oil pump jack - Codepen
Oil pump jack - GitHub

Particle Tornado

This one seems to be a very popular example. It even got mentioned on twitter by David Walsh:

Believe it or not it's actually quite easy to code. Everything we need is contained in this function:

  Particle.prototype.draw = function () {

   // change particle position
   this.angle += angleSpeed;
   this.h -= verticalSpeed;

   // if the particle is outside of canvas
   //make it appear back on random position
   if (this.h < 0 || this.h > canvas.height) {
    this.h = Math.floor(canvas.height * Math.random());
   }

   ctx.beginPath();
   ctx.fillStyle = singlecolor ? defaultColor : this.color;
   // single line of code makes it look like 3d
   var sizeFactor = 0.5 + (Math.sin(this.angle) + 1) / 2;
   ctx.arc(
    canvas.width / 2 + Math.cos(this.angle) 
     * (canvas.height - this.h) / widthFactor,
    this.h,
    particleSize * sizeFactor, 0, Math.PI * 2);
   ctx.fill();
  };
The rest of the code is just fancy stuff mentioned in the previous posts.

Particle Tornado - Codepen
Particle Tornado - GitHub

Neurons

The neurons have random placing on the canvas. But connecting them at random makes a very "noisy" and ugly example. To avoid this mess a simple algorithm is used. One by one we're finding the nearest neuron having no connection to the current neuron:

  for (i = 0; i < this.neurons.length; i++) {
   for (var j = 0; j < this.neurons.length; j++) {

    if (i !== j) {

     // take first neuron not being the current one
     if (typeof pickedNeuron === 'undefined') {
      pickedNeuron = this.neurons[j];
     }

     // compare the distances to other neurons
     if (distance(this.neurons[i], this.neurons[j]) <
       distance (this.neurons[i], pickedNeuron)) {
       
      if (this.neurons[j].soma && this.neurons[j].id !== i) {
       pickedNeuron = this.neurons[j];
      }
     }
    }

   }
   this.neurons[i].soma = pickedNeuron;
   pickedNeuron = undefined;
  }

Every neuron has its own counter making it switch between active and inactive state. To make the example more interesting a firing neuron also fires the neuron connected to it.

Neurons - Codepen
Neurons - GitHub