Building Pipes JS

Hello guys, It’s been so long since i posted last. So this time I will cover some of the basic javascript animation concept.

You must have seen a lot of animations flowing around the entire web … from a burning candle to a full fledged solar system.
This post will mainly focus on the concept behind these animations and how to build a flawless animation.

The beginning of the tutorial could be boring to you if you are more of a practical sort of fella but it is important.

Canvas

Canvas is HTML5 element that allows you to draw something on it…like paint in Windows.. well sort of! We can do a lot of operations including adding pictures, custom polygons etc.

To perfectly understand the Canvas Element, I recommend looking over W3 website.

To put it plainly, Canvas is a box where you can draw and change things using javascript. The applications are endless if you have the imaginations. Most of the beautiful animations you see everyday on the web is build using canvas.

There is also a huge documentation available here

RequestAnimationFrame

The Window.requestAnimationFrame() method tells the browser that you wish to perform an animation and requests that the browser call a specified function to update an animation before the next repaint. The method takes as an argument a callback to be invoked before the repaint.

Check documentation here.

 

Now for the project, we will be building 3D PIPES screensaver which could be seen in Windows XP. So Let’s Build our Screensaver.

HTML

Like most of my posts, the HTML part is always simple. We will only have one Canvas element in the body.
Let’s give it a width of 800px and height 0f 500px to get started. The ID ‘myCanvas’ is important as this will be used to reference the canvas in javascript.

		<canvas id='myCanvas' width='800' height='500'></canvas>
	

CSS

The CSS part of the project is also very simple. You can either include it in the index file or in a separate file. I recomment using a separate file because it’s just good practice.


		body {
			background: #CCC;
		}

		canvas {
			position: absolute;
			top: calc(50% - 260px);
			left: calc(50% - 410px);

			border: 1px solid #999;
			background: #AAA;
			padding: 20px;
			border-radius: 20px;
		}

	

This will give you a beautiful canvas in the center of the website. You can change CSS according to your wishes.

Javascript

Now here comes the fun part. We will be using basic Javascript but you can also use any third party Library to speed up your coding.
As always, first comes the global variable part.

 


		/* Holder for Globals */
		var canvas, mainContext;

		/* Set the number of pipes to show */
		var limit = 3; 

		/* Arrays to hold the pipes and colors */
		var pipes = new Array();
		var colors = ['green', 'red', 'blue', 'yellow', 'purple', 'gold'];

		/* No of frames per second */
		var frames = 1;

		/* Time in milliseconds to be given for a single pipe to flow */
		var timeForLine = 200;

	

The comments are a very good coding practice so make sure to add plenty. The frames is used to control the speed of the animation. Rest of the variables will be explained as we use them.

Since we want the pipes to move randomly, so we declare a method to return us a random integer between a range.


		var getRandom = function(min, max) {
			return Math.floor(Math.random() * (max - min)) + min;
		}

	

In Javascript, we don’t have classes. So to build a Object Oriented Project, we have to do a work around. we will use the prototype property of the object. so to declare a class, we will define a method that has multiple prototypes.
To start off, Build a simple method with parameters related to the pipes. In this case, we will take color and width.


		var Pipe = function(color, width) {
			...
		}

	

Now set the attributes of the object. A currentX and currentY attribute is taken to keep track of the current position of the pipe insode the canvas. We will random position the pipe on the left side of the canvas.


			...
			this.color = color;
			this.width = width;

			// decide initial position
			this.currentX = 0;
			this.currentY = getRandom(0, canvas.height);
		}

	

Since our object is build we can refernce it by new operator. This will give us a pipe of red color and 10px wide.


		var pipe = new Pipe('red', 10);

	

Now we will initialize a lot of pipes based on the limit we set on the globals. These pipes are then stored in pipes array.
We will define a init method to do just that.


		var init = function() {

		    // Initialize all the pipes
			for(i = 0 ; i < limit; i++) {
				var line = new Pipe(colors[getRandom(0, colors.length)], getRandom(5, 30));
				pipes.push(line);
			}

			...

	

Also just go ahead and give the canvas some background. This will clear the canvas and give it a dark grey background.


		...

		// Clear the canvas and fill it with gooey color
	    mainContext.clearRect(0, 0, canvas.width, canvas.height);
	    mainContext.fillStyle = '#444';
	    mainContext.fillRect(0, 0, canvas.width, canvas.height);

	    ...

    

One last thing to add in init method is a call to DRAW method by requestAnimationFrame() method. The DRAW method will be defined in a little while.


    	...

	    	// The magic begins now
			requestAnimationFrame(draw);
		}

    

