It is getting to that time of year again. Digging around in the attic I found an old-fashion Flash/Actionscript snow storm. Oh Happy days … but as it is 2011 what we really need is a HTML5 snowstorm.

Here is breakdown of the code. First you need a canvas.

<canvas id="myCanvas" width="500" height="320">
</canvas>

To use this canvas element you then need a “context”. The “context” is in effect the javascript space into which you can ‘draw’ via code. We are going to use jQuery to target the context though you could just use Javascript’s ‘getElementByID’. We are also going to create two variables. A primative number variable to hold the number of snowballs we want and then an array to manage our snowballs.

$(document).ready(function(){
    var mainContext = $('#myCanvas')[0].getContext("2d");
    var snowStorm = new Array();
    var noOfSnowFlakes = 25;
}

Next to create the Snow class. As Javascript isn’t Object Oriented in the same way as ActionScript or Java this really means just setting up a function. This function takes five parameters the canvas context, snowball speed for moving them, the snowball width for sizing them and then starting x/y coordinates.

function Snow(context, speed, width, xPos, yPos){
	this.context = context;
	this.speed = speed;
	this.width = width;
	this.xPos = xPos;
        this.yPos = yPos;
}

Add a ‘method’ to this ‘Snow’ class with Javascript prototyping. This ‘method’ of the ‘Snow’ class I have chosen to call ‘update’. The ‘this’ keyword inside the function/method will refer to each individual instance of the Snow object we choose to create. This ‘method’ then uses the Javascript drawing API to draw a white circle. This is positioned based on the ‘xPo’s and ‘yPo’s variables and conditional logic is used to check if the ‘snowball’ has fallen off the bottom or right-hand side of the canvas.

Snow.prototype.update = function () {
	this.context.beginPath();
	this.context.arc(this.xPos, this.yPos, this.width, 0, Math.PI*2, false);
	if(this.yPos > 305){
		this.yPos = -5;
	}
	if(this.xPos > 505){
		this.xPos = 0;
	}
	this.xPos = this.xPos + this.speed;
	this.yPos = this.yPos + this.speed;
	this.context.closePath();
	this.context.fillStyle = "#FFFFFF";
	this.context.fill();
}

The ‘buildSnowStorm()’ function is used to loop around the ‘noOfSnowFlakes’ variable. We use Math.round() and Math.random() to produce a randomized range of snowball sizes and coordinates. As each ‘snowball’ is created via the ‘new Snow’ call, a reference to it is stashed away in the ‘snowStorm’ array. Outside of the loop a setInterval() is set up to call the ‘draw()’ function every 50 milliseconds.

function buildSnowStorm(){
	for (var i = 0; i < noOfSnowFlakes; i++) {
		var randomW = Math.round(Math.random() * 5) +2;
		var randomX = Math.round(Math.random() * 500);
	        var randomY = Math.round(Math.random() * 300);
		var snowBallAr = new Snow(mainContext, randomW, randomW, randomX, randomY);
		snowStorm.push(snowBallAr);
	}
	setInterval(draw, 50);
}

Animation with HTML5 canvas is achieved by redrawing the canvas at regular intervals. This is achieved here through use of Javascript’s ‘setInterval’. We will now create the draw() function called by the ‘setInterval’ from the buildSnowStorm() function. This will clear the context/canvas and then loop around all our ‘snowball’ objects running each ones ‘update()’ method. As a result the context/canvas is redrawn with each ‘snowball’ object in its new position. This occurs every 50 milliseconds and so we are fooled into thinking it is snowing and we need hats and gloves.

function draw(){

	mainContext.clearRect(0, 0, 500, 300);

	for (var i = 0; i < snowStorm.length; i++) {

	            var snowBall = snowStorm[i];
	            snowBall.update();

	 }
}

Finally from the Javascript side of things, lets kick it all off by calling the ‘buildSnowStorm()’ function.

buildSnowStorm();

To add a bit of atmosphere, (I like a party with a bit of atmosphere) I added a little CSS3 gradient magic to give it that nice wintery feel. Brrrrrrr.

canvas{
	border:1px solid #000;
	margin:20px;
	background-image: linear-gradient(bottom, rgb(60,45,71) 12%, rgb(59,93,130) 69%);
	background-image: -o-linear-gradient(bottom, rgb(60,45,71) 12%, rgb(59,93,130) 69%);
	background-image: -moz-linear-gradient(bottom, rgb(60,45,71) 12%, rgb(59,93,130) 69%);
	background-image: -webkit-linear-gradient(bottom, rgb(60,45,71) 12%, rgb(59,93,130) 69%);
	background-image: -ms-linear-gradient(bottom, rgb(60,45,71) 12%, rgb(59,93,130) 69%);
	background-image: -webkit-gradient(linear,left bottom,left top,color-stop(0.12, rgb(60,45,71)),color-stop(0.69, rgb(59,93,130)));
}

Ah lovely. And here is the whole lot to cut and paste.

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Must Be Snowing!</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js">
</script>
<script language="javascript">

$(document).ready(function(){
	
var mainContext = $('#myCanvas')[0].getContext("2d");	
var snowStorm = new Array();
var noOfSnowFlakes = 25;

function Snow(context, speed, width, xPos, yPos){
	this.context = context;
	this.speed = speed;
	this.width = width;
	this.xPos = xPos;
    this.yPos = yPos;
}

Snow.prototype.update = function () {
	this.context.beginPath();
	this.context.arc(this.xPos, this.yPos, this.width, 0, Math.PI*2, false);
	if(this.yPos > 305){
		this.yPos = -5;	
	}
	if(this.xPos > 505){
		this.xPos = 0;	
	}
	this.xPos = this.xPos + this.speed;
	this.yPos = this.yPos + this.speed;
	this.context.closePath();
	this.context.fillStyle = "#FFFFFF";
	this.context.fill();
}



function buildSnowStorm(){
	for (var i = 0; i < noOfSnowFlakes; i++) {
		var randomW = Math.round(Math.random() * 5) +2;
		var randomX = Math.round(Math.random() * 500);
	    var randomY = Math.round(Math.random() * 300);
		
		var snowBallAr = new Snow(mainContext, randomW, randomW, randomX, randomY);	
		snowStorm.push(snowBallAr);
	}
	setInterval(draw, 50);
}

function draw(){
	
	mainContext.clearRect(0, 0, 500, 300);
	
	for (var i = 0; i < snowStorm.length; i++) {

	            var snowBall = snowStorm[i];
	            snowBall.update();
	 
	 }
}

buildSnowStorm();
});
</script>
<style type="text/css">
body{
	padding:0;
	margin:0;	
}
canvas{
	border:1px solid #000;
	background-image: linear-gradient(bottom, rgb(60,45,71) 12%, rgb(59,93,130) 69%);
	background-image: -o-linear-gradient(bottom, rgb(60,45,71) 12%, rgb(59,93,130) 69%);
	background-image: -moz-linear-gradient(bottom, rgb(60,45,71) 12%, rgb(59,93,130) 69%);
	background-image: -webkit-linear-gradient(bottom, rgb(60,45,71) 12%, rgb(59,93,130) 69%);
	background-image: -ms-linear-gradient(bottom, rgb(60,45,71) 12%, rgb(59,93,130) 69%);
	background-image: -webkit-gradient(linear,left bottom,left top,color-stop(0.12, rgb(60,45,71)),color-stop(0.69, rgb(59,93,130)));
}
</style>
</head>
<body>
<canvas id="myCanvas" width="500" height="320">
</canvas>
</body>
</html>

One Thought to “HTML5 Canvas Snow Storm”

  1. Fine, looks good in mobile devices, I like that.

    Regards

Leave a Reply to Filipo Grand Cancel reply