<canvas id="canvas"> Fallback text </canvas>
#canvas {
background: black;
}
body {
margin: 0px;
}
/* Next time, update the colors */
/* pass in lifetime to the drawCircle method to make it fade over time */
const COLORS = ["red", "orange", "turquoise", "blue", "purple", "pink", "yellow"];
var utils = (function() {
return {
randomPositiveOrNegative: function () {
return (Math.round(Math.random()) * 2 - 1);
},
getRandomArbitrary: function (min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
};
})();
const canvas = document.getElementById("canvas");
const context = canvas.getContext("2d");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
let formations = [];
class Particle {
constructor(x, y, angle, speed, color) {
this.x = x;
this.y = y;
this.angle = angle;
this.speed = speed;
this.color = color;
this.radius = 10;
}
drawCircle = () => {
context.beginPath();
context.arc(this.x, this.y, this.radius, 0, 2 * Math.PI);
// this.gradient = context.createRadialGradient(this.x, this.y, 1, this.x, this.y, this.radius);
// this.gradient.addColorStop(0.15, this.color);
// this.gradient.addColorStop(0.95, oklch(60% 0.15 50));
context.fillStyle = this.color;
context.fill();
}
moveCircle = () => {
this.x = this.x + (this.speed * Math.cos(this.angle));
this.y = this.y + (this.speed * Math.sin(this.angle));
this.angle += .03;
// this.angle = this.angle > (2 * Math.PI) ? 0 : this.angle;
/*this.x = this.x + (this.speed * Math.cos(this.angle));
this.y = this.y + (this.speed * Math.sin(this.angle));
this.angle += .01;
this.angle = this.angle > (2 * Math.PI) ? 0 : this.angle;*/
}
}
class Formation {
constructor(x, y, particleCount, speed) {
this.particleCount = particleCount;
this.speed = utils.getRandomArbitrary(1,4);
this.particles = [];
this.lifetime = 0;
this.drawIntervals = 1;
this.currDrawInterval = 0;
this.shouldDraw = true;
this.color = COLORS[utils.getRandomArbitrary(0, COLORS.length - 1)];
for (let i = 0; i < this.particleCount ; i++ ) {
const radianAngle = 2/ this.particleCount * Math.PI * (i + 1);
this.particles.push(new Particle(x, y, radianAngle, this.speed, this.color));
}
}
moveFormation() {
for (let i = 0; i < this.particleCount ; i++ ) {
const particle = this.particles[i];
if (this.shouldDraw) {
particle.drawCircle();
}
particle.moveCircle();
}
this.lifetime++;
if (this.currDrawInterval > this.drawIntervals ) {
this.currDrawInterval = 0;
this.shouldDraw = !this.shouldDraw;
} else {
this.currDrawInterval++;
}
}
getLifetime() {
return this.lifetime;
}
}
function offsetSpirals(spiralCount, x, y) {
setTimeout(function() {
// main logic
console.log(`count ${spiralCount}`);
createSpiral(randomX, randomY)
// call again if spiralCount > 0
if (--spiralCount) offsetSpirals(spiralCount);
}, 400)
}
async function createMultipleSpirals() {
const numberOfSpirals = utils.getRandomArbitrary(3,7);
// console.log(numberOfSpirals)
randomX = utils.getRandomArbitrary(canvas.width/5,canvas.width*4/5);
randomY = utils.getRandomArbitrary(canvas.height/5,canvas.height*4/5);
// for (let i = 0; i < numberOfSpirals ; i++ ) {
// createSpiral(randomX, randomY)
// }
offsetSpirals(numberOfSpirals, randomX, randomY);
}
const createSpiral = (x, y) => {
const numberOfParticles = utils.getRandomArbitrary(5,20);
formations.push(new Formation(x, y, numberOfParticles));
}
const handleClick = event => {
const x = event.pageX;
const y = event.pageY;
createSpiral(x, y);
}
const animate = () => {
// clear context
//context.clearRect(0, 0, canvas.width, canvas.height);
// instead of completely clearing, only partially clear so it shows a little of past frames
context.globalAlpha = 0.1;
context.fillStyle = "black";
context.fillRect(0, 0, canvas.width, canvas.height);
context.globalAlpha = 1.0;
for (let i = 0; i < formations.length; i++) {
// draw particles and move them along
const formation = formations[i];
formation.moveFormation();
const MAX_LIFETIME = 500;
if (formation.getLifetime() > MAX_LIFETIME) {
// then remove the formation (using i, its index)
formations = formations.slice(0, i).concat(formations.slice(i+1));
}
}
requestAnimationFrame(animate);
}
animate();
setInterval(createMultipleSpirals, 5000);
canvas.addEventListener('click', handleClick);
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.