Skip to content

html5 canvas drawing on ipad

by will on December 16th, 2010


Download Source Code: draw.html

why would you do this?

While iOS and Android offer OpenGL for adding rich graphics to native apps, you may want to add similar (albeit more primitive) capabilities to your web-based app. I had recently come to this problem while doing some prototypical gesture recognition work which I wanted to test using the iPad’s screen. Since I just needed to trace and capture the path of a finger on the screen, it seemed like a more attractive option to quickly throw together such an interface in a web browser using html & javascript.

html5 canvas element

The html5 canvas element is the key component that makes drawing in a web browser possible. The canvas provides a powerful scriptable interface for rendering graphics on-the-fly, and is supported by most modern browser (including IE9!). To get started with it, simply place a canvas tag in the body of the page:

63
64
65
66
67
68
69
<body>
  <div id="container">
    <canvas id="sketchpad">
      Sorry, your browser is not supported.
    </canvas>		
  </div>
</body>

Then access it via javascript like this:

9
10
11
// get the canvas element and its context
var canvas = document.getElementById('sketchpad');
var context = canvas.getContext('2d');

There’s a wealth of material available online which covers canvas usage, but I found this one to be most useful for basic drawing.

For this example, I created a “drawer” object which has a “isDrawing” flag to indicate whether or not it’s currently drawing, and 3 handlers: touchstart, touchend, touchmove for the start, end, and process of a touch stroke respectively. Each handler accepts a pair of coordinates corresponding to the current position of the finger.

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// create a drawer which tracks touch movements
var drawer = {
   isDrawing: false,
   touchstart: function(coors){
      context.beginPath();
      context.moveTo(coors.x, coors.y);
      this.isDrawing = true;
   },
   touchmove: function(coors){
      if (this.isDrawing) {
         context.lineTo(coors.x, coors.y);
         context.stroke();
      }
   },
   touchend: function(coors){
      if (this.isDrawing) {
         this.touchmove(coors);
         this.isDrawing = false;
      }
   }
};

ipad dimensions & orientation

To fit the canvas to the screen (with the browser chrome included) you should 946 x 768 pixels (height x width). In the example, I’ve taken 2 pixels off of each dimension, so I could add a 1 pixel border around the canvas. Although, it’s possible to detect rotations using mobile safari’s orientation and rotation features, I’ve found the easiest solution is to simply enable the iPad’s orientation lock while in the vertical orientation when drawing.

63
64
65
66
67
68
69
<body>
  <div id="container">
    <canvas id="sketchpad" width="766" height="944">
      Sorry, your browser is not supported.
    </canvas>		
  </div>
</body>

the touch events

When implementing this simple app on a computer with a mouse or trackpad, you would normally use the event listeners mousedown, mouseup, and mousemove; however, when developing for a touchscreen, you’ll instead use: touchstart, touchend, and touchmove event listeners.

I’ve created a draw wrapper function which takes the touch coordinates from the event object and passes them to the appropriate handler of the drawer object. The draw function is then registered with the canvas’ touch events.

34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// create a function to pass touch events and coordinates to drawer
function draw(event){
   // get the touch coordinates
   var coors = {
      x: event.targetTouches[0].pageX,
      y: event.targetTouches[0].pageY
   };
   // pass the coordinates to the appropriate handler
   drawer[event.type](coors);
}
 
// attach the touchstart, touchmove, touchend event listeners.
canvas.addEventListener('touchstart',draw, false);
canvas.addEventListener('touchmove',draw, false);
canvas.addEventListener('touchend',draw, false);

fixing the viewport

Normally on the ipad a web page would allow for elastic scrolling, which is a bit problematic when you want to draw on a static canvas. To disable it, simply add a handler to the touchmove event of the document body which prevents triggering of the event’s default action:

50
51
52
53
// prevent elastic scrolling
document.body.addEventListener('touchmove',function(event){
  event.preventDefault();
},false);	// end body:touchmove

more..

Although, at the time of writing this article, the iPad was the only target platform for this project (because that’s the only tablet that I own), this should in theory be easily extended to support any html5-capable tablet which has touch-gesture API exposed to the web browser.

From → web apps

