Time for yet another canvas example, this time I am thinking just a basic canvas grid example. A grid is something that will come up all the time when it comes to all kinds of canvas projects, mainly games, but other projects as well such as drawing apps and the like.
When it comes to grids there is drawing them, and then there is having a model of sorts that contains the values of the grid that is to be rendered to the canvas. I would say that it is very much a good idea to keep these things independent from each other by having one module that serves as a way to create and store the state of the grid, and another that is used to draw all of part of this grid to the canvas. The state of the grid can be a state object that has a property that contains cell objects for each cell, tile, gird location, or whatever you call it for each such instance in the grid. Another approach is to just have a width and height for the count of cells, and a cell size value and think of all cell locations in an abstract sense. That is that there are only cell objects for certain locations sort of speak. Either way I would want a way to create some kind of state object, or module for this grid, and a way to render the grid to the canvas as two independent modules.
In this example I will be starting out with a very simple Grid class example, and a single drawing method that just draws the grid lines of an instance of that grid class.
So in this section I will start out with a very basic Grid Constructor that will serve as a way to pull away the data state of the Grid away from the logic that is used to render that grid. In addition I will just have one draw method that will render the grid lines of the Grid. All other canvas examples in this post will just be improvements, additions, or just simply changes to this basic Canvas Grid example.
So for now the constructor just creates a standard object that just contains some values that outline the values of a grid such as the x and y offset values of the upper left corner of the gird in the canvas matrix. The cellSize of each grid cell or tile f you prefer, and the width and height of the gird in cell count rather than pixel size.
After I define the Gird constructor I write my first draw method that can be used to draw the current state of an instance of my Grid constructor. For now this draw method just renders the lines of the gird, a method that I might want to have when ot comes to using something like this in an actual project.
There are many ways to go about writing this kind of method, for this example I decided to go with the two loops kind of approach that seems to be common when it comes to this kind of thing. You might think that it is possible to have just one loop wrapped up into a single separate method and then just call that method twice with deferent arguments. You would be right about that and I will be getting to that in a latter section in this post, however doing so might make things more complicated then they need to be.
The draw grid lines method seems to work okay, but there is the question of drawing more than just grid lines for the canvas Grid. Doing so might require some more work on the Grid constructor, and the introduction of cell objects though, and for now I would like to keep this basic example of a Canvas Grid clean and simple.
So now for the setup of the canvas element, and to make use of what I worked out here. I start out by creating a canvas element and setting that to a variable that I also used to get a reference to the 2d drawing context. I then append that canvas element to the container element which in this case is a div element in the HTML.
I then call my Grid constructor using the new keyword,and pass some options for the grid. I then save a reference to the grid instance and use that to draw the gird lines by passing that to my draw grid lines method along with the drawing context and a style to use when stroking the grid lines.
When this example is up in running in my browser it results in a simple grid being rendered in the canvas. I can change the options that I pass to the gird constructor and that changes the state of this grid.
Not much to get excited over at this point, however in this section the aim is to just start out with a very simple canvas grid example. At this point the Grid constructor is just simply that a constructor function without any methods added to the prototype just yet. Also although my draw grid lines method is working okay I am not sure if I am happy with it, I might like replace that with something else. So lets look at some additional revisions of this in the additional sections in this post.
So as I mentioned in the previous section on the basic canvas grid example it is of course possible to create a sort of draw grid axis lines method that would then be called twice. Just a method could be called twice in the body of the draw grid lines method.
This satisfies a desire to find a way to keep from repeating the same code, but it also results in a more complicated way of doing the same thing. So maybe there is yet another way to go about doing this that will be a bit more concise, I hate making things more complicated than they need to be. I can get into adding some more features to my Grid constrictor such as cells, and then just loop threw that array of cells as a way of drawing grid lines, and also any additional drawing for the background of each cell.
So now lets make a more advanced version of the Gird constructor that introduces at least one prototype method. In addition I think it is time to have a cells array as part of the Grid constructor as well. This gird cells array will be a collection of objects, and each object can contain values like the cell position in the grid, and also an index value for a type of background for the cell. So I can just loop over this array and use that data in the drawing method, to draw grid lines as well as backgrounds.
The single prototype method will be used to build the cells array, and will be called with the constructor, but it could also be used after the instance is created to rebuild the cells of the grid.
In addition to creating a prototype method for the Grid constructor in this section I will also be going over a draw Cell lines method that will be yet another way to draw the lines of a grid, however in some respects this might be a better way of doing so, and the other draw methods that I have outlined so far may not be necessary. There is more than one way to solve a problem, and if I am going to have a cells array for my Grid constructor this might be the preferred way to go about drawing canvas Grid lines.
So here is the updated Grid constructor, things are more or less the same only now I am calling a set cells method in the body of the constructor, and of course I have that method in the prototype object of the Grid constructor.
I made it so that the set cells method can accept a single argument that is a function that will be called for each cell in the Grid. I am not sure if I really want or even need that feature though I could always just do an Array.prototype.forEach call over the cells array as it is a public property of a Grid constructor instance. This might be getting off topic for this section at least, as here I just want a slightly more advanced version of the grid constructor that introduces cells, and a single prototype method that creates that array of cells.
I have decided to go with a single linear array design rather than an array of arrays design. Having to choose between one or the other ends u being a rabbit hole of sorts for me that I wish to avoid by just simply choosing this kind of approach of that other general option that I see often.
This method should maybe be keep separate from any additional draw methods such as one that draws the backgrounds of each cell in the grid. This will help to keep things more fine grain, and also I might only want to draw grid lines alone for the grid, or I might want to draw the grid lines after drawing the backgrounds.
So now on top of having a draw method that draws the grid lines I now have a methods that will draw the backgrounds also. This method works more or less the same way, only now I am using the draw image method, and I am passing a reference to a tile sheet in the from of an image or another canvas element. This of course makes use of the background index value that I added to the cell objects.
I will not be getting into the draw image method in depth here but the first argument is of course a reference to the sheet that I will be using to draw the backgrounds, and then there are values for the source position as well as width in height when it comes to getting the tile in the tile sheet, followed by the same set of values for drawing it to the canvas.
So then once again I just need to use everything I worked out. This time I am still using the same options as before, but now I am also creating a sprite sheet as a canvas element rather than loading an extremal image, and using the canvas as the tile sheet when calling the draw cell backgrounds method.
I also set some background index properties of cell objects to something other than the default zero value. For this sheet I just have two cell values, but in a real project there would of course be many more.
When this example is working I see what I would expect I have orange tiles as the default background, and then green tiles for each one that I have set to a value of one. I then have gray grid lines over this.
This is my no means the end all be all solution for creating a canvas grid there are many different ways of going about doing this, such is the nature of programing in general of course. I was considering making more of a functional approach to this for example where there would be a method that just creates a plain old object that can then be passed to all kinds f methods that act on that object. In any case I might use what is written here in additional posts on canvas examples that make used of a grid to do something interesting.