Animation of a storm with lightning and thunder. Pretty Awesome!
A Pen by Carlo Moscatiello on CodePen.
Animation of a storm with lightning and thunder. Pretty Awesome!
A Pen by Carlo Moscatiello on CodePen.
<body class="thunder"> | |
<canvas id="canvas1"></canvas> | |
<canvas id="canvas2"></canvas> | |
<canvas id="canvas3"></canvas> | |
</body> |
var canvas1 = document.getElementById('canvas1'); | |
var canvas2 = document.getElementById('canvas2'); | |
var canvas3 = document.getElementById('canvas3'); | |
var ctx1 = canvas1.getContext('2d'); | |
var ctx2 = canvas2.getContext('2d'); | |
var ctx3 = canvas3.getContext('2d'); | |
var rainthroughnum = 500; | |
var speedRainTrough = 25; | |
var RainTrough = []; | |
var rainnum = 500; | |
var rain = []; | |
var lightning = []; | |
var lightTimeCurrent = 0; | |
var lightTimeTotal = 0; | |
var w = canvas1.width = canvas2.width = canvas3.width = window.innerWidth; | |
var h = canvas1.height = canvas2.height = canvas3.height = window.innerHeight; | |
window.addEventListener('resize', function() { | |
w = canvas1.width = canvas2.width = canvas3.width = window.innerWidth; | |
h = canvas1.height = canvas2.height = canvas3.height = window.innerHeight; | |
}); | |
function random(min, max) { | |
return Math.random() * (max - min + 1) + min; | |
} | |
function clearcanvas1() { | |
ctx1.clearRect(0, 0, w, h); | |
} | |
function clearcanvas2() { | |
ctx2.clearRect(0, 0, canvas2.width, canvas2.height); | |
} | |
function clearCanvas3() { | |
ctx3.globalCompositeOperation = 'destination-out'; | |
ctx3.fillStyle = 'rgba(0,0,0,' + random(1, 30) / 100 + ')'; | |
ctx3.fillRect(0, 0, w, h); | |
ctx3.globalCompositeOperation = 'source-over'; | |
}; | |
function createRainTrough() { | |
for (var i = 0; i < rainthroughnum; i++) { | |
RainTrough[i] = { | |
x: random(0, w), | |
y: random(0, h), | |
length: Math.floor(random(1, 830)), | |
opacity: Math.random() * 0.2, | |
xs: random(-2, 2), | |
ys: random(10, 20) | |
}; | |
} | |
} | |
function createRain() { | |
for (var i = 0; i < rainnum; i++) { | |
rain[i] = { | |
x: Math.random() * w, | |
y: Math.random() * h, | |
l: Math.random() * 1, | |
xs: -4 + Math.random() * 4 + 2, | |
ys: Math.random() * 10 + 10 | |
}; | |
} | |
} | |
function createLightning() { | |
var x = random(100, w - 100); | |
var y = random(0, h / 4); | |
var createCount = random(1, 3); | |
for (var i = 0; i < createCount; i++) { | |
single = { | |
x: x, | |
y: y, | |
xRange: random(5, 30), | |
yRange: random(10, 25), | |
path: [{ | |
x: x, | |
y: y | |
}], | |
pathLimit: random(40, 55) | |
}; | |
lightning.push(single); | |
} | |
}; | |
function drawRainTrough(i) { | |
ctx1.beginPath(); | |
var grd = ctx1.createLinearGradient(0, RainTrough[i].y, 0, RainTrough[i].y + RainTrough[i].length); | |
grd.addColorStop(0, "rgba(255,255,255,0)"); | |
grd.addColorStop(1, "rgba(255,255,255," + RainTrough[i].opacity + ")"); | |
ctx1.fillStyle = grd; | |
ctx1.fillRect(RainTrough[i].x, RainTrough[i].y, 1, RainTrough[i].length); | |
ctx1.fill(); | |
} | |
function drawRain(i) { | |
ctx2.beginPath(); | |
ctx2.moveTo(rain[i].x, rain[i].y); | |
ctx2.lineTo(rain[i].x + rain[i].l * rain[i].xs, rain[i].y + rain[i].l * rain[i].ys); | |
ctx2.strokeStyle = 'rgba(174,194,224,0.5)'; | |
ctx2.lineWidth = 1; | |
ctx2.lineCap = 'round'; | |
ctx2.stroke(); | |
} | |
function drawLightning() { | |
for (var i = 0; i < lightning.length; i++) { | |
var light = lightning[i]; | |
light.path.push({ | |
x: light.path[light.path.length - 1].x + (random(0, light.xRange) - (light.xRange / 2)), | |
y: light.path[light.path.length - 1].y + (random(0, light.yRange)) | |
}); | |
if (light.path.length > light.pathLimit) { | |
lightning.splice(i, 1); | |
} | |
ctx3.strokeStyle = 'rgba(255, 255, 255, .1)'; | |
ctx3.lineWidth = 3; | |
if (random(0, 15) === 0) { | |
ctx3.lineWidth = 6; | |
} | |
if (random(0, 30) === 0) { | |
ctx3.lineWidth = 8; | |
} | |
ctx3.beginPath(); | |
ctx3.moveTo(light.x, light.y); | |
for (var pc = 0; pc < light.path.length; pc++) { | |
ctx3.lineTo(light.path[pc].x, light.path[pc].y); | |
} | |
if (Math.floor(random(0, 30)) === 1) { //to fos apo piso | |
ctx3.fillStyle = 'rgba(255, 255, 255, ' + random(1, 3) / 100 + ')'; | |
ctx3.fillRect(0, 0, w, h); | |
} | |
ctx3.lineJoin = 'miter'; | |
ctx3.stroke(); | |
} | |
}; | |
function animateRainTrough() { | |
clearcanvas1(); | |
for (var i = 0; i < rainthroughnum; i++) { | |
if (RainTrough[i].y >= h) { | |
RainTrough[i].y = h - RainTrough[i].y - RainTrough[i].length * 5; | |
} else { | |
RainTrough[i].y += speedRainTrough; | |
} | |
drawRainTrough(i); | |
} | |
} | |
function animateRain() { | |
clearcanvas2(); | |
for (var i = 0; i < rainnum; i++) { | |
rain[i].x += rain[i].xs; | |
rain[i].y += rain[i].ys; | |
if (rain[i].x > w || rain[i].y > h) { | |
rain[i].x = Math.random() * w; | |
rain[i].y = -20; | |
} | |
drawRain(i); | |
} | |
} | |
function animateLightning() { | |
clearCanvas3(); | |
lightTimeCurrent++; | |
if (lightTimeCurrent >= lightTimeTotal) { | |
createLightning(); | |
lightTimeCurrent = 0; | |
lightTimeTotal = 200; //rand(100, 200) | |
} | |
drawLightning(); | |
} | |
function init() { | |
createRainTrough(); | |
createRain(); | |
window.addEventListener('resize', createRainTrough); | |
} | |
init(); | |
function animloop() { | |
animateRainTrough(); | |
animateRain(); | |
animateLightning(); | |
requestAnimationFrame(animloop); | |
} | |
animloop(); |
@mixin size($size) { | |
width: $size; | |
height: $size; | |
} | |
@mixin abs-pos { | |
display: block; | |
position: absolute; | |
top: 0; | |
left: 0; | |
} | |
html { | |
box-sizing: border-box; | |
} | |
*, | |
*:before, | |
*:after { | |
box-sizing: inherit; | |
margin: 0; | |
padding: 0; | |
} | |
html, | |
body, | |
canvas { | |
@include size(100%); | |
} | |
body { | |
@include size(100%); | |
background-color: #222; | |
background-image: url('https://drive.google.com/uc?export=view&id=0BzFF7FmbJUo5X0NEUXFVd0NBcWc'); | |
background-size: cover; | |
background-position: 0 0; | |
background-repeat: no-repeat; | |
position: relative; | |
z-index: 0; | |
&:after { | |
content: ''; | |
@include size(100%); | |
@include abs-pos; | |
background-color: rgba(0, 0, 0, 0.1); | |
z-index: 1; | |
animation: thunder-bg 6s infinite; | |
} | |
} | |
canvas { | |
@include abs-pos; | |
} | |
#canvas3 { | |
z-index: 5; | |
} | |
#canvas2 { | |
z-index: 10; | |
} | |
#canvas1 { | |
z-index: 100; | |
} | |
$color1: rgba(34, | |
34, | |
34, | |
.9); | |
$color2: rgba(59, | |
59, | |
59, | |
.3); | |
.thunder { | |
@at-root { | |
@-webkit-keyframes thunder-bg { | |
0% { | |
background-color: $color1; | |
} | |
9% { | |
background-color: $color1; | |
} | |
10% { | |
background-color: $color2; | |
} | |
10.5% { | |
background-color: $color1; | |
} | |
80% { | |
background-color: $color1; | |
} | |
82% { | |
background-color: $color2; | |
} | |
83% { | |
background-color: $color1; | |
} | |
83.5% { | |
background-color: $color2; | |
} | |
100% { | |
background-color: $color1; | |
} | |
} | |
} | |
} |