Last active
July 13, 2021 18:24
-
-
Save qmzik/baeb76709d23991dc2995893df683dbd to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface IParticle { | |
element: HTMLElement; | |
size: number; | |
horizontalSpeed: number; | |
speedUp: number; | |
spinVal: number; | |
spinSpeed: number; | |
top: number; | |
left: number; | |
direction: -1 | 1; | |
} | |
interface IOptions { | |
element?: HTMLElement; | |
limit?: number; | |
sizes?: number[]; | |
} | |
const defaultOptions: Required<IOptions> = { | |
element: document.body, | |
limit: 35, | |
sizes: [15, 20, 25, 35, 45], | |
} | |
class ParticlesFountain { | |
constructor(imageLink: string, options: IOptions = defaultOptions) { | |
this.src = imageLink; | |
this.options = {...defaultOptions, ...options}; | |
this.addHandlers(); | |
this.loop(); | |
} | |
private options: Required<IOptions>; | |
private src: string; | |
private autoAddParticle: boolean = false; | |
private particles: IParticle[] = []; | |
private mouseY: number = 0; | |
private mouseX: number = 0; | |
public loop() { | |
if (this.autoAddParticle && this.particles.length < this.options.limit) { | |
this.createParticle(); | |
} | |
this.updateParticles(); | |
requestAnimationFrame(this.loop.bind(this)); | |
} | |
public addHandlers() { | |
const tap = 'mousedown'; | |
const tapEnd = 'mouseup'; | |
const move = 'mousemove'; | |
document.addEventListener(move, (e: any) => { | |
this.mouseX = e.pageX ?? (e.touches ? e.touches[0]?.pageX : 0); | |
this.mouseY = e.pageY ?? (e.touches ? e.touches[0]?.pageY : 0); | |
}, { passive: false }); | |
document.addEventListener(tap, (e: any) => { | |
this.mouseX = e.pageX ?? (e.touches ? e.touches[0]?.pageX : 0); | |
this.mouseY = e.pageY ?? (e.touches ? e.touches[0]?.pageY : 0); | |
this.autoAddParticle = true; | |
}); | |
document.addEventListener(tapEnd, () => { | |
this.autoAddParticle = false; | |
}); | |
document.addEventListener('mouseleave', () => { | |
this.autoAddParticle = false; | |
}); | |
} | |
public createParticle() { | |
const size = this.options.sizes[Math.floor(Math.random() * this.options.sizes.length)]; | |
const horizontalSpeed = Math.random() * 10; | |
const speedUp = Math.random() * 25; | |
const spinVal = Math.random() * 360; | |
const spinSpeed = ((Math.random() * 35)) * (Math.random() <= 0.5 ? -1 : 1); | |
const top = (this.mouseY - size / 2); | |
const left = (this.mouseX - size / 2); | |
const direction = Math.random() <= 0.5 ? -1 : 1; | |
const particle = document.createElement('img'); | |
particle.src = this.src; | |
particle.style.width = '30px'; | |
particle.style.top = `${top}px`; | |
particle.style.left = `${left}px`; | |
particle.style.transform = `rotate(${spinVal}deg)`; | |
particle.style.position = 'absolute'; | |
particle.style.willChange = 'transform'; | |
particle.style.pointerEvents = 'none'; | |
this.options.element.appendChild(particle); | |
this.particles.push({ | |
element: particle, | |
size, | |
horizontalSpeed, | |
speedUp, | |
spinVal, | |
spinSpeed, | |
top, | |
left, | |
direction, | |
}); | |
} | |
public changeImage(imageLink: string) { | |
this.src = imageLink; | |
} | |
public updateParticles() { | |
const height = document.body.clientHeight; | |
this.particles.forEach((p) => { | |
p.left = p.left - (p.horizontalSpeed * p.direction); | |
p.top = p.top - p.speedUp; | |
p.speedUp = Math.min(p.size, p.speedUp - 1); | |
p.spinVal = p.spinVal + p.spinSpeed; | |
if (p.top >= height + p.size) { | |
this.particles = this.particles.filter((o) => o !== p); | |
p.element.remove(); | |
} | |
p.element.style.top = `${p.top}px`; | |
p.element.style.left = `${p.left}px`; | |
p.element.style.transform = `rotate(${p.spinVal}deg)`; | |
}); | |
} | |
} | |
export default ParticlesFountain; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment