parent
6e66965193
commit
abc8c178e6
@ -0,0 +1,39 @@ |
||||
export default class Particle { |
||||
constructor(canvas, accel) { |
||||
this.init(canvas, accel) |
||||
} |
||||
|
||||
init(canvas, accel) { |
||||
this.x = Math.random() * canvas.width |
||||
this.y = Math.random() * canvas.height |
||||
this.vx = accel * (Math.random() - Math.random()) |
||||
this.vy = accel * (Math.random() - Math.random()) |
||||
} |
||||
|
||||
step(parent) { |
||||
// move towards every attractor
|
||||
// at a speed inversely proportional to distance squared
|
||||
// (much slower when further away, very fast when close)
|
||||
for (const a of parent.attractors) { |
||||
// calculate the square of the distance
|
||||
// from this particle to the current attractor
|
||||
const dx = a.x - this.x |
||||
const dy = a.y - this.y |
||||
const d2 = dx * dx + dy * dy |
||||
if (d2 > 0.1) { |
||||
// make sure we don't divide by zero
|
||||
// accelerate towards each attractor
|
||||
this.vx += parent.accel * dx / d2 |
||||
this.vy += parent.accel * dy / d2 |
||||
} |
||||
} |
||||
// move by the velocity
|
||||
this.x += this.vx |
||||
this.y += this.vy |
||||
// scale the velocity back for the next frame
|
||||
this.vx *= parent.damp |
||||
this.vy *= parent.damp |
||||
// draw particle
|
||||
parent.ctx.fillRect(this.x, this.y, 0.5, 0.5) |
||||
} |
||||
} |
||||
@ -0,0 +1,65 @@ |
||||
import Particle from './Particle' |
||||
|
||||
export default class FluxRay { |
||||
constructor(canvas) { |
||||
this.canvas = canvas |
||||
this.canvas.style.setProperty('background-color', 'black') |
||||
this.ctx = canvas.getContext('2d') |
||||
this.frame = 0 |
||||
this.damp = 0.00002 // remember a very small amount of the last direction
|
||||
this.accel = 100 // move very quickly
|
||||
this.attractors = Array.from({length: 8}, () => new Particle(canvas, this.accel)) |
||||
this.particles = Array.from({length: 1000}, () => new Particle(canvas, this.accel)) |
||||
this.rAF = null |
||||
this.stopSign = false |
||||
this.loop = this.loop.bind(this) |
||||
this.start() |
||||
} |
||||
|
||||
start() { |
||||
this.resizeObserver = new ResizeObserver(() => this.resize()) |
||||
this.resizeObserver.observe(this.canvas) |
||||
this.resize() |
||||
this.loop() |
||||
} |
||||
|
||||
stop() { |
||||
if (this.resizeObserver) { |
||||
this.resizeObserver.disconnect() |
||||
this.resizeObserver = null |
||||
} |
||||
this.stopSign = true |
||||
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height) |
||||
this.canvas.style.removeProperty('background-color') |
||||
} |
||||
|
||||
loop() { |
||||
if (this.stopSign) { |
||||
this.rAF && window.cancelAnimationFrame(this.rAF) |
||||
return |
||||
} |
||||
this.draw() |
||||
this.rAF = window.requestAnimationFrame(this.loop) |
||||
} |
||||
|
||||
draw() { |
||||
if (this.frame++ < 1000) { |
||||
this.particles.forEach(p => p.step(this)) |
||||
} |
||||
} |
||||
|
||||
reset() { |
||||
this.ctx.globalCompositeOperation = "source-over" |
||||
this.ctx.fillStyle = "#321" |
||||
this.ctx.globalCompositeOperation = "lighter" |
||||
this.particles.forEach(p => p.init(this.canvas, this.accel)) |
||||
this.attractors.forEach(a => a.init(this.canvas, this.accel)) |
||||
this.frame = 0 |
||||
} |
||||
|
||||
resize() { |
||||
this.canvas.width = window.innerWidth |
||||
this.canvas.height = window.innerHeight |
||||
this.reset() |
||||
} |
||||
} |
||||
Loading…
Reference in new issue