Skip to content

Instantly share code, notes, and snippets.

@SevenChan07
Created November 13, 2018 12:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SevenChan07/843b6752923fd51c44b5ba152f33843d to your computer and use it in GitHub Desktop.
Save SevenChan07/843b6752923fd51c44b5ba152f33843d to your computer and use it in GitHub Desktop.
Infinity loader on canvas
<canvas></canvas>
<div class="links">
Check out my other <a href="https://codepen.io/kiyutink/" target="_blank">pens</a> and follow me on <a href="https://twitter.com/kiyutin_k" target="_blank">twitter</a>!
</div>
const parameters = {
particleRadius: 2,
speed: 0.5,
deceleration: 0.05,
maxLife: 1200,
particlesCount: 4,
tIncrement: 0.15,
stepPeriod: 30
};
const canvas = document.querySelector('canvas');
const canvasCtx = canvas.getContext('2d');
const setCanvasSize = () => {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
};
window.addEventListener('resize', setCanvasSize);
setCanvasSize();
let particles = [];
let lastRafCall = 0;
class Particle {
constructor(x, y) {
const {maxLife, radius, speed, colors, deceleration} = parameters;
this.framesCount = Math.ceil(maxLife / (1000 / 60));
this.framesRendered = 0;
this.opacity = 1;
this.opacitySpeed = 1 / this.framesCount;
this.x = x;
this.y = y;
this.deceleration = deceleration; //percentage of speed lost each frame
if (Math.random() > 0.8) {
this.color = '#BB3BA7';
}
else {
this.color = '#fff';
}
this.speedX = random(-speed, speed);
this.speedY = random(-speed, speed);
this.radius = parameters.particleRadius;
this.radiusSpeed = this.radius / this.framesCount;
}
frame(canvasCtx) {
canvasCtx.fillStyle = this.color;
canvasCtx.globalAlpha = this.opacity;
canvasCtx.beginPath();
canvasCtx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI);
canvasCtx.fill();
this.opacity-= this.opacitySpeed;
if (this.opacity < 0) {
this.opacity = 0;
}
this.x += this.speedX;
this.y += this.speedY;
this.speedX *= (1 - this.deceleration);
this.speedY *= (1 - this.deceleration);
this.radius = this.radius - this.radiusSpeed;
if (this.radius < 0) {
this.radius = 0;
}
this.framesRendered++;
return this.framesCount >= this.framesRendered;
}
}
const particlesFrame = timestamp => {
if (timestamp - lastRafCall > 1000 / 65) {
canvasCtx.clearRect(0, 0, canvas.width, canvas.height);
particles = particles.filter(p => p.frame(canvasCtx));
lastRafCall = timestamp;
}
window.requestAnimationFrame(particlesFrame);
};
particlesFrame();
const random = (min, max) => {
return min + Math.random() * (max - min);
};
const addParticlesAtPoint = (x, y) => {
const newParticles = (new Array(parameters.particlesCount)).fill(0).map(() => new Particle(x, y));
particles.push(...newParticles);
};
const getPositionOnCanvas = (x, y) => ({
x: x + window.innerWidth / 2,
y: y + window.innerHeight / 2
});
const addParticlesOnAxis = (x, y) => {
const {x: realX, y: realY} = getPositionOnCanvas(x, y);
addParticlesAtPoint(realX, realY);
};
let t = 0;
const getScreenScale = () => {
return Math.min(window.innerWidth, window.innerHeight) / 5;
};
const addParticlesAtNextPoint = () => {
if (!document.hidden) {
const scale = 2 / (3 - Math.cos(2 * t)) * getScreenScale();
const x = scale * Math.cos(t);
const y = scale * Math.sin(2 * t) / 2;
t += parameters.tIncrement;
addParticlesOnAxis(x, y);
}
setTimeout(addParticlesAtNextPoint, parameters.stepPeriod);
};
addParticlesAtNextPoint();
const LINKS_APPEARANCE_DELAY = 5000;
const addTwitterLinkParticles = () => {
const count = 30;
const y = window.innerHeight - 15;
canvasCtx.font = '16px Roboto';
const {width} = canvasCtx.measureText('Check out my other pens and follow me on twitter!');
const firstX = (window.innerWidth - width) / 2;
const lastX = window.innerWidth - firstX;
const step = (lastX - firstX) / count;
const particlePositions = new Array(count).fill(0).map((el, idx) => ({
x: firstX + step * idx,
y
}));
particlePositions.unshift({
x: firstX - step,
y
});
particlePositions.push({
x: lastX + step,
y
});
particlePositions.forEach((pos, i) => {
setTimeout(() => addParticlesAtPoint(pos.x, pos.y), i * 20);
});
document.querySelector('.links').classList.add('links--visible');
};
setTimeout(addTwitterLinkParticles, LINKS_APPEARANCE_DELAY);
*, *:before, *:after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-size: 0;
user-select: none;
}
canvas {
background-color: black;
}
.links {
color: white;
font-family: Roboto, sans-serif;
font-weight: 300;
font-size: 16px;
position: absolute;
bottom: 5px;
text-align: center;
width: 100%;
background-color: transparent;
opacity: 0;
transition: opacity 0.5s linear;
transition-delay: 0.5s;
@media (max-width: 370px) {
font-size: 13px;
}
&--visible {
opacity: 1;
}
}
a {
color: white;
&:active, &:hover {
color: #BB3BA7;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment