|
|
|
|
/*
|
|
|
|
|
* Snowing routine based on one <canvas> element dynamically
|
|
|
|
|
* injected in the background of the page.
|
|
|
|
|
*
|
|
|
|
|
* The code is not optimized, feel free to make your own edits!
|
|
|
|
|
*
|
|
|
|
|
* Copyright 2010 by David Flanagan
|
|
|
|
|
* http://creativecommons.org/licenses/by-nc-sa/3.0/
|
|
|
|
|
*
|
|
|
|
|
* Modified by Giorgio Sardo
|
|
|
|
|
* http://blogs.msdn.com/Giorgio
|
|
|
|
|
*/
|
|
|
|
|
(function () {
|
|
|
|
|
|
|
|
|
|
// Start Animation only if browser support <canvas>
|
|
|
|
|
if (document.createElement('canvas').getContext) {
|
|
|
|
|
if (document.readyState === 'complete')
|
|
|
|
|
Snow();
|
|
|
|
|
else
|
|
|
|
|
window.addEventListener('DOMContentLoaded', Snow, false);
|
|
|
|
|
} else {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var deg = Math.PI / 180; // For converting degrees to radians
|
|
|
|
|
var sqrt3_2 = Math.sqrt(3) / 2; // Height of an equilateral triangle
|
|
|
|
|
var flakes = []; // Things that are dropping
|
|
|
|
|
var scrollspeed = 64; // How often we animate things
|
|
|
|
|
var snowspeed = 200; // How often we add a new snowflake
|
|
|
|
|
var maxflakes = 20; // Max number of flakes to be added at the same time
|
|
|
|
|
var rand = function (n) { return Math.floor(n * Math.random()); }
|
|
|
|
|
|
|
|
|
|
var canvas, sky;
|
|
|
|
|
var snowingTimer;
|
|
|
|
|
var invalidateMeasure = false;
|
|
|
|
|
|
|
|
|
|
function Snow() {
|
|
|
|
|
canvas = document.createElement('canvas');
|
|
|
|
|
canvas.style.position = 'fixed';
|
|
|
|
|
canvas.style.top = '0px';
|
|
|
|
|
canvas.style.left = '0px';
|
|
|
|
|
canvas.style.zIndex = '-1';
|
|
|
|
|
document.body.insertBefore(canvas, document.body.firstChild);
|
|
|
|
|
sky = canvas.getContext('2d');
|
|
|
|
|
|
|
|
|
|
ResetCanvas();
|
|
|
|
|
|
|
|
|
|
snowingTimer = setInterval(createSnowflake, snowspeed);
|
|
|
|
|
setInterval(moveSnowflakes, scrollspeed);
|
|
|
|
|
|
|
|
|
|
window.addEventListener('resize', ResetCanvas, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function ResetCanvas() {
|
|
|
|
|
invalidateMeasure = true;
|
|
|
|
|
canvas.width = document.body.offsetWidth;
|
|
|
|
|
canvas.height = window.innerHeight;
|
|
|
|
|
sky.strokeStyle = '#0066CC';
|
|
|
|
|
sky.fillStyle = 'white';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function drawFlake(x, y, size, order) {
|
|
|
|
|
sky.save();
|
|
|
|
|
sky.translate(x, y);
|
|
|
|
|
snowflake(order, 0, Math.floor(sqrt3_2 * y), size);
|
|
|
|
|
sky.fill();
|
|
|
|
|
sky.stroke();
|
|
|
|
|
sky.restore();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function snowflake(n, x, y, len) {
|
|
|
|
|
sky.save(); // Save current transformation
|
|
|
|
|
sky.beginPath();
|
|
|
|
|
sky.translate(x, y); // Translate to starting point
|
|
|
|
|
sky.moveTo(0, 0); // Begin a new subpath there
|
|
|
|
|
leg(n); // Draw the first leg of the fractal
|
|
|
|
|
sky.rotate(-120 * deg); // Rotate 120 degrees anticlockwise
|
|
|
|
|
leg(n); // Draw the second leg
|
|
|
|
|
sky.rotate(-120 * deg); // Rotate again.
|
|
|
|
|
leg(n); // Draw the final leg
|
|
|
|
|
sky.closePath(); // Close the subpath
|
|
|
|
|
sky.restore(); // Restore original transformation
|
|
|
|
|
|
|
|
|
|
// Draw a single leg of a level-n Koch snowflake.
|
|
|
|
|
// This function leaves the current point at the end of
|
|
|
|
|
// the leg it has drawn and translates the coordinate
|
|
|
|
|
// system so the current point is (0,0). This means you
|
|
|
|
|
// can easily call rotate() after drawing a leg.
|
|
|
|
|
function leg(n) {
|
|
|
|
|
sky.save(); // Save current transform
|
|
|
|
|
if (n == 0) { // Non-recursive case:
|
|
|
|
|
sky.lineTo(len, 0); // Just a horizontal line
|
|
|
|
|
}
|
|
|
|
|
else { // Recursive case: _ _
|
|
|
|
|
// draw 4 sub-legs like: \/
|
|
|
|
|
sky.scale(1 / 3, 1 / 3); // Sub-legs are 1/3rd size
|
|
|
|
|
leg(n - 1); // Draw the first sub-leg
|
|
|
|
|
sky.rotate(60 * deg); // Turn 60 degrees clockwise
|
|
|
|
|
leg(n - 1); // Draw the second sub-leg
|
|
|
|
|
sky.rotate(-120 * deg); // Rotate 120 degrees back
|
|
|
|
|
leg(n - 1); // Third sub-leg
|
|
|
|
|
sky.rotate(60 * deg); // Back to original heading
|
|
|
|
|
leg(n - 1); // Final sub-leg
|
|
|
|
|
}
|
|
|
|
|
sky.restore(); // Restore the transform
|
|
|
|
|
sky.translate(len, 0); // Translate to end of leg
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function createSnowflake() {
|
|
|
|
|
var order = 2;
|
|
|
|
|
var size = 10 + rand(90);
|
|
|
|
|
// var t = (document.body.offsetWidth - 964) / 2;
|
|
|
|
|
// var x = (rand(2) == 0) ? rand(t) : t + 964 + rand(t); // Make it fit with my blog
|
|
|
|
|
var x = rand(document.body.offsetWidth);
|
|
|
|
|
var y = window.pageYOffset;
|
|
|
|
|
|
|
|
|
|
flakes.push({ x: x, y: y, vx: 0, vy: 3 + rand(3), size: size, order: order });
|
|
|
|
|
|
|
|
|
|
if (flakes.length > maxflakes) clearInterval(snowingTimer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function moveSnowflakes() {
|
|
|
|
|
sky.clearRect(0, 0, canvas.width, canvas.height);
|
|
|
|
|
|
|
|
|
|
var maxy = canvas.height;
|
|
|
|
|
|
|
|
|
|
for (var i = 0; i < flakes.length; i++) {
|
|
|
|
|
var flake = flakes[i];
|
|
|
|
|
|
|
|
|
|
flake.y += flake.vy;
|
|
|
|
|
flake.x += flake.vx;
|
|
|
|
|
|
|
|
|
|
if (flake.y > maxy) flake.y = 0;
|
|
|
|
|
if (invalidateMeasure) {
|
|
|
|
|
var t = (canvas.width - 964) / 2;
|
|
|
|
|
flake.x = (rand(2) == 0) ? rand(t) : t + 964 + rand(t);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
drawFlake(flake.x, flake.y, flake.size, flake.order);
|
|
|
|
|
|
|
|
|
|
// Sometimes change the sideways velocity
|
|
|
|
|
if (rand(4) == 1) flake.vx += (rand(11) - 5) / 10;
|
|
|
|
|
if (flake.vx > 2) flake.vx = 2;
|
|
|
|
|
if (flake.vx < -2) flake.vx = -2;
|
|
|
|
|
}
|
|
|
|
|
if (invalidateMeasure) invalidateMeasure = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} ());
|