How To: Let It Snow using the HTML5 Canvas
HTML5 has some great features like native video and audio players and a flexible canvas. Unlike the video or audio player which have controls that are visible on screen using only HTML code, the canvas requires javascript to create anything visible. Yes, you can use CSS or inline styles for the canvas to position, size, or set borders, but that is all you can do with just mark-up.
<canvas id="Cnv1" width="100" height="100" style="border: 1px solid;"></canvas>
As you can see, the canvas is blank. So we need to write some javascript to draw something on it. We are going to draw a small rectangle and fill it with the color red when the Draw button is clicked and clear the entire canvas when the Clear button is clicked. We are going to use jQuery to write all of our javascript code throughout.
with a 1px CSS border
var cnv = $('#Cnv1').get(0), // Get the canvas element by id
ctx = cnv.getContext('2d'); // Get the canvas context
ctx.fillStyle = 'red'; // Set the context fill style
$('#btnDraw').click(function() { // Draw button click event handler
ctx.fillRect(10, 10, 80, 80); // Draw and fill the rectangle
});
$('#btnClear').click(function() { // Clear button click event handler
ctx.clearRect(0, 0, 100, 100); // Clear the entire canvas
});
HTML Layout and CSS
You can find lots of examples to show you the basics of using the canvas but we want to do a little more than just the basics, right? We want to make it snow! To get started, we need a simple HTML layout.
<body>
<div id="sceneContainer">
<canvas id="backgroundGradient"></canvas>
<canvas id="snowflakesCanvas"></canvas>
<input type="button" id="btnMP" value="Mute">
<p id="msg">Seasons<br>Greetings</p>
</div>
That is all the HTML elements we need to reproduce the demo page. Now we need to add some style with CSS.
<link rel="stylesheet" type="text/css" href="http://fonts.googleapis.com/css?family=Waiting+for+the+Sunrise&text=Seasons%20Greetings">
<style type="text/css">
html, body {
border: 0;
margin: 0;
padding: 0;
width: 100%;
}
body {
color: white;
}
#sceneContainer {
position: absolute;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
background-color: black;
overflow: hidden;
}
#backgroundGradient, #snowflakesCanvas {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
#msg {
position: relative;
top: 100px;
width: 500px;
margin: 0 auto;
text-align: center;
font: normal 4em 'Waiting for the Sunrise';
}
#btnMP {
position: relative;
top: 10px;
left: 10px;
width: 55px;
color: white;
background-color: black;
}
</style>
Everything is basic CSS except for line 1. We are getting a font from Google Web Fonts named 'Waiting for the Sunrise' and we only want certain characters to keep the download small.
Objects and Functions
Moving right along, we need to define our jQuery environment. To do that we add the following:
<script src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script type="text/javascript">
Snowflakes = (function() {
})(jQuery);
// single animation loop and fps calculation
Animation = (function() {
})(jQuery);
jQuery(function($) {
});
</script>
</body>
From a previous article "Add The Power of jQuery" (see Related articles below) we add the jQuery library. Next we add "Snowflakes" and "Animation" as objects in the jQuery namespace. Then we declare the main jQuery.
Snowflakes
Okay, now we need to add a bunch of variables and a few functions to the "Snowflakes" object. Start adding the following code between lines 3 and 4 from the Objects and Functions section above. It is a long list with comments to help explain things along the way.
// snowflakes objects collection
var snowflakes = [],
snowflakesDefaultCount = 1000,
// snowflakes sprites
snowflakeSprites = [],
spritesCount = 9,
spriteWidth = 20,
spriteHeight = 20,
// canvas bounds used for snowflake animation
bounds = {width: $(window).width(), height: $(window).height()},
// snowflake movement parameters:
// we'll advance each snowflake vertically at least or most by these amounts
// (think gravity and resistance)
minVerticalVelocity = 1,
maxVerticalVelocity = 4,
// we'll shift each snowflake horizontally at least or most by these amounts
// (think wind and resistance)
minHorizontalVelocity = -1,
maxHorizontalVelocity = 3,
// each snowflake sprite will be scaled by these settings
minScale = 0.2,
maxScale = 1.25,
// each snowflake also "bobs" on horizontal axis
// (think volumetric resistance) at least or most by these amounts
minHorizontalDelta = 2,
maxHorizontalDelta = 3,
// each snowflakes opacity is set at least or most by these
minOpacity = 0.2,
maxOpacity = 0.9,
// change opacity by at max 1/maxOpacityIncrement
maxOpacityIncrement = 50,
// dynamic speed:
// start without any speed correction
speedFactor = 1;
// create number of snowflakes adding if required (or regenerate from scratch)
function generate(number, add) {
var ii = 0,
// Unicode snowflakes
sfShapes = ['\u2745', '\u2744', '\u2745', '\u2745', '\u2745', '\u2745', '\u2745', '\u2746', '\u2745'];
// initialize sprite
for (ii = 0; ii < spritesCount; ii++) {
var sprite = $('<canvas/>', {
width: spriteWidth,
height: spriteHeight
}).get(0),
context = sprite.getContext('2d');
context.fillStyle = 'white';
context.font = 'normal 27px sans-serif';
context.textBaseline = 'bottom';
context.fillText(sfShapes[ii], -2, 24);
snowflakeSprites.push(sprite);
}
if (number) {
snowflakesDefaultCount = number;
}
if (!add) {
snowflakes = [];
}
for (ii = 0; ii < snowflakesDefaultCount; ii++) {
snowflakes.push(generateSnowflake());
}
}
The generate function needs a little explanation. Well more specifically the variables sfShapes and sprite. There are no jpg, gif, png, or any other format graphics being used. We create the images dynamically with this function. You may wonder what the codes '\u2744', '\u2745', '\u2746' are. They are Unicode characters. This is what they look like and how to use them:
Character Name | Character | Image | HTML Escape Code | Javascript Code |
---|---|---|---|---|
Snowflake | ❄ | ❄ | "\u2744" | |
Tight Trifoliate Snowflake | ❅ | ❅ | "\u2745" | |
Heavy Chevron Snowflake | ❆ | ❆ | "\u2746" |
We use a for loop to create a separate canvas for each snowflake shape. We create a total of nine even though we are only using three different shapes. The reason why is so the final results are more random. The last for loop of the generate function calls the generateSnowflake function to populate the snowflakes array.
function generateSnowflake() {
var scale = Math.random() * (maxScale - minScale) + minScale;
return {
// x position
x: Math.random() * bounds.width,
// y position
y: Math.random() * bounds.height,
// vertical velocity
vv: Math.random() * (maxVerticalVelocity - minVerticalVelocity) + minVerticalVelocity,
// horizontal velocity
hv: Math.random() * (maxHorizontalVelocity - minHorizontalVelocity) + minHorizontalVelocity,
// scaled sprite width
sw: scale * spriteWidth,
// scaled sprite width
sh: scale * spriteHeight,
// maximum horizontal delta
mhd: Math.random() * (maxHorizontalDelta - minHorizontalDelta) + minHorizontalDelta,
// horizontal delta
hd: 0,
// horizontal delta increment
hdi: Math.random() / (maxHorizontalVelocity * minHorizontalDelta),
// opacity
o: Math.random() * (maxOpacity - minOpacity) + minOpacity,
// opacity increment
oi: Math.random() / maxOpacityIncrement,
// sprite index
si: Math.ceil(Math.random() * (spritesCount - 1))
}
}
The generateSnowflake function returns parameters used to manipulate each individual snowflake created.
Demo and Download
See the Let It Snow! - HTML5 Canvas Demo here.
Download the source file here.