Doodle - Part 4: More Power to the User / Page 3 | WebReference

Doodle - Part 4: More Power to the User / Page 3


Doodle - Part 4: More Power to the User [con't]

Canvas Widgets

Each shape is different; they appear differently to the user and may have different numbers of required or optional control points. Additionally, different shapes may offer different modes of manipulation and processing user input. Let's have a look at some of these differences:

Shape Behavior
Point Creates a point on the canvas on mouse down. No further editing is necessary.
Line Creates a line on the canvas on mouse down with starting point at mouse position. Initially the start and end point are the same but as the user drags the mouse with the mouse button down, the second end point is adjusted. When the user releases the mouse button, the line is completed and editing stops.
Ellipse Creates an ellipse on the canvas on mouse down with one corner at mouse position. Like the line, the two opposing corners start together and as the user drags the mouse, the second corner is adjusted. Editing is complete when the user releases the mouse button.
Bezier Curve Creates a bezier curve on the canvas on mouse down. Initially the curve will have two control points both at the current mouse position. As the user moves the mouse, the final control point is adjusted. For each click, an internal control point is added at the mouse position. Editing completes when the user double clicks to fix the final control point position.

The point, with its minimal requirements is the easiest to implement.

The create() function gets the mouse position on the canvas and creates a document point for that position. After the Widget.create() function is called, the Point widget may be unselected. No further code is necessary.

The line and the ellipse both require two control points and so their user interaction is very similar.

The create() function creates a document line object using the mouse down position as the start and end points (or two corners for the ellipse) and then adjusts the second end point (corner) during the mouse move so that the user can see the outcome as the mouse moves. On the mouseup event, the widget unselects itself, committing the new shape to the document.

The bezier curve collects an arbitrary number of points from the user so its interface is a little more complex.

The create function creates the document bezier object using the mouse position as the first point. It also sets the value this.bClick to true; this will be used in the onclick and mousemove event handlers.

The onclick handler also sets this.bClick to true and if the value was already true, it adds the current point to the document bezier object, too. The net result of this awkward bit of click-logic is that when the user clicks, the Bezier widget doesn't add a new control point until the mouse moves. This stops the shape of the curve from changing after the click. Once the user moves the mouse away from the control point a new one is added to the end, shadowing the mouse position.

The mousemove handler redraws the bezier using the updated position for the last control point. If this.bClick is set to true, a new point must be added to the bezier curve or the last onclick position will be lost.

Finally the onDblClick() function unselects the bezier curve. Note that there is no need to update the position of the last control point as this will have been done in the onMouseMove() handler.

Download the Code

Right click the links below and select "Save Link As ..." [Firefox] or "Save Target As" [IE] to download copies of the demo code.


In this article, Doodle has gained a number of new shape types enhancing the user's experience with the canvas.

  • A new Control class heirarchy was introduced to manage user control of application state. A DropList control binds HTML <select> controls to the application.
  • New Document shapes and Canvas Widgets were created to store and manipulate information about the new shapes.
  • The Canvas was enhanced to handle the new shapes and pass user input to the selected Widget.


While I've done my best to make this code as browser compatible as possible, I've only tested it with Internet Explorer (7.0) and Firefox (1.5) as this represents of a large proportion of users.

About the Author

Guyon Roche is a freelance Web developer in London, Great Britain. He specializes in Windows platforms with an interest in bridging the gaps between different technologies, visit for more details.

Original: April 4, 2007

Digg This Add to