ngx-snowf
Version:
Snowfall component for React -- Let it snow on your page! ❄
212 lines (191 loc) • 5.77 kB
text/typescript
import { Component, Input, ElementRef, HostListener } from '@angular/core';
export class SnowfComponent {
amount: number = 50;
size: number = 5;
speed: number = 1.5;
wind: number = 0;
color: string = '#fff';
opacity: number = 0.8;
swing: number = 1;
image: string = null;
zIndex: number = null;
private inited: boolean = false;
private canvas: any = null;
private context: any = null;
private flakes: Array<any> = [];
private canvasWidth: number = 0;
private canvasHeight: number = 0;
private img: any = null;
constructor(private elementRef: ElementRef) {}
onResize() {
this.handleResize();
}
ngOnInit() {
this.canvas = this.elementRef.nativeElement.querySelector('.snowf-canvas');
this.context = this.canvas.getContext('2d');
this.canvasHeight = this.canvas.offsetHeight;
this.canvasWidth = this.canvas.offsetWidth;
this.canvas.height = this.canvasHeight;
this.canvas.width = this.canvasWidth;
if (this.zIndex != null) this.canvas.style.zIndex = this.zIndex;
if (this.image) {
this.img = new Image();
this.img.onload = () => this.init();
this.img.src = this.image;
} else {
this.init();
}
}
ngOnChanges(changes) {
if (changes.amount && changes.amount.firstChange) return;
if (changes.zIndex) this.canvas.style.zIndex = this.zIndex;
if (changes.amount) this.update();
if (changes.image) {
this.img = new Image();
this.img.src = this.image;
}
}
/**
* update props
*/
update() {
if (this.image) {
this.img = new Image();
this.img.onload = () => this.init();
this.img.src = this.image;
} else {
this.init();
}
}
/**
* Initialize flakes
*/
init() {
this.flakes = [];
for (var i = 0; i < this.amount; i++) {
this.flakes.push({
x: this.random(0, this.canvasWidth),
y: this.random(0, this.canvasHeight),
r: this.random(this.size, this.size * 2) / 2,
velX: 0,
velY: this.random(this.speed, this.speed * 2),
swing: this.random(0, 2 * Math.PI),
opacity: this.random(0, this.opacity)
});
}
if (!this.inited) {
this.inited = true;
this.snow();
}
}
/**
* draw snowflakes on canvas
*/
snow() {
this.context.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
for (var i = 0; i < this.flakes.length; i++) {
var flake = this.flakes[i];
if (!this.image) {
this.context.beginPath();
this.context.fillStyle = 'rgba(' + this.getRgb(this.color) + ',' + flake.opacity + ')';
this.context.arc(flake.x, flake.y, flake.r, 2 * Math.PI, false);
this.context.fill();
this.context.closePath();
}
else {
this.context.drawImage(this.img, flake.x - flake.r, flake.y - flake.r, 2 * flake.r, 2 * flake.r);
}
flake.velX = Math.abs(flake.velX) < Math.abs(this.wind) ? flake.velX + this.wind / 20 : this.wind;
flake.y = flake.y + flake.velY * 0.5;
flake.x = flake.x + (this.swing ? 0.4 * Math.cos(flake.swing += 0.03) * flake.opacity * this.swing : 0) + flake.velX * 0.5;
if (flake.x > this.canvasWidth + flake.r || flake.x < -flake.r || flake.y > this.canvasHeight + flake.r || flake.y < -flake.r) {
this.reset(flake);
}
}
requestAnimationFrame(this.snow.bind(this));
}
/**
* reset flake property
* @param flake
*/
reset(flake) {
var prevR = flake.r;
flake.r = this.random(this.size, this.size * 2) / 2;
if (flake.x > this.canvasWidth + prevR) {
flake.x = -flake.r;
flake.y = this.random(0, this.canvasHeight);
}
else if (flake.x < -prevR) {
flake.x = this.canvasWidth + flake.r;
flake.y = this.random(0, this.canvasHeight);
}
else {
flake.x = this.random(0, this.canvasWidth);
flake.y = -flake.r;
}
flake.velX = 0;
flake.velY = this.random(this.speed, this.speed * 2);
flake.swing = this.random(0, 2 * Math.PI);
flake.opacity = this.random(0, this.opacity);
}
/**
* handle window resize
*/
handleResize() {
if (!this.inited) return;
var H0 = this.canvas.height,
W0 = this.canvas.width,
H1 = this.canvas.offsetHeight,
W1 = this.canvas.offsetWidth;
this.canvas.height = this.canvasHeight = H1;
this.canvas.width = this.canvasWidth = W1;
for (var i = 0; i < this.flakes.length; i++) {
var flake = this.flakes[i];
flake.x = flake.x / W0 * W1;
flake.y = flake.y / H0 * H1;
}
}
/**
* get random number
* @param min
* @param max
*/
random(min, max) {
var delta = max - min;
return max === min ? min : Math.random() * delta + min;
}
/**
* get rgb color
* @param str
*/
getRgb(str) {
var rgb = '';
if (str.indexOf('#') === 0) {
rgb = str.length === 4 ? str.substr(1).split('').map(function (n) { return parseInt(n.concat(n), 16); }).join(',') :
str.length === 7 ? [str.substr(1, 2), str.substr(3, 2), str.substr(5, 2)].map(function (n) { return parseInt(n, 16); }).join(',') :
'255,255,255';
}
else if (str.indexOf('rgb(') === 0) {
rgb = str.substring(4, str.length - 1);
}
else {
rgb = '255,255,255';
}
return rgb;
}
}