<div id="container">
<canvas id="mycanvas" width="640" height="480">
</canvas>
  
<div>
  <div>Add a new Particle</div>
  <button class="controller" onclick="addNewRandomParticle()"> ADD </button>
  
  <div>Add 100 new Particles</div>
  <button class="controller" onclick="for(let i=0; i<100; i++){addNewRandomParticle()}"> ADD </button>
  
  <div>Add 1000 new Particles</div>
  <button class="controller" onclick="for(let i=0; i<1000; i++){addNewRandomParticle()}"> ADD </button>
  
  <div>Clear Scene Graph</div>
  <button class="controller" onclick="sceneGraph = []"> CLEAR </button>
  
  <div> Total Particles: <span id="partCount">0</span> </div>
  </div>
</div>
#container {
  display: flex;
  flex-direction: row;
}

button.controller {
  padding: 5px 15px;
  min-width: 122px;
  border-radius: 5px;
  border: none;
  font-family: 'helvetica';
  background: #7371e0;
  color: white
}
let sceneGraph = [];
let globalTime = 0;
let initTime = 0;

class Particle {
  constructor(cx, cy, r, fill, orbit) {
    this.cx = cx;
    this.cy = cy;
    this.r = r;
    this.fill = fill;
    this.orbit = orbit;
  }

  update(ctx) {
    if(this.orbit){
      let {x,y} = this.orbit.update();
      this.cx = x;
      this.cy = y;
    }
    ctx.fillStyle = this.fill;
    ctx.beginPath();
    ctx.arc(this.cx, this.cy, this.r, 0, 2 * Math.PI);
    ctx.closePath();
    ctx.fill();
  }
}

/**
Orbiter is simply a form of parametric equation, given a parameter t, it will spew out a co-ordinate x,y
*/
class Orbit {
  constructor(x, y, r, lifeTime, initPos) {
    this.x = x;
    this.y = y;
    this.r = r;
    this.lifeTime = lifeTime;
    this.curPos = initPos % (2*Math.PI);
    this.initPos = initPos % (2*Math.PI);
    this.initTime = globalTime;
  }

  update() {
    // for x,y co-ordinate we need the angle theta, which is curPos,
    // it completes 2PI radians (360deg) in lifeTime time
    let curTime = globalTime;
    // we need the difference to calculate the curPos
    let deltaTime = curTime - this.initTime;
    // in N ms, it completes 2Pi radians
    // in 1ms, it completes 2Pi/N radians
    // in k ms, it completes 2*k*Pi/N radians
    let curPos = this.initPos + (2 * deltaTime * Math.PI) / this.lifeTime;
    // since it is cyclic, i.e. it completes a cycle, we can simply take a modulo
    this.curPos = curPos % (2 * Math.PI);

    // we have the angle, thus, we can find the x,y co-ordinates using formulas
    // x(theta) = R*sin(theta) + cx
    // y(theta) = R*sin(theta) + cy
    let xVal = this.r * Math.cos(this.curPos) + this.x;
    let yVal = this.r * Math.sin(this.curPos) + this.y;
    return { x: xVal, y: yVal };
  }
}

function redrawSurface() {
  let canvas = document.getElementById("mycanvas");
  globalTime = Date.now() - initTime;

  let ctx = canvas.getContext("2d");
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  for (obj of sceneGraph) {
    obj.update(ctx);
  }
  document.getElementById("partCount").innerHTML = sceneGraph.length.toString();
  requestAnimationFrame(redrawSurface);
}

function addNewRandomParticle() {
  // generate random parameters for particle
  let x = Math.floor(Math.random() * 640);
  let y = Math.floor(Math.random() * 480);
  let r = Math.ceil(Math.random() * 4 + 1);
  let color = `rgb(${Math.ceil(Math.random(0) * 255)}, ${Math.ceil(
    Math.random(0) * 255
  )}, ${Math.ceil(Math.random(0) * 255)})`;
  
  // generate random orbit for particle
  let Ox = Math.floor(Math.random() * 540) + 50;
  let Oy = Math.floor(Math.random() * 380) + 50;
  let Or = Math.ceil(Math.random()*150) + 100;
  let Olt = Math.ceil(Math.random() * 25000) + 1000;
  let Oip = Math.floor(Math.random() * 2 * Math.PI);
  
  let orbit = new Orbit(Ox, Oy, Or, Olt, Oip);
  let part = new Particle(x, y, r, color, orbit);
  sceneGraph.push(part);
  console.log(part);
}


window.onload = function () {
  let canvas = document.getElementById("mycanvas");
  let ctx = canvas.getContext("2d");
  initTime = Date.now();
  
  for(let i=0; i<100; i++){
    addNewRandomParticle();
  }
  requestAnimationFrame(redrawSurface);
};

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.