Skip to content

Instantly share code, notes, and snippets.

@SunRed
Last active July 4, 2022 20:05
Show Gist options
  • Save SunRed/a3c5c1ed3f835fd22c465751d3f093b5 to your computer and use it in GitHub Desktop.
Save SunRed/a3c5c1ed3f835fd22c465751d3f093b5 to your computer and use it in GitHub Desktop.
Draw connected particles onto a canvas
const c = document.getElementById("particles");
const ctx = c.getContext("2d");
const maxParticles = 100 * (1/Math.pow(window.devicePixelRatio, .75));
const size = 2;
const r = size/2;
const cft = 1000/60;
let previous, stepratio;
let w, h, d;
resize();
const particles = [];
const mouse = {};
mouse.x = w/2;
mouse.y = h/2;
function random(min, max) {
return (Math.random() * (max - min)) + min;
}
function getDistance(x1, y1, x2, y2) {
return Math.sqrt( (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) );
}
function resize() {
w = c.width = window.innerWidth;
h = c.height = window.innerHeight;
d = (w/9)*Math.pow(window.devicePixelRatio, .75);
}
function moveMouse(e) {
mouse.x = e.touches ? e.touches[0].clientX : e.clientX;
mouse.y = e.touches ? e.touches[0].clientY : e.clientY;
}
function P() {}
P.prototype = {
init: function() {
this.x = random(0, (w - size));
this.y = h + random(0, 20);
this.vx = 0;
this.vy = random(-1, -2);
this.alpha = 0;
this.active = false;
},
draw: function() {
const hue = 60 + 120 * (h - this.y)/h;
const lineWidth = r/(2*(1/stepratio));
ctx.fillStyle = this.active ? "hsla("+(hue+30)+", 100%, 50%, 1)" : "hsla("+hue+", 100%, 50%, .8)";
ctx.strokeStyle = this.active ? "hsla("+(hue+30)+", 100%, 50%, .5)" : "hsla("+hue+", 100%, 50%, "+this.alpha+")";
ctx.globalCompositeOperation = this.active ? "lighter" : "source-over";
ctx.beginPath();
ctx.arc(this.x + r, this.y + r, r, 0, 2 * Math.PI, false);
ctx.fill();
for(const i in particles) {
const p = particles[i];
const pd = getDistance(this.x, this.y, p.x, p.y);
if(pd < d) {
ctx.lineWidth = lineWidth * 1/(Math.max(1,(pd-d*.8)/5));
ctx.beginPath();
ctx.moveTo(this.x + r, this.y + r);
ctx.lineTo(p.x + r, p.y + r);
ctx.stroke();
}
}
this.update();
},
update: function() {
this.active = (getDistance(this.x, this.y, mouse.x, mouse.y) < 80) ? true : false;
this.x += this.vx;
this.y += this.vy * stepratio;
this.vx *= 1.15;
this.alpha += .0005 * stepratio * window.devicePixelRatio;
if(this.y < h *.8 && Math.random() > .5){
this.vx = random(-1, 1) * stepratio;
this.vy -= .05 * stepratio;
}
if(this.y + 50 < 0){
this.init();
}
}
}
function setup() {
for(let i=0; i<maxParticles; i++) {
(function(x) {
setTimeout(function() {
const p = new P();
p.init();
particles.push(p);
}, x * 100)
})(i);
}
window.addEventListener("resize", resize);
window.addEventListener("mousemove", moveMouse);
window.addEventListener("touchstart", moveMouse);
window.addEventListener("touchmove", moveMouse);
previous = performance.now();
}
function anim(timestamp) {
previous = Math.max(timestamp - 100, previous);
stepratio = (timestamp - previous)/cft;
ctx.fillStyle = "rgba(0,0,0," + (.2 * stepratio) +")";
ctx.globalCompositeOperation = "source-over";
ctx.fillRect(0,0,w,h);
for(const i in particles) {
const p = particles[i];
p.draw();
}
previous = timestamp;
window.requestAnimationFrame(anim);
}
setup();
window.requestAnimationFrame(anim);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment