“Nothing is particularly hard if you divide it into small jobs.” --Henry Ford

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.

Here is an HTML5 Canvas. It is 100 pixels wide by 100 pixels high with a CSS border. Here is the HTML code to create it:
 
<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.

Your browser does not support the HTML5 canvas.
A 100px X 100px canvas
with a 1px CSS border

  1. var cnv = $('#Cnv1').get(0), // Get the canvas element by id
  2.     ctx = cnv.getContext('2d'); // Get the canvas context
  3. ctx.fillStyle = 'red'; // Set the context fill style
  4. $('#btnDraw').click(function() { // Draw button click event handler
  5.     ctx.fillRect(10, 10, 80, 80); // Draw and fill the rectangle
  6. });
  7. $('#btnClear').click(function() { // Clear button click event handler
  8.     ctx.clearRect(0, 0, 100, 100); // Clear the entire canvas
  9. });

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.

  1.     <body>
  2.         <div id="sceneContainer">
  3.             <canvas id="backgroundGradient"></canvas>
  4.             <canvas id="snowflakesCanvas"></canvas>
  5.             <input type="button" id="btnMP" value="Mute">
  6.             <p id="msg">Seasons<br>Greetings</p>
  7.         </div>

That is all the HTML elements we need to reproduce the demo page. Now we need to add some style with CSS.

  1. <link rel="stylesheet" type="text/css" href="http://fonts.googleapis.com/css?family=Waiting+for+the+Sunrise&text=Seasons%20Greetings">
  2. <style type="text/css">
  3.     html, body {
  4.         border: 0;
  5.         margin: 0;
  6.         padding: 0;
  7.         width: 100%;
  8.     }
  9.     body {
  10.     	color: white;
  11.     }
  12.     #sceneContainer {
  13.         position: absolute;
  14.         top: 0px;
  15.         left: 0px;
  16.         right: 0px;
  17.         bottom: 0px;
  18.         background-color: black;
  19.         overflow: hidden;
  20.     }
  21.     #backgroundGradient, #snowflakesCanvas {
  22.         position: fixed;
  23.         top: 0;
  24.         left: 0;
  25.         width: 100%;
  26.         height: 100%;
  27.     }
  28.     #msg {
  29.         position: relative;
  30.         top: 100px;
  31.         width: 500px;
  32.         margin: 0 auto;
  33.         text-align: center;
  34.         font: normal 4em 'Waiting for the Sunrise';
  35.     }
  36.     #btnMP {
  37.         position: relative;
  38.         top: 10px;
  39.         left: 10px;
  40.         width: 55px;
  41.         color: white;
  42.         background-color: black;
  43.     }
  44. </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:

  1.         <script src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
  2.         <script type="text/javascript">
  3.             Snowflakes = (function() {
  4.             })(jQuery);
  5.  
  6.             // single animation loop and fps calculation
  7.             Animation = (function() {
  8.             })(jQuery);
  9.  
  10.             jQuery(function($) {
  11.             });
  12.         </script>
  13.     </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.

  1.                 // snowflakes objects collection
  2.                 var snowflakes = [],
  3.                     snowflakesDefaultCount = 1000,
  4.                 // snowflakes sprites
  5.                     snowflakeSprites = [],
  6.                     spritesCount = 9,
  7.                     spriteWidth = 20,
  8.                     spriteHeight = 20,
  9.                 // canvas bounds used for snowflake animation
  10.                     bounds = {width: $(window).width(), height: $(window).height()},
  11.                 // snowflake movement parameters:
  12.                 // we'll advance each snowflake vertically at least or most by these amounts
  13.                 // (think gravity and resistance)
  14.                     minVerticalVelocity = 1,
  15.                     maxVerticalVelocity = 4,
  16.                 // we'll shift each snowflake horizontally at least or most by these amounts
  17.                 // (think wind and resistance)
  18.                     minHorizontalVelocity = -1,
  19.                     maxHorizontalVelocity = 3,
  20.                 // each snowflake sprite will be scaled by these settings
  21.                     minScale = 0.2,
  22.                     maxScale = 1.25,
  23.                 // each snowflake also "bobs" on horizontal axis
  24.                 // (think volumetric resistance) at least or most by these amounts
  25.                     minHorizontalDelta = 2,
  26.                     maxHorizontalDelta = 3,
  27.                 // each snowflakes opacity is set at least or most by these
  28.                     minOpacity = 0.2,
  29.                     maxOpacity = 0.9,
  30.                 // change opacity by at max 1/maxOpacityIncrement
  31.                     maxOpacityIncrement = 50,
  32.                 // dynamic speed:
  33.                 // start without any speed correction
  34.                     speedFactor = 1;
  35.  
  36.                 // create number of snowflakes adding if required (or regenerate from scratch)
  37.                 function generate(number, add) {
  38.                     var ii = 0,
  39.                     // Unicode snowflakes
  40.                         sfShapes = ['\u2745', '\u2744', '\u2745', '\u2745', '\u2745', '\u2745', '\u2745', '\u2746', '\u2745'];
  41.  
  42.                     // initialize sprite
  43.                     for (ii = 0; ii < spritesCount; ii++) {
  44.                         var sprite = $('<canvas/>', {
  45.                                 width: spriteWidth,
  46.                                 height: spriteHeight
  47.                             }).get(0),
  48.                             context = sprite.getContext('2d');
  49.  
  50.                         context.fillStyle = 'white';
  51.                         context.font = 'normal 27px sans-serif';
  52.                         context.textBaseline = 'bottom';
  53.                         context.fillText(sfShapes[ii], -2, 24);
  54.                         snowflakeSprites.push(sprite);
  55.                     }
  56.  
  57.                     if (number) {
  58.                         snowflakesDefaultCount = number;
  59.                     }
  60.                     if (!add) {
  61.                         snowflakes = [];
  62.                     }
  63.                     for (ii = 0; ii < snowflakesDefaultCount; ii++) {
  64.                         snowflakes.push(generateSnowflake());
  65.                     }
  66.                 }
  67.  

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 NameCharacterImageHTML Escape CodeJavascript Code
Snowflake
Snowflake
&#x2744;"\u2744"
Tight Trifoliate Snowflake
Tight Trifoliate Snowflake
&#x2745;"\u2745"
Heavy Chevron Snowflake
Heavy Chevron Snowflake
&#x2746;"\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.

  1.                 function generateSnowflake() {
  2.                     var scale = Math.random() * (maxScale - minScale) + minScale;
  3.                     return {
  4.                     // x position
  5.                         x: Math.random() * bounds.width,
  6.                     // y position
  7.                         y: Math.random() * bounds.height,
  8.                     // vertical velocity
  9.                         vv: Math.random() * (maxVerticalVelocity - minVerticalVelocity) + minVerticalVelocity,
  10.                     // horizontal velocity
  11.                         hv: Math.random() * (maxHorizontalVelocity - minHorizontalVelocity) + minHorizontalVelocity,
  12.                     // scaled sprite width
  13.                         sw: scale * spriteWidth,
  14.                     // scaled sprite width
  15.                         sh: scale * spriteHeight,
  16.                     // maximum horizontal delta
  17.                         mhd: Math.random() * (maxHorizontalDelta - minHorizontalDelta) + minHorizontalDelta,
  18.                     // horizontal delta
  19.                         hd: 0,
  20.                     // horizontal delta increment
  21.                         hdi: Math.random() / (maxHorizontalVelocity * minHorizontalDelta),
  22.                     // opacity
  23.                         o: Math.random() * (maxOpacity - minOpacity) + minOpacity,
  24.                     // opacity increment
  25.                         oi: Math.random() / maxOpacityIncrement,
  26.                     // sprite index
  27.                         si: Math.ceil(Math.random() * (spritesCount - 1))
  28.                     }
  29.                 }
  30.  

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.