Canvas Grid Part 3

Last time we managed to create a very simple grid and change colors when you clicked on a cell. But, being a first attempt the grid wasn’t flexible and it had a lot of duplicated code. In this post we are going to improve it. Before we start, let’s take a look at the finished result.

Click a square var Grid = { //Canvas Size canvasWidth: 300, canvasHeight: 300, //Columns and Rows numberOfColumns: 5, numberOfRows: 5, //Size of the cells cellWidth: function() { return this.canvasWidth/this.numberOfColumns; }, cellHeight: function() { return this.canvasHeight/this.numberOfRows; }, //Draw the GridLines drawGrid: function(display){ display.beginPath(); //Draw the Vertical lines for(var i=0; i < this.numberOfColumns; i++){ //Move to the top of the canvas display.moveTo(i*this.cellWidth(), 0) //Draw the line display.lineTo( i*this.cellWidth(), this.canvasHeight ); } //Draw the Horizontal lines. for(var i=0; i < this.numberOfRows; i++){ //Move to the left of the canvas display.moveTo(0, i*this.cellHeight()) //Draw the line display.lineTo( this.canvasWidth, i*this.cellHeight() ); } display.stroke(); }, //Find which cell was clicked. cellMouseIn: function(evt, offset){ //Create an Object to hold the column/row var position = { column: -1, row: -1, }; //Find the poistion of the mouse var x_pos = Math.floor(evt.pageX – offset.left); var y_pos = Math.floor(evt.pageY – offset.top); //Now which column was it clicked? for(var column=0; column < this.numberOfColumns; column++){ //Find the column if( x_pos > column*this.cellWidth() && x_pos < (column+1)*this.cellWidth() ){ //Found it! position.column = column; //Fow find the row for(var row=0; row < this.numberOfRows; row++){ //Find the row if( y_pos > row*this.cellHeight() && y_pos < (row+1)*this.cellHeight()){ //Found it! position.row = row; } } //End Row } } // End Column //Return the found position return position; }, //(re)Draw a cell at the position. drawCell: function(display, position){ var y_pos = position.row * this.cellHeight(); var x_pos = position.column * this.cellWidth(); //Draw the cell display.fillRect( x_pos, y_pos, this.cellWidth(), this.cellHeight()); //ReDraw the grid this.drawGrid(display); }, }; var display; //This is going to be our Drawing Context $(document).ready(function(){ //Setup the Canvas $(“#display”).attr({ width: Grid.canvasWidth, height: Grid.canvasHeight, }) /* Register Events */ .bind(“mousedown”, onMouseDown) .bind(“mouseup”, onMouseUp); //Get the context display = $(“#display”)[0].getContext(“2d”); //Draw it draw(); }); function onMouseDown(evt){ //Change the Squares Color. display.fillStyle = “#0F0”; display.strokeStyle = “#FFF”; //Get the cell That the mouse is in var position = Grid.cellMouseIn(evt, $(“#display”).offset() ) //Now redraw it Grid.drawCell(display, position); //Now display the cell info $(“#text”).html( position.column +”,”+ position.row); } function onMouseUp(evt){ //Change the color back. display.fillStyle = “#000”; display.strokeStyle = “#FFF”; //Get the cell That the mouse is in var position = Grid.cellMouseIn(evt, $(“#display”).offset() ) //Now redraw it Grid.drawCell(display, position); } //Draw on the Canvas function draw(){ //Lets draw the outline of four squares on a black canvas. //Draw the background display.fillStyle = “#000”; display.fillRect(0,0, Grid.canvasWidth, Grid.canvasHeight); //all the squares will be white. display.strokeStyle = “#FFF”; display.lineWidth = 2; //Tell the Grid to draw Grid.drawGrid(display); }

Let’s start by creating a Grid object. This object should have the basic properties for a grid.

var Grid = { //Canvas Size canvasWidth: 300, canvasHeight: 300, //Columns and Rows numberOfColumns: 5, numberOfRows: 5, //Size of the cells cellWidth: function() { return this.canvasWidth/this.numberOfColumns; }, cellHeight: function() { return this.canvasHeight/this.numberOfRows; }, };

Now we have one place to adjust the size of the Canvas, the number of rows/columns, and the cell sizes will be automatically calculated.

We also need to adjust the setup of the Canvas to use the grid.

//Setup the Canvas $(“#display”).attr({ width: Grid.canvasWidth, height: Grid.canvasHeight, });

Now we need to actually draw the grid. Last time I just drew outlines of squares, but I think it will be easier this time to simply draw lines.

//Draw the GridLines drawGrid: function(display){ display.beginPath(); //Draw the Vertical lines for(var i=0; i < this.numberOfColumns; i++){ //Move to the top of the canvas display.moveTo(i*this.cellWidth(), 0) //Draw the line display.lineTo( i*this.cellWidth(), this.canvasHeight ); } //Draw the Horizontal lines. for(var i=0; i < this.numberOfRows; i++){ //Move to the left of the canvas display.moveTo(0, i*this.cellHeight()) //Draw the line display.lineTo( this.canvasWidth, i*this.cellHeight() ); } display.stroke(); },

Now we can simply tell the Grid to draw its self. It will draw properly no matter how many rows and columns we want, and we can adjust the size of the canvas.

To handle clicking on the grid, we need two more methods. One to know which cell the user clicked on, and one to redraw a specific cell.

//Find which cell was clicked. cellMouseIn: function(evt, offset){ //Create an Object to hold the column/row var position = { column: -1, row: -1, }; //Find the poistion of the mouse var x_pos = Math.floor(evt.pageX – offset.left); var y_pos = Math.floor(evt.pageY – offset.top); //Now which column was it clicked? for(var column=0; column < this.numberOfColumns; column++){ //Find the column if( x_pos > column*this.cellWidth() && x_pos < (column+1)*this.cellWidth() ){ //Found it! position.column = column; //Fow find the row for(var row=0; row < this.numberOfRows; row++){ //Find the row if( y_pos > row*this.cellHeight() && y_pos < (row+1)*this.cellHeight()){ //Found it! position.row = row; } } //End Row } } // End Column //Return the found position return position; }, //(re)Draw a cell at the position. drawCell: function(display, position){ var y_pos = position.row * this.cellHeight(); var x_pos = position.column * this.cellWidth(); //Draw the cell display.fillRect( x_pos, y_pos, this.cellWidth(), this.cellHeight()); //ReDraw the grid this.drawGrid(display); },

Now all we have to do is adjust our onMouseDown and onMouseUp functions to use the grid, and register these events.

var display; //This is going to be our Drawing Context $(document).ready(function(){ //Setup the Canvas $(“#display”).attr({ width: Grid.canvasWidth, height: Grid.canvasHeight, }) /* Register Events */ .bind(“mousedown”, onMouseDown) .bind(“mouseup”, onMouseUp); //Get the context display = $(“#display”)[0].getContext(“2d”); //Draw it draw(); }); function onMouseDown(evt){ //Change the Squares Color. display.fillStyle = “#0F0”; display.strokeStyle = “#FFF”; //Get the cell That the mouse is in var position = Grid.cellMouseIn(evt, $(“#display”).offset() ) //Now redraw it Grid.drawCell(display, position); //Now display the cell info $(“#text”).html( position.column +”,”+ position.row); } function onMouseUp(evt){ //Change the color back. display.fillStyle = “#000”; display.strokeStyle = “#FFF”; //Get the cell That the mouse is in var position = Grid.cellMouseIn(evt, $(“#display”).offset() ) //Now redraw it Grid.drawCell(display, position); } //Draw on the Canvas function draw(){ //Lets draw the outline of four squares on a black canvas. //Draw the background display.fillStyle = “#000”; display.fillRect(0,0, Grid.canvasWidth, Grid.canvasHeight); //all the squares will be white. display.strokeStyle = “#FFF”; display.lineWidth = 2; //Tell the Grid to draw Grid.drawGrid(display); }

That’s it! There are still some bugs with it, but it works for the most part.