[Update: This post was written in my early days of JavaScript. Although the main ideas are good, my use of separate JavaScript files for holding object prototype definitions is probably misguided. I was following an ActionScript paradigm too closely. The JavaScript should probably all be in one place together.]

Welcome to the next installment in a series of simple HTML5 Canvas tutorials. In our previous posts, we presented a simple example of dragging objects with the mouse, and then later extended this example with some more advanced features:

Although the new example in this post looks very similar on the surface — display objects which can be dragged with the mouse — behind the scenes in the code there are some significant differences. Here we will use our dragging example to illustrate object-oriented programming in JavaScript. We will use classes to represent the display objects. These classes are JavaScript Objects which include methods both for drawing the particles and for determining whether a given point hits the display object.

Click here or on the screenshot below to see the demo.

OOPDragging screencap

Download

Download the complete, well-commented source code here: OOPDragging.zip

About the Code

The basic ideas behind detecting mouse events over display objects, and creating smooth motion were covered in the earlier tutorials referenced above. Here we are using this simple dragging example as a context for discussing object-oriented programming in JavaScript.

The display object classes

If you are coming from a different coding experience, then the construction of a JavaScript class will look a lot different from, say, an ActionScript class. But the idea is the same: the class defines an object which retains information about its properties, along with methods for performing important tasks related to that object. In our example here we define two separate display object classes: a SimpleDiskParticle representing a filled-in circle and a SimpleSquareParticle representing a filled-in square. These are not the most exciting display objects, but the simplicity will allow us to concentrate on the coding method.

When we create a new “particle” using one of these classes, we will be creating a JavaScript Object which retains information about the position, size, and color of the particle. The SimpleDiskParticle and the SimpleSquareParticle both include a drawToContext() method for drawing the particle to a canvas context, as well as a hitTest() method that we will use to see if a mousedown event occurs over the particle.

These classes are very simple. Let’s take a look at the complete code for the SimpleDiskParticle class, which is defined in the separate SimpleDiskParticle.js file. The class could also have been created within the main application; the external file is simply used for organizational purposes (and it also mimics the way classes are defined in ActionScript). The SimpleDiskParticle code begins with a constructor:

function SimpleDiskParticle(posX, posY) {
     this.x = posX;
     this.y = posY;
     this.color = "#FF0000";
     this.radius = 10;
}

Note the use of the keyword this which refers to the current object being defined by the constructor function. The consturctor simply defines an object and attaches to it some needed properties. Later when we want to create a new SimpleDiskParticle at the position with coordinates (tempX, tempY), we will use the new keyword:

tempShape = new SimpleDiskParticle(tempX, tempY);

Note that the constructor takes as an argument the desired coordinates, and it also sets a default color and size for the particle. The color and size can be changed later if we like by explicitly setting these properties to new values. We will show how these classes are used later.

We now build the functions which will handle drawing the particle and performing a hit test. These functions must be attached to a prototype object. Each newly created SimpleDiskParticle will inherit these functions from the prototype object. This is essentially the same thing as defining an instance method for an ActionScript (or Java) class. The drawing and hit test functions are defined as follows:

SimpleDiskParticle.prototype.drawToContext = function(theContext) {
     theContext.fillStyle = this.color;
     theContext.beginPath();
     theContext.arc(this.x, this.y, this.radius, 0, 2*Math.PI, false);
     theContext.closePath();
     theContext.fill();
}

SimpleDiskParticle.prototype.hitTest = function(hitX,hitY) {
     var dx = this.x - hitX;
     var dy = this.y - hitY;
     return(dx*dx + dy*dy < this.radius*this.radius);
}

Note that the hit test is based on the circular geometry of the particle, as explained in our first post in this series.

Of course, a square particle has to be drawn differently, and its geometry requires a hit test to be done differently. So by associating the drawing and hit test functions with the individual particles, we can simply call these instance methods in our main code and the methods will do the right thing depending on what type of object we are dealing with. We will explain this in more detail below.

Using the classes in the main code

The basic set up for this example is the same as the two previous examples in this series. What has changed is how we create new display objects to add to our array shapes, and how we draw these shapes and perform hit tests with the instance methods described above. We already explained above how the new keyword is used to create new instances of our particle classes. Let's take a look at it in context. Within the makeShapes function, and inside a for-next loop iterated to create several objects, we create a random color tempColor, including a randomized alpha (transparency) value, and select a random point with coordinates (tempX, tempY). Then we randomly create either a disk or square particle and initialize its position at the point (tempX, tempY):

if (Math.random() < 0.5) {
     tempShape = new SimpleDiskParticle(tempX, tempY);
}
else {
     tempShape = new SimpleSquareParticle(tempX, tempY);
}

After this is done, we explictly set the size and color of the newly created particle, changing these values from the default values which were set inside the constructor:

tempShape.color = tempColor;
tempShape.radius = tempRad;

Finally, we add the new shape to our array:

shapes.push(tempShape);

The array shapes now contains a list of our particles. Some of these particles are disk particles, some are squares. Later, when we want to test whether a mouse position (mouseX, mouseY) hits the particle shapes[i] in our array, we simply check the Boolean value returned by the hitTest function associated with the particle: shapes[i].hitTest(mouseX, mouseY). The beauty of the object-oriented approach is that the function hitTest will do the right thing depending on what kind of shape shapes[i] is.

Similarly, when we draw the particles inside the drawShapes() function, we simply need to call the drawing method associated to the particle class:

for (i=0; i < numShapes; i++) {
     shapes[i].drawToContext(context);
}

Note that we have to pass to this function the canvas context to which we would like to draw the particles.

To see this all put together, download the source code.