Now that we have a list of pipes, we want them to move. So we would utilize the prototype property of the object and give them two methods – UPDATE and BUILD.

Update method will update the attributes of the pipe to give us the final destination. We again used the getRandom method defined earlier.


    	Pipe.prototype.update = function() {

			// New coordinates to traverse
			this.nextX = getRandom(0, canvas.width);
			this.nextY = getRandom(0, canvas.height);

			...

    

To get smooth animation, we will divide the path a pipe has to travel into smaller path. We wil define four more attributes to pipe to defined the increments and direction of the pipe.


		    ...

		    // check the sign of the new coordinates
			if(this.nextX < this.currentX) this.signX = -1;
			else this.signX = 1;

			if(this.nextY < this.currentY) this.signY = -1;
			else this.signY = 1;

			// set increments to reach destination in timeForLine milliseconds
			this.incrementX = (this.signX) * Math.abs((this.nextX - this.currentX) / timeForLine);
			this.incrementY = (this.signY) * Math.abs((this.nextY - this.currentY) / timeForLine);
		}

    

Now we arrive at the BUILD method. The BUILD method is responsible to draw everything on the canvas. It’s a recursive method so it needs to have a exit condition. These two conditions defined does exactly that.


    	Pipe.prototype.build = function() {

			// Check for exit condition
			if(this.currentX < 0 || (this.currentX  <= this.nextX && this.signX < 0) || (this.currentX  >= this.nextX && this.signX > 0) || this.currentX > canvas.width) return;

			if(this.currentY < 0 || (this.currentY  <= this.nextY && this.signY < 0) || (this.currentY  >= this.nextY && this.signY > 0) || this.currentY > canvas.height) return;

			...

    

If you have ever worked with canvas before, These lines will make a lot of sense. But if you have never seen these lines before, I recommend looking over at WW3 canvas documentation. These lines are responsible for drawing and applying styles to the pipes inside the canvas. The moveTo() position the start point and lineTo() method draw a line from the start point to the given position.

    	...
    	// draw on canvas
		mainContext.beginPath();
	    mainContext.moveTo(this.currentX, this.currentY);
	    mainContext.lineTo(this.currentX + this.incrementX, this.currentY + this.incrementY);
	    mainContext.strokeStyle = this.color;
	    mainContext.lineWidth = this.width;
	    mainContext.lineCap = 'round';
	    mainContext.shadowBlur = 2;
	    mainContext.shadowColor = 'rgba(180, 180, 180, .6)';
	    mainContext.stroke();
	    ...

    

To allow recursive approach, the initial points must change accordingly.


    	...

    	// update current position
	    this.currentX = this.currentX + this.incrementX;
	    this.currentY = this.currentY + this.incrementY;

	    ...

    

Finally add a recursive call to the same method. It’sa little bit tricky to call the class method inside the class.


    		...

    		// recursive call
			var self = this;
		    setTimeout(function () {
		    	requestAnimationFrame(function() {
		    		self.build();
		    	});
		    }, 0);
		}

    

And we are done with the BUILD method. Now we have pipes inside an array. To call the defined method of the pipe object, we define another method called DRAW. This is also a recursive method call itself depending on the frames we defined earlier.


    	function draw() {

		    // Let's draw everything
		    for (var i = 0; i < pipes.length; i++) {
		        var line = pipes[i];
		        line.update();
		        line.build();
		    }

		    setTimeout(function() {
			    // call the draw function again!
			    requestAnimationFrame(draw);
		    }, 1000 / frames);
		}

    

Atlast we arrive at the onload method of the window object.


    	window.onload = function() {

			// Same old ... same old
			canvas = document.getElementById('myCanvas');
			mainContext = canvas.getContext('2d');

			// And here we go...
			init();
		}

    

and we are done!

Complete Source code is at github. Here is a live preview.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s