Yash Sharma
Yash Sharma

Reputation: 31

how to decrease speed of canvas animation?

I am creating an animation using java script & canvas. I am using a fiddle as a reference, currently object are generating randomly & falling from top right corner to bottom left corner which is okay. but the issue is speed the objects are generating & falling in high speed. I want to make animation flow little slow & smooth. I am new canvas programming, any help will be very useful.

(function() {
  var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame ||
    function(callback) {
      window.setTimeout(callback, 1000 / 60);
    };
  window.requestAnimationFrame = requestAnimationFrame;
})();

var particleArr = [],
  canvas = document.getElementById("canvas"),
  ctx = canvas.getContext("2d"),
  flakeCount = 700,
  mouseX = -100,
  mouseY = -100,
  xMultiplier = 0.015


canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

function getRandomColor() {
  // Random Color Generate
  const colorArr = ["rgba(215,88,69, 1)", "rgba(117, 161, 199, 1)"]; // Blue & Orange Color
  const randomColor = colorArr[Math.floor(Math.random() * colorArr.length)];

  return randomColor;
}

function flow() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  for (var i = 0; i < flakeCount; i++) {
    var flake = particleArr[i],
      x = mouseX,
      y = mouseY,
      minDist = 150,
      x2 = flake.x,
      y2 = flake.y;

    var dist = Math.sqrt((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y)),
      dx = x2 - x,
      dy = y2 - y;

    if (dist < minDist) {
      var force = minDist / (dist * dist),
        xcomp = (x - x2) / dist,
        ycomp = (y - y2) / dist,
        deltaV = force / 2;

      flake.velX -= deltaV * xcomp;
      flake.velY -= deltaV * ycomp;

    } else {
      flake.velX *= .98;
      if (flake.velY <= flake.speed) {
        flake.velY = flake.speed
      }
      flake.velX += Math.cos(flake.step += .05) * flake.stepSize;
    }

    ctx.fillStyle = getRandomColor();

    flake.y += flake.velY;
    flake.x += flake.velX;

    if (flake.y >= canvas.height || flake.y <= 0) {
      reset(flake);
    }

    if (flake.x >= canvas.width || flake.x <= 0) {
      reset(flake);
    }

    ctx.beginPath();
    ctx.arc(flake.x, flake.y, flake.size, 0, Math.PI * 2);
    ctx.fill();
  }
  requestAnimationFrame(flow);

};

function reset(flake) {
  let temp = (Math.random() * 1) + 0.5;
  flake.x = canvas.width;
  flake.y = 50;
  flake.size = (Math.random() * 3) + 5;
  flake.speed = (Math.random() * 7) + 0.5;
  flake.velY = flake.speed;
  flake.velX = -xMultiplier * canvas.width * temp;
  // flake.opacity = (Math.random() * 0.5) + 0.3;
}

function init() {
  for (var i = 0; i < flakeCount; i++) {
    var x = canvas.width,
      y = 50,
      size = (Math.random() * 3) + 5,
      // speed = (Math.random() * 1) + 0.5;
      speed = 0;
    // opacity = (Math.random() * 0.5) + 0.3;

    particleArr.push({
      speed: speed,
      velY: speed,
      velX: -xMultiplier * canvas.width * speed,
      x: x,
      y: y,
      size: size,
      stepSize: (Math.random()) / 30,
      step: 0,
      angle: 360
      // opacity: opacity
    });
  }

  flow();
};

canvas.addEventListener("mousemove", function(e) {
  mouseX = e.clientX,
    mouseY = e.clientY
});

window.addEventListener('resize', onWindowResize, false);

function onWindowResize() {

  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
}

init();
canvas {
  background-color: #000000 !important;
}

body {
  margin: 0;
  overflow: hidden;
}
<canvas id="canvas"></canvas>

Upvotes: 0

Views: 1030

Answers (3)

Blindman67
Blindman67

Reputation: 54039

Could not work out what it was you wanted to slow down as there are several FX and interactions in the code.

I rewrote from the ground up as your code is a little old school.

Rather than play with the constants you had OI added the global variable rate (at the ver top of the source) is used to control the rate at which the animation plays, including the user interaction.

I have added two button to slow or speed up the animation.

Hope this helps :)

