Skip to content

Instantly share code, notes, and snippets.

@Sheraff
Last active July 28, 2021 18:22
Show Gist options
  • Select an option

  • Save Sheraff/a6f2894cdb4f8d2fcf06e0dcd4632fb2 to your computer and use it in GitHub Desktop.

Select an option

Save Sheraff/a6f2894cdb4f8d2fcf06e0dcd4632fb2 to your computer and use it in GitHub Desktop.
test particles behavior
{
"scripts": [],
"styles": []
}
<div id="container"></div>
const MIN_DELAY = 100
const container = document.getElementById('container')
const canvas = document.createElement('canvas')
const { width, height } = container.getBoundingClientRect()
canvas.width = width
canvas.height = height
const ctx = canvas.getContext('2d')
container.appendChild(canvas)
const particles = []
ctx.filter = 'blur(1px)'
loop(ctx, particles)
let make = false
async function waitForGenerateParticle() {
await new Promise(resolve => setTimeout(resolve, MIN_DELAY))
if (make) {
particles.push(new Placeholder(x, y))
// make = false
}
waitForGenerateParticle()
}
waitForGenerateParticle()
let x, y
container.addEventListener('pointermove', (e) => {
x = e.offsetX
y = e.offsetY
})
container.addEventListener('pointerenter', () => make = true)
container.addEventListener('pointerleave', () => make = false)
container.addEventListener('pointerdown', () => {
particles.forEach((particle) => {
oscillatorToLinear(particle, x, y)
})
lastParticle = performance.now() + 500
})
// animation loop
function loop(ctx, particles) {
requestAnimationFrame((timestamp) => {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height)
particles.forEach((particle, i) => {
if (particle instanceof Particle) {
particle.update(timestamp)
if (particle.opacity === 0) {
particles.splice(i, 1)
} else {
particle.draw(ctx)
}
} else if (particle instanceof Placeholder) {
particles.push(new Particle(particle.x, particle.y, timestamp))
particles.splice(i, 1)
}
})
loop(ctx, particles)
})
}
class Placeholder {
constructor(x, y) {
this.x = x
this.y = y
}
}
class Particle {
constructor(x, y, time) {
this.start = time
this.last = time
this.type = Oscillator
this.pointX = new Oscillator(x + Math.random() * 30 - 15)
this.pointY = new Oscillator(y + Math.random() * 30 - 15)
this.decay = 0.005
this.opacity = 1
this.radius = Math.random() * .75 + .75
}
update(time) {
const total = time - this.start
const delta = (time - this.last) / 10
this.x = this.pointX.update(delta, total)
this.y = this.pointY.update(delta, total)
this.opacity -= this.decay * delta
if (this.opacity < 0) {
this.opacity = 0
}
this.last = time
}
draw(ctx) {
ctx.beginPath()
ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI)
ctx.globalAlpha = this.opacity
ctx.fillStyle = `lime`
ctx.fill()
}
}
class Oscillator {
constructor(value) {
this.math = Math.random() < .5 ? Math.sin : Math.cos
this.period = Math.random() * 300 + 200
this.amplitude = Math.random() * 4 + 4
this.anchor = value
}
update(_, time) {
return this.anchor + this.math(time / this.period) * this.amplitude
}
}
class Linear {
constructor(value, speed) {
this.value = value
this.speed = speed
}
update(delta) {
return this.value += delta * this.speed
}
}
function oscillatorToLinear(particle, x, y) {
if (particle.type !== Oscillator) {
return
}
particle.type = Linear
const dx = particle.x - x
const dy = particle.y - y
const total = Math.abs(dx) + Math.abs(dy)
const speed = Math.max(.6, (Math.random() * 7 + 10) / total)
particle.start = particle.last
particle.decay = 0.01
particle.pointX = new Linear(particle.x, speed * dx / total)
particle.pointY = new Linear(particle.y, speed * dy / total)
particle.opacity = 1
}
#container {
height: 500px;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment