Welcome to the first of what I hope will be many tutorials at RectangleWorld! For the inaugural tutorial we will look at a very simple example for beginners: drawing objects to the canvas which can be dragged around with the mouse. We will extend this basic example in subsequent tutorials. Click here or on the screenshot below to see the demo.


SimpleDragging screencap

Download

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

About the Code

I won’t attempt to explain every line of the HTML and JavaScript code used in this example; instead you may find it instructive to simply download the commented source and study it carefully. The basics of creating a canvas application can be found in several books; the basic setup I am using here is covered very carefully in HTML5 Canvas by Fulton & Fulton. If you are unfamiliar with JavaScript you may also find it necessary to do a little reading on the topic; for example see JavaScript: The Definitive Guide (and by the way, no, I’m not affiliated with O’Reilly publishing!). A good on-line introduction to the HTML5 Canvas can be found at the Mozilla Developer Network site here.

Mouse Events

This example features mouse interactivity. The code has to set up listeners for mouse events. For example, to listen for a mouse down event we include the code

theCanvas.addEventListener("mousedown", mouseDownListener, false);

Here, theCanvas was defined earlier in the code and references a canvas which has been placed in the html page. The line of code above establishes an action to take if any mousedown events occur over the canvas: the function mouseDownListener will be called (the Boolean parameter false means that the mousedown event will not be captured).

Note that once a mousedown event occurs, there are lines of code added in the listener function to take the appropriate action when the mouse moves or if the mouse button is released. For example:

window.addEventListener("mouseup", mouseUpListener, false);

Note that the mousemove and mouseup event listeners are attached to the whole document window, because if the user drags the mouse outside of the canvas area while holding the mouse button down, we still want mouse actions to have an effect.

The Display Objects

If you’re coming from a Flash and ActionScript background, you’re accustomed to working with a display list with separate display objects, each of which can have its own mouse event listeners. But in the HTML5 Canvas, there is one display object which essentially works like a big bitmapdata object, and all display objects have to be drawn to this display. Mouse events can only be detected as occuring over the whole display – not on individual objects. So we will have to listen for mouse down events occuring over the whole canvas, then check if the mouse location was over any of the positions where we have drawn an object.

The display objects in this example will all be filled circles, and will in fact be represented by abstract JavaScript Objects, each of which simply records the position, radius, and color of the shape. We define one of these shapes with the code:

tempShape = {x:tempX, y:tempY, rad:tempRad, color:tempColor, layer:i};

where the variables tempX, tempY, etc., were defined in previous lines by randomization. These Objects are stored in the array called shapes. When it comes time to draw these objects to the canvas, we use the code

context.fillStyle = shapes[i].color;
context.beginPath();
context.arc(shapes[i].x, shapes[i].y, shapes[i].rad, 0, 2*Math.PI, false);
context.closePath(); context.fill();

Since the objects in this example will be filled in circles, it will be easy to check if the mouse coordinates are over one of our objects by a simple test to see whether the distance from the center is less than the radius of the circle. We will check each circle to see if the mouse coordinates are over that object, and by paying attention to the layering order of the objects we will only move the topmost object.

Checking each object for “hit test” with the mouse coordinate position could be very inefficient in a situation where we would have a very long list of objects. In such a situation, we would have to make use of a data structure like a quadtree to pre-sort the objects as they are placed on the canvas, in order to avoid checking all objects for a hit. But with a small number of objects, checking all objects for a hit will work fine.

You will notice that in this example when dragging the objects, the layering order is preserved. This is because the objects are always drawn in the same order based on their array order. We might wish to have the currently dragged object appear in front of all the other objects so that we can see it while dragging. We will add some code in our next tutorial to create this effect.

Acknowledgments:

  • Checking to see whether the browser supports the canvas tag is done with the Modernzr JavaScript library, available at http://www.modernizr.com
  • Code for the basic setup used here is copied from HTML5 Canvas by Fulton & Fulton. This book is an excellent resource for anyone looking to get started in HTML5 Canvas development.