Drawing by touching using JavaScript


An updated version of this post and demo is available here: http://www.kinderas.com/technology/2014/3/13/a-drawing-application


The web is no longer exclusive for desktop and laptop computers. With the introduction of the iPhone and the iPad Apple changed how we interact with the web. In the wake of Apples success with iOS devices we see the emergence of a slew of "handheld" devices. They are all different, some are small, others bigger and more powerful, however most of them utilize touch as a means of input. In this article I take a look at how we can create a simple touch enabled drawing application using only JavaScript and a tinsy-winsy bit of HTML 5.

First, you can try the finished app (with comments) and download the source code from here.

The first thing we need to do is to make sure that the user visiting our web-app is on a device which can understand touch events. This is pretty straight forward. We accomplish this by asking the «window» DOM element if is knows about one of the touch events.
if('ontouchstart' in window == false){
   alert('Sorry, you need a touch enabled device to use this app');
   return;
}
If this does not stop our script, we know that the current device supports the touch events we need. The next step is to prevent the screen itself from scrolling when you drag your finger across it. We need to do this because touch events «bubbles» in JavaScript. This means that all the parent elements will get a chance to handle the touch event after we have handled it in our function. So after we have handled the «touchmove» event in our canvas element it will bubble right up to the window element where the browser will try to scroll the window. PS: Sometimes you might want this behavior, for example when you're scrolling a page. For our demo, we don't need it. To disable page scrolling we listen for the «touchmove» event on the document element, then we flag the event as handled using «event.preventDefault()».

Now to the construction part. We need to create a canvas element.
var canvas = document.createElement('canvas');
canvas.width  = window.innerWidth;
canvas.height = window.innerHeight;
document.body.appendChild(canvas);
We now have a «canvas» element which is the same size as our entire page. Next up we need to create a context in which to draw for the canvas. A context is kinda like a page within a drawing pad. The context can receive JavaScript drawing commands as we will see later on.
ctx  = canvas.getContext('2d');
ctx.strokeStyle = "rgba(255,0,0,1)";
ctx.lineWidth   = 5;
ctx.lineCap     = 'round';
The context is now set up using the color red with a 5 pixel wide stroke and rounded ends. You can change these values as you like of course.

In order for our fingers to be able to produce wonderful line drawings, we need to tell our application to listen for touch events. We'll need three of them. The «touchstart» event is where we set our starting position for the drawing operation. This event fires when a finger is added to the screen. The «touchmove» is where we draw the lines, this event fires when we move a finger on the screen. The «touchcancel» is where we handle exceptions, like what happens if you receive a call in the middle of your art creation extravaganza. This event fires whenever it needs to.
canvas.addEventListener("touchstart",touchstartHandler,false);
canvas.addEventListener("touchmove", touchmoveHandler,false);
canvas.addEventListener("touchcancel", touchcancelHandler,false);

Now we'll need to handle those events as well, here is where the real fun begins! Let's have a look a the «touchstart» handler first.
function touchstartHandler(event)
{
   ctx.moveTo(event.touches[0].pageX, event.touches[0].pageY);
}
It's just one line, but do take notice in the «touches» object contained within the event. This is an array (well, kind of) of touches. The reason for this is that most humans have more than one finger, so the «touches» object could actually contain several values. We only need one, so we refer to the first (0) element in the «touches» object. Now that we have found the first finger we get it's location on the screen by asking for the «pageX/Y» values. We then continue to move the canvas context pointer to the coordinates for this finger using the «moveTo» method. This happens every time we place a finger on the screen. But, only for the first finger.
function touchmoveHandler(event)
{
    ctx.lineTo(event.touches[0].pageX, event.touches[0].pageY);
    ctx.stroke();
}
In the «thouchmove» handler we do the actual work of telling the canvas context to draw a line from where it's last location was to where the finger is now. The first time this is called the line is drawn from where we placed the finger on to the screen, set in the «touchstart» handler. After that, the canvas context will update it's starting position to the location of the last drawing operation. Like the «moveTo» command in «touchstart» the «lineTo» will update the coordinate position, but it will also issue a drawing command which is rendered to the screen when we call the «stroke» method.

That's it. Try it out on your iPad, iPhone or any other touch device which understands the new HTML 5 APIs by clicking this magical link.

Recommended further reading:

8 comments:

Josh said...

Hello!

This is very neat! How hard would this be to embed within webpage? I am trying to make a website that I can create interactive worksheets for my students and want text boxes and freehand boxes.

Thanks!

-Josh

Jørn Kinderås said...

Hello Josh.
You know, the entire drawing application is just a webpage, you can view the source and create your own version if you want to.

Josh said...

Hey,

How about submitting the drawing as part of a form? Say I give them a math test, multiple choice, and I need them to draw me a polygon.. could this be adapted in such a way to submit/save the information?

Thanks!

Jørn Kinderås said...

Hello again Josh.

The «canvas» has a method called "toDataURL". This will create a string (base64) of any drawing within the «canvas» element. This string can then be submitted via a form or pushed to a server in any number of ways.

To view this "imagestring" you can actually set the source of an image tag as the string.

Josh said...

Hey,

Two more questions for you :) Could this be added to an epub file? I am learning to make them now.

Also, could I use this as part of an html form and when the submit button is hit, the data from the scratch pad is saved and sent along?

Thanks!

Jørn Kinderås said...

I have no idea about e-pub files and yes, if you export the drawing data as a string as mentioned above you can post the drawing data.

Josh said...

Hello again,

Sorry to have double posted, I did not realize my original one had posted after asking me to log in.

Could I encapsulate this into an object tag ? Ive been messing around with that, and have not had much luck.

Thanks!

Adam Levy said...

you rock! thanks for the help!