22 Comments
  1. scatal permalink

    It works in Android (Samsung Galaxy S)

  2. balaji permalink

    its work on iPad but draw line formate can u provide pencil formate so please guide

  3. will permalink

    Hi Balaji,

    You can use the canvas context properties to change the basic style of the line you’re drawing, e.g. if you want to change the color or make it thicker, by inserting something like this after line 11 of the example:

    context.fillStyle = '#00f'; // red
    context.strokeStyle = '#00f'; // red
    context.lineWidth = 4;

  4. Hey Will,

    Great post! I’ve been searching for this functionality and your code works beautifully.

    Do you know if there is a way to save the input – for instance if someone draws into the box can this input be submitted as in image or in some other way? Perhaps through an html form?

    Thanks!
    Marc

  5. Raughn permalink

    Hi will,

    This implementation has an issue when the canvas doesn’t have the same width and height as the iPad. If you place the canvas on the lower part if would look as if it’s not working. The reason is that the “drawing” is being drawn on the upper part (which is not covered by the canvas). Any ideas as to why it’s so?

  6. MrMoka permalink

    @Marc

    The canvas element’s: toDataURL method returns the contents of the canvas as a base-64 encoded string. You can use that as the URL of an image element or send it to a server script for saving:

    var url = canvas.toDataURL('image/png');
    document.write('');
    

    For more info, see WhatWG’s canvas page.

  7. MrMoka permalink

    Oops. Let me try that again. Second line of code is writing an img element with the src attribute set to the URL. Maybe this will render:

    var url = canvas.toDataURL('image/png');
    document.write('<img src="' + url + '"/>');
    
  8. will permalink

    Hey Raughn,

    I think it could be because the coordinates are being taken relative to the page, rather than the canvas itself (in this line):
    var coors = {
    x: event.targetTouches[0].pageX,
    y: event.targetTouches[0].pageY
    };

    I think the fix will be to account for the position of the canvas on the page when populating that coors object. If you post your code, or a snippet from it, I can take a look.

  9. will permalink

    Hey Mark,

    Thanks! Yes, you can save the drawing. I have written this functionality to work with a django back-end, and was planning to blog about that as well. I can let you know when we publish that post.

  10. Andrew Ogi permalink

    Hello, will! Can I not only draw but also erase content of canvas, ex. any image in it on ipad?

  11. balaji permalink

    Thanks Will,

    Its working now increasing the line Width then will be slit changes
    context.lineWidth = 4;

    one more guide please now i draw a cartoon image any example

  12. Paul permalink

    May i know if we can save the image sketched on the canvas into either jpg or png etc?
    And may i have some sample code?

  13. will permalink

    Hey Paul, in some web browsers, the canvas element has a “toDataURL” method which will work. You can find libraries to do this when a browser doesn’t have this method. I think this stackoverflow post will give you some good code samples: http://stackoverflow.com/questions/923885/capture-html-canvas-as-gif-jpg-png-pdf

  14. will permalink

    Hey Andrew,

    Check out this post about using the context.clearRect(x,y,w,h) method: http://stackoverflow.com/questions/2142535/how-to-clear-the-canvas-for-redrawing

  15. Bilbo permalink

    Will,
    Could you please show an example of how to wire up the context.clearRect(x,y,w,h) to a touch event on a button? I am trying to add a simple “clear” button to your code, but am apparently not getting it.

    Thanks.

  16. shinaco permalink

    Hello, I know this is and old post but I hope you can help me. I am trying to do a writing app in the web using html5 canvas that should work on EVERY browser. On the PC based browsers (including Safari, Firefox, Opera, IE and Chrome) it works fine. I even made it work on IE 8 and earlier using flash canvas. However, on the Ipad it does not work, as when you drag, instead of drawing, it scrolls the page. I have both mouse and touch events declared on my app. Are they conflicting with each other? is it just impossible to make an app like this that works both with Ipad and pc browsers simultaneously?

  17. shinaco permalink

    Sorry, I meant drawing app

  18. will permalink

    Hi Shinaco,
    Yes it is possible to develop a single app that will work in all browsers. I would recommend using a framework like jQuery if that is your goal. You should update the “drawer” object with methods for: mousedown, mousemove, and mouseup which correspond to the relevant touch methods. Then, instead of using the canvas.addEventListener.. lines, use the jQuery bind method like:
    $(canvas).bind(‘touchstart,mousedown,touchend,mouseup,touchmove,mousemove’,draw);

    Hope that helps!

  19. Omega permalink

    Do you have a example you can share for this query ?
    Thank you.

    Will,
    Could you please show an example of how to wire up the context.clearRect(x,y,w,h) to a touch event on a button? I am trying to add a simple “clear” button to your code, but am apparently not getting it.

    Thanks.

  20. Marc permalink

    Awesome, just what I needed. Thank you.

  21. The ‘touchend’ function doesnt get trigerred at all . I tried this code . Touchstart and touchmove works fine . But touchend never gets called . Any reason why ?

    http://stackoverflow.com/questions/10579726/touchend-events-not-getting-fired-on-html5-canvas

  22. andher bhai permalink

    Yeah , same touchend problem with me as well .

Leave a Reply

Note: XHTML is allowed. Your email address will never be published.

Subscribe to this comment feed via RSS

*