JS-E03 - Efeito Neve (snow) com JavaScript
Aprenda a realizar o efeito de neve de forma descomplicada
Este é um efeito que coloquei na home desta página, para dar colocar um algo a mais no "call to action".
A imagem que utilizo de fundo tem tons de magenta, então escolhi este tom para os flocos em movimento.
O código é levemente complexo, mas é bem prático de configurar, e utilizei um macete para permitir que os flocos partissem também do bottomdesta seção.
O função em JS, declarada como variável é a seguinte:
//EFEITO SNOW
let snowCanvas = function (obj) {
var canvas = obj.el;
canvas.style.backgroundColor = obj.background;
var fillStyle = obj.snowColor;
var ctx = canvas.getContext("2d");
var maxSpeed = obj.maxSpeed,
minSpeed = obj.minSpeed,
count = obj.amount ,
rMax = obj.rMax,
rMin = obj.rMin,
W, H; //height and width of canvas;
setHeightWidth( );
function setHeightWidth( ) {
W = obj.width;
H = obj.height;
canvas.width = W;
canvas.height = H;
}
window.onresize = setHeightWidth;
var snowGroup = [];
var i;
for (i = 0; i < count; i++) {
snowGroup.push(initialEverySnow());
}
function initialEverySnow() {
return {
x: Math.random() * W - rMax,
y: Math.random() * H - rMax,
r: Math.random() * (rMax - rMin) + rMin,
s: Math.random() * (maxSpeed - minSpeed) + minSpeed,
xChangeRate: Math.random() * 1.6 - 0.8
};
}
function draw() {
ctx.clearRect(0, 0, W, H);
ctx.beginPath();
var p;
for (var i = 0; i < snowGroup.length; i++) {
p = snowGroup[i];
ctx.fillStyle = fillStyle;
ctx.moveTo(p.x, p.y);
ctx.arc(p.x, p.y, p.r, 0, 2 * Math.PI);
}
ctx.fill();
update();
}
var delta = 0;
function update() {
//update position of every snow
delta += 0.01;
var p;
for (var i = 0; i < snowGroup.length; i++) {
p = snowGroup[i];
p.y += p.s;
p.x += Math.sin(delta + p.xChangeRate) * p.xChangeRate;
if (p.x > W + p.r || p.y > H + p.r || p.x < -p.r) {
snowGroup[i] = initialEverySnow();
var randomStartPostion = Math.ceil(Math.random() * 3);
switch (randomStartPostion) {
case 1:
//drop from top
snowGroup[i].x = Math.random() * W;
snowGroup[i].y = -rMax;
break;
case 2:
//start from left
snowGroup[i].x = -rMax;
snowGroup[i].y = Math.random() * H;
break;
case 3:
//start from right
snowGroup[i].x = W + rMax;
snowGroup[i].y = Math.random() * H;
break;
}
}
}
}
setInterval(draw, 1000 / 60);
};
Para acionar utilizei a seguinte função, passando os parâmtros necessários para a função snowCanvas, que será aplicada em um elemento canvas, selecionado através de um id. Implementei uma condicional por utilizar um único script minificado para a camada web desta página:
if (document.getElementById("snowCanvas")) {
window.onload = snowCanvas({
el: document.getElementById("snowCanvas"),// elemento selecionado
snowColor: "#821C87",// cor dos flocos
background: "rgba(0,0,0,0)",// cor de fundo que deixei trasnparente para apresentar a minha imagem
maxSpeed: 2,// velocidade máxima do movimento
minSpeed: 1,// velocidade mínima do movimento
width: "",// largura opicional
height: "",// altura opicional
amount: 15,// quantidade de flocos
rMax: 4,// raio máximo do floco
rMin: 1// raio mínimo do floco
});
}
No html, basta utilizar o canvas com o id "snowCanvas". Eu utilizei na página home deste site a tag canvas da seguinte forma:
Percebeu que utilizei dois elementos canvas? Agora vem um macete! O segundo canvas foi utilizado para implementar os flocos subindo, poderia ser utilizado para qualquer lado, inlcuindo um evento de mouseMove alterando a orientação deste elemento.
Na ativação eu dupliquei a chamada do método snowCanvas passando os elementos canvas pelos seus respectivos id (snowCanvas e snowCanvas2):
if (document.getElementById("snowCanvas1")) {
window.onload = snowCanvas({
el: document.getElementById("snowCanvas"),
snowColor: "#821C87",
background: "rgba(0,0,0,0)",
maxSpeed: 2,
minSpeed: 1,
width: "",
height: "",
amount: 15,
rMax: 4,
rMin: 1
});
}
if (document.getElementById("snowCanvas2")) {
window.onload = snowCanvas({
el: document.getElementById("snowCanvas2"),
snowColor: "#821C87",
background: "rgba(0,0,0,0)",
maxSpeed: 2,
minSpeed: 1,
width: "",
height: "",
amount: 15,
rMax: 4,
rMin: 1
});
}
utilizei as mesmas cores, mas podem ser utilizadas n cores, tomando cuidado com a performance.
Para inverter o sentido do floco, rotacionei este canvas em 180graus no css:
#snowCanvas1, #snowCanvas2 {
top: 0;
left: 0;
position: absolute;
max-width: 100%;
overflow-x: hidden;
}
#snowCanvas1{
z-index: 1;
}
#snowCanvas2{
z-index: 2;
transform: rotate(180deg);
}
Utilizei o z-index para sobrepor os elementos, colocando como absoluteà div pai. O botão eu defini com o z-index 4 e no mobile defini o nav com 5, sobrepondo corretamente os elementos.
Caso seja necessário apenas o efeito simples, basta inserir o canvas definindo altura e largura, com uma cor de fundo que destaque os flocos.
Para visualizar o efeito, clique aqui na HOME.