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.

HTML5, whats it all about ?

HTML5 is a web standard in progress developed and maintained by W3C and WHAT (Web Hypertext Application Technologies working group). HTML5 is a collection of different things, different features. You need to grasp this idea to understand HTML5. Let me explain why.

There are different browsers out there that you can use, each browser having it’s pros and cons. The biggest difference between browsers is what happens under the hood, how they parse HTML and render it, how strictly have they implemented the standard. Since HTML5 is a standard (although not complete), each browser implements the standard differently, therefore you can find browsers that support most of the standard and some support few features of it.

So, what does HTML5 have to offer ? Here are the main features that make up HTML5:

  • Canvas: a canvas is exactly what the name implies, it’s a drawing surface. JavaScript is used to access the canvas APIs to do the actual drawing.
  • Canvas Text: the canvas text APIs are used to draw text on the canvas. Your browser might support the canvas API but not the canvas text APIs
  • Video: the <video> element is used  to embed video in your web page. This was previously impossible without a third party plug in.
  • Local Storage: local storage is used to store data on the client, this data can be used by your site. The concept is similar to cookies but the storage space is much larger.
  • Web Workers: this is one of the most exciting features, it allows your browser to run JavaScript in the background, and run multiple threads at the same time.
  • Offline Web Applications: HTML5 provides a way for your application to work offline. This is done by caching any resources your application need on the client.
  • Geolocation: the geolocation API allows you to retrieve the client’s location. You have to obtain the clients permission first.
These are some of the main features of HTML5. I recommend reading HTML5 Up and Running by Mark Pilgrim for more details on HTML5. The book is great and very much simplified.