Simple Canvas Experiment

This post is more than 2 years old.

I've been giving the HTML5 Canvas tag a bit of a hard time. It's not that I'm against the feature in general, I just don't think most of the example use cases are actually practical. I love coding for coding's sake as much as anyone else. But if you are trying to sell me on using a feature, I need to see some examples of how I'd actually use the tag on a real web site. I think Canvas works great for charting, but I've been trying to come up with additional examples of where it could be practical. Unfortunately, this is probably not a really practical example. But, it was fun to right, so being Friday afternoon I'm invoking my right to spend some time learning something by writing some code that will probably never be used.

For my example, I wanted to build code that would create a grid. I've been looking at grids quite a bit lately as my wife is in College Algebra. She is doing a lot of work with linear equations and graphing, and I thought it might be interesting to write some Canvas code that would generate a grid and then allow me to plot arbitrary points. I'll share the entire template (and a demo will be linked to at the end) and go over the code bit by bit.

<html>

<head> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script> <script> $(document).ready(function() {

var plot = $("#plot")[0];
var canvasWidth = plot.width;
var canvasHeight = plot.height;
var canvas = plot.getContext("2d");
var tickWidth = "";
var radius="";

console.log("My plot is "+canvasWidth+" wide by "+canvasHeight+" high");

//Given a value N which represents how many hashes to max on the axis, I draw
//a grid with N hashes on each side of the axis
function drawGrid(n) {

	//tick width is how far between hashes
	tickWidth = canvasWidth/(n*2);
	//tick length is how big to make it
	var tickLength = canvasHeight/40;
	//radius, which is used later, is also based on size
	radius = canvasWidth/100;
	
	console.log("Tick width is "+tickWidth);

	//y axis
	canvas.moveTo(canvasWidth/2,0);
	canvas.lineTo(canvasWidth/2, canvasHeight);		
	canvas.stroke();

	//x axis
	canvas.moveTo(0, canvasHeight/2);
	canvas.lineTo(canvasWidth, canvasHeight/2);
	canvas.stroke();
	
	//now for the ticks on the y-axis, yes, 
	//we end up 'drawing over' the x-axis one
	canvas.beginPath();
	canvas.moveTo(canvasWidth/2, 0);
	
	for(var i=1; i&lt;(n*2); i++) {
		console.log(i+ " Moving to "+(canvasWidth/2-tickLength)+","+(i*tickWidth));
		canvas.moveTo(canvasWidth/2-tickLength, i*tickWidth);
		canvas.lineTo(canvasWidth/2+tickLength, i*tickWidth);

		canvas.stroke();
	} 

	//now for the ticks on the x-axis, yes, 
	//we end up 'drawing over' the y-axis one
	canvas.beginPath();
	canvas.moveTo(0, canvasHeight/2);
	
	for(var i=1; i&lt;(n*2); i++) {
		console.log(i+ " Moving to "+(i*tickWidth)+","+(canvasHeight/2-tickLength));
		canvas.moveTo(i*tickWidth,canvasHeight/2-tickLength);
		canvas.lineTo(i*tickWidth,canvasHeight/2+tickLength);

		canvas.stroke();
	} 
	
		
}

function drawPoint(point) {
	var x = point[0];
	var y = point[1]; 
	console.log("going to draw point "+x+","+y);
	canvas.beginPath();
	canvas.arc(canvasWidth/2+(x*tickWidth), canvasHeight/2-(y*tickWidth), radius, 0, Math.PI * 2, false);
	canvas.closePath();
	canvas.stroke();
	canvas.fill();
	
}

drawGrid(10);
//initial data points
var points = [
	[1,2],
	[2,4],
	[-2,6],
	[2,1],
	[-4,-4]
	];
	
$.each(points, function(n,point) {
	drawPoint(point);
});

}) </script> <style> canvas { background-color:ghostwhite; } </style> </head>

<body>

&lt;canvas id="plot" width="500" height="500"&gt;&lt;/canvas&gt;

</body> </html>

I decided to use jQuery for this even though I really didn't make heavy use of it. I think I have a grand total of one selector and the each() operator. If this were production code I'd not use jQuery just for that. That being said, jQuery makes everything a little more awesome. Like unicorns and rainbows. So why not include it?

On top of my code I've got a few variables I'll be using throughout. You can see where I create a canvas object (basically by taking the canvas tag and grabbing the 2d context). I remember the size of the canvas tag and have a few other variables that will be setup later on.

The first big function, drawGrid, handles drawing the X and Y axis as well as the hash marks. In general this is just simple math. The size of my "ticks" are based on the total height and sized to what I thought looked nice. You can see I set up my radius value here too. This will be used later on when drawing points.

The drawPoint method simply handles inverting a simple X,Y coordinate to the right position for a Canvas element. Canvas treats the upper left corner as 0,0, so once again math is used to treat 0,0 as the center of the grid. I also need to handle "shifting" over based on the tickWidth value I created earlier. Once I've done that it's a simple matter of drawing a complete arc.

After this code I've got the calls to setup my grid and create some sample data. Finally I loop over each point and plot it. The main block of functionality could be packaged up into a real Grid object. I'll be honest though. I'm still wrapping my head around JavaScript encapsulation so I'll be coming back to it later. Anyway, click the Demo button below for - well - the demo.

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by andy matthews posted on 9/24/2011 at 1:56 AM

You didn't provide inputs so that I could add my own plots?

Comment 2 by Raymond Camden posted on 9/24/2011 at 1:58 AM

No. I thought about it - but then I decided - I will not do anything to help Andy. Andy is evil. He will use the plots to probably draw something cool and remind people how poor my own design skills are. Therefore - no points for you.

Comment 3 by Jaana Gilbert posted on 9/24/2011 at 2:11 AM

So far I've seen quite a nice implementation of Captcha with Canvas. It's still in works, but the one I tested was quite nice.
http://befungle.com/

Comment 4 by Edward Beckett posted on 9/24/2011 at 2:39 AM

Hmm ... Looks fine in Chrome But I can't see the coords in FF 3.6.22 ...

Comment 5 by Raymond Camden posted on 9/24/2011 at 2:44 AM

Edward - I made use of console.log. Do you have Firebug installed?

Jaana - Ok - that's a good use too. But I'd be worried about any client side implementation of captcha.

p.s. I hope folks know that I know Andy well and that I was only teasing.

Comment 6 by Edward Beckett posted on 9/24/2011 at 3:13 AM

Ah ... yes ... I should have read the code ... Nice :-)

Comment 7 by andy matthews posted on 9/24/2011 at 5:07 AM

I'm shocked and offended (and offended and shocked)...I like to have it both ways what can I say?