var rate = 1;
slower.addEventListener("click", () => rate *= 1 / 1.2);
faster.addEventListener("click", () => rate *= 1.2);

const flakes = [], flakeCount = 700, xMultiplier = 0.015;
const minDist = 150,  minDistSqr = minDist * minDist;
const colors = ["#F99","#F83","#AF9","#ED9","#AC8","#FA9" ];
const ctx = canvas.getContext("2d");

const mouse = {x: -100, y: -100};
const randPick = (arr, len = arr.length) => arr[Math.random() * len | 0];
Math.rand = (min, range) => Math.random() * range + min;
   
function Flake() {
  this.reset();
  this.stepSize = Math.random() / 30;
  this.step = 0;
}
Flake.prototype = {
  reset() {
    this.x = canvas.width;
    this.y = 50;
    this.size = Math.rand(5, 3);
    this.speed = Math.rand(0.5, 7);
    this.velY = this.speed;
    this.velX = -xMultiplier * canvas.width * Math.rand(0.5, 1);
    this.col = randPick(colors);
  },
  draw() {
    ctx.fillStyle = this.col;
    const s = this.size, sh = -s / 2;
    ctx.fillRect(this.x + sh, this.y + sh, s, s);
  },
  update(w, h) {
    const f = this;
    const dx = f.x - mouse.x;
    const dy = f.y - mouse.y;
    const distSqr = dx * dx + dy * dy;
    if (distSqr < minDistSqr) {
      const deltaV = 2 * minDist * rate / distSqr ** 1.5;
      f.velX -= deltaV * dx;
      f.velY -= deltaV * dy;
    } else {
      f.velX -= 0.1 * rate * f.velX;
      if (f.velY <= f.speed ) { f.velY = f.speed }
      f.velX += Math.cos(f.step += 0.05 * rate) * f.stepSize  * rate;
    }
    f.y += f.velY * rate;
    f.x += f.velX * rate;
    if (f.y >= h || f.y <= 0 || f.x >= w || f.x <= 0) { this.reset() }
    else { this.draw() }
  }
};

init();
mainLoop();
function mainLoop() {
  if (innerWidth !== canvas.width || innerHeight !== canvas.height) { resize() }
  else { ctx.clearRect(0, 0, canvas.width, canvas.height) }
  for (const f of flakes) { f.update(canvas.width, canvas.height) }
  requestAnimationFrame(mainLoop);
}

function init() {
  var i = flakeCount;
  while (i--) { flakes.push(new Flake()) }
}

canvas.addEventListener("mousemove", e => { mouse.x = e.clientX; mouse.y = e.clientY });
function resize() { canvas.width = innerWidth;  canvas.height = innerHeight }
canvas {
  background-color: #000;
}

body {
  margin: 0;

}
.buttons {
  position: absolute;
  top: 12px;
  left: 12px;
  color: #000;
  background-color: #AAA; 
}
.buttons > div {
  margin: 3px;
  padding: 3px;
  background-color: #EEE;
  cursor: pointer;
}
.buttons > div:hover {
  background-color: #DEF; 
}
<canvas id="canvas"></canvas>
<div class = "buttons">
<div id="slower">Slower</div>
<div id="faster">Faster</div>
</div>

Upvotes: 1

Rio Weber
Rio Weber

Reputation: 3143

https://jsfiddle.net/z6r8h5de/

if the issue is there are too many flakes on the screen, turn the count down from 700.

flakeCount = 100,

Upvotes: 0

georgedum
georgedum

Reputation: 501

That requestAnimationFrame() function that calls flow() every frame is designed to run as fast as possible for whoever's computer it's running on. I wouldn't mess with your actual render loop.

Try messing with the flake.speed or the xMultiplier. Those are two of the main variables affecting the speed of your particles. You can see how each time through the flow() loop you're adjusting each particle's position based on their velocity properties and position. Then finally rendering the arc with ctx.arc(flake.x, flake.y, flake.size, 0, Math.PI * 2);

So any variable passed to ctx.arc() affects the particle's position. And many of those variables are recalculated each time through the loop.

I'm no expert here, but maybe try fiddling with your variables.

https://codepen.io/nitwit/pen/XWXJNaJ

Upvotes: 0

Related Questions