Scribble app with HTML5

The “canvas” is one of the new elements in HTML5, it provides a drawing surface and APIs for yes you guessed it…drawing. The actual drawing is done through JavaScript. I’m going to show you a simple Scribble app that uses the canvas. It should be very straightforward and will help you get familiar with the canvas.

Before we begin I want to have a word about development tools for HTML5. Basically you can use any text editor to write HTML and JavaScript code. There are more sophisticated editors that provide syntax highlighting and basic debugging features such as Notepad++.

For this app I used Visual Studio 2010 SP1. The reason for my choice is that VS2010 SP1 now supports HTML5 and CSS3. That means you get syntax highlighting , Intellisense and some debugging capabalities (IE only). I know VS2010 is not free but you can get your hand on Microsoft’s Visual Web Developer 2010 Express which is free and also supports HTML5. Microsoft will be updating Visual Studio every 3 months to keep it up to date with the latest HTML5 standard changes.

Enough talking, lets dive into the code. First we will design the HTML page, on top we will have 2 drop down lists for selecting the colour and the line width along with a button to clear the canvas. Below these controls we will add the canvas. To achieve this I am using a simple table layout. Here is the HTML for the page:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Scribble</title>
</head>
<body>
    <table>
        <tr>
            <td>
                Colour:
            </td>
            <td>
                <select id="ddlColour" onchange="ddlColour_onChange();">
                    <option value="#000000">Black</option>
                    <option value="#FF0000">Red</option>
                    <option value="#00FF00">Green</option>
                    <option value="#0000FF">Blue</option>
                </select>
            </td>
            <td>
                Line Width:
            </td>
            <td>
                <select id="ddlLineWidth" onchange="ddlLineWidth_onChange();">
                    <option value="1">1</option>
                    <option value="3">3</option>
                    <option value="5">5</option>
                    <option value="10">10</option>
                </select>
            </td>
            <td>
                <input id="btnClear" value="Clear" type="button" onclick="btnClear_onClick();" />
            </td>
        </tr>
    </table>
    <canvas id="mainCanvas" width="400" height="400" style="border: 1px solid #000;">
    </canvas>
</body>
</html>

There are few things I want to point out, the first line in the HTML file:

<!DOCTYPE html>

This line indicates that the HTML version is HTML5. You probably noticed the canvas element, there is nothing fancy about the markup for the canvas. The width and height are set and the canvas is given a border (so we actually know where we are drawing) and the canvas is given an ID so we can access it in JavaScript. I also added event handlers to the drop down lists and the button, in a bit we will see what these do.

If you open the HTML page in a browser (preferably Chrome) you will see a page that looks something like this:

At this point the app does nothing, it’s still not functional. We need to add the JavaScript Code that will contain the drawing logic.

We need some variables which we will use later.

var doDraw = false;
var mainCanvas, canvasContext;
var xCoords = new Array();
var yCoords = new Array();
var colour = new Array();
var isMouseDownEvent = new Array();
var lineWidth = new Array();

The first and most important function is the “window.onload” function

window.onload = function () {

    //Get canvas element
    mainCanvas = document.getElementById('mainCanvas');
    if (!mainCanvas) {
        alert('No canvas found !');
        return;
    }

    //Check for canvas support
    if (!mainCanvas.getContext) {
        alert('Sorry, your browser does not support the canvas element :(');
        return;
    }

    //Get canvas context
    canvasContext = mainCanvas.getContext('2d');

    //Attach the event handlers
    mainCanvas.addEventListener('mousemove', mainCanvas_mouseMove, false);
    mainCanvas.addEventListener('mousedown', mainCanvas_mouseDown, false);
    mainCanvas.addEventListener('mouseup', mainCanvas_mouseUp, false);
}

This function is responsible for 2 main things:

  1. Checking for canvas support in the browser. This is done by retrieving the canvas object and checking for the “getContext” method. If this method exists in the returned object then the browser supports the canvas element, otherwise the user should upgrade his browser.
  2. Attach the event handlers to the canvas element.

Notice that we are retrieving the “2D” context. The 2D context is responsible for everything 2D, it provides the APIs necessary for 2D drawing.

Now we want to change the line colour and width when the user changes the value from the drop down lists.

//Change the drawing colour
function ddlColour_onChange() {

    var ddlColour = document.getElementById('ddlColour');
    canvasContext.strokeStyle = ddlColour.options[ddlColour.selectedIndex].value;
}

//Change the line width
function ddlLineWidth_onChange() {

    var ddlLineWidth = document.getElementById('ddlLineWidth');
    canvasContext.lineWidth = ddlLineWidth.options[ddlLineWidth.selectedIndex].value;
}

There is nothing fancy about this code, we set the line colour by assigning a value to “canvasContext.strokeStyle” and we set the line width by assigning a value to “canvasContext.lineWidth”.

Now onto the drawing itself, we want to control what happens when the user presses down on a mouse button, what happens when the user moves the mouse and what happens when the user lifts up the mouse button.

When a mouse button is pressed down we want to record the click location, the current properties of the canvas.

//Start drawing when a mouse button is pressed
function mainCanvas_mouseDown(args) {
    xCoords.push(args.layerX);
    yCoords.push(args.layerY);
    colour.push(canvasContext.strokeStyle);
    lineWidth.push(canvasContext.lineWidth);
    isMouseDownEvent.push(true);
    doDraw = true;
}

The “doDraw” variable is set to true, this variable will be used to indicate that a mouse button is pressed. The reason for this is that we do not want to draw anything on the canvas if the mouse is moving without pressing down onto a button. Here is he variable in action in the “mainCanvas_mouseMove” function:

//The event handler that does the actual drawing
function mainCanvas_mouseMove(args) {

    if (doDraw) {

        xCoords.push(args.layerX);
        yCoords.push(args.layerY);
        colour.push(canvasContext.strokeStyle);
        lineWidth.push(canvasContext.lineWidth);
        isMouseDownEvent.push(false);
        redraw();
    }
}

If “doDraw” is set to “false” no drawing will take place when the mouse moves. Again we are saving the current mouse location and canvas properties. Then the “redraw” function is called (we’ll get to that in a moment).

When the mouse button is released we want to stop drawing on the canvas, “mainCanvas_mouseUp” does exactly that:

//Stop drawing when the mouse is released
function mainCanvas_mouseUp(args) {
    doDraw = false;
}

Onto the “redraw” function, this function is responsible for drawing the lines onto the canvas:

//Do the actual drawing
function redraw() {
    //Clear canvas
    mainCanvas.width = mainCanvas.width;

    for (i = 0; i < xCoords.length; i++) {

        canvasContext.beginPath();
        if (!i || isMouseDownEvent[i]) {
            canvasContext.moveTo(xCoords[i], yCoords[i]);
        }
        else {
            canvasContext.moveTo(xCoords[i - 1], yCoords[i - 1]);
        }

        canvasContext.lineTo(xCoords[i], yCoords[i]);

        canvasContext.closePath();

        //Stroke properties
        canvasContext.strokeStyle = colour[i];
        canvasContext.lineWidth = lineWidth[i];
        canvasContext.lineCap = 'round';
        canvasContext.lineJoin = 'round';
        canvasContext.stroke();
    }
}

First we want to clear the canvas, the easiest way to do this is to set the canvas width property to itself. “canvasContext.moveTo” moves the cursor to a given X,Y coordinate. “canvasContext.lineTo” draws a line to a given X,Y coordinate.

Surprisingly “canvasContext.lineTo” doesn’t render any drawing, it just draws invisible lines. To actually ink in the line we call the “canvasContext.stroke” function. Before calling it we tell the canvasContext how we want it to render our lines (strokeStyle, lineWidth…etc.)

When you string it all together you should have a working Scribble app 😀

That was a simple demo of the HTML5 canvas element. You can get the source code for the Scribble app here.

I’m sure there are more sophisticated effects that can be achieved using the canvas APIs but I’m still learning about HTML5 🙂 All comments are appreciated.