Click here to Skip to main content
15,879,326 members
Articles / Web Development / HTML5
Alternative
Article

HTML 5 Canvas - A Simple Paint Program (Touch and Mouse)

Rate me:
Please Sign up or sign in to vote.
3.67/5 (3 votes)
26 Apr 2012CPOL 162.6K   30   22
This is an alternative for "HTML 5 Canvas - A Simple Paint Program"

Introduction

I've seen quite a few HTML5 canvas painting examples, but I had not seen one that worked on both a touch screen, and on a normal desktop with a mouse.  This is just a very basic example of what is needed to get this feature working on both. 

Background 

Some time back I had to develop an HTML5 customer input form which also included a  signature.  This would be used mostly on a tablet, however it was possible it needed to be supported on a drawing pad and a desktop PC.  I viewed quite a few online examples of painting on the canvas, but none worked on touch screens AND desktops:
http://mudcu.be/sketchpad/ 
http://devfiles.myopera.com/articles/649/example5.html 

This is simply an alternate to Gordon Kushner's article on the HTML5 canvas & painting.  His article can be found here: http://www.codeproject.com/Articles/351253/HTML-5-Canvas-A-Simple-Paint-Program.   His code works well; though again it does not work on a touch device. 

Most of the code here I found from various examples on Code Project and Stack Overflow.  I simply put them all together to get this demo working. 

Using the code

This code simply determines which device type you are using and sets up the canvas event handlers accordingly. 

HTML
<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="utf-8" />
   <title>Desktops and Tablets</title>
 
   <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
 
   <script type="text/javascript">
      $(document).ready(function () {
         initialize();
      });
 

      // works out the X, Y position of the click inside the canvas from the X, Y position on the page
      function getPosition(mouseEvent, sigCanvas) {
         var x, y;
         if (mouseEvent.pageX != undefined && mouseEvent.pageY != undefined) {
            x = mouseEvent.pageX;
            y = mouseEvent.pageY;
         } else {
            x = mouseEvent.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
            y = mouseEvent.clientY + document.body.scrollTop + document.documentElement.scrollTop;
         }
 
         return { X: x - sigCanvas.offsetLeft, Y: y - sigCanvas.offsetTop };
      }
 
      function initialize() {
         // get references to the canvas element as well as the 2D drawing context
         var sigCanvas = document.getElementById("canvasSignature");
         var context = sigCanvas.getContext("2d");
         context.strokeStyle = 'Black';
 
         // This will be defined on a TOUCH device such as iPad or Android, etc.
         var is_touch_device = 'ontouchstart' in document.documentElement;
 
         if (is_touch_device) {
            // 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;
                  }
               }
            };
 
            // create a function to pass touch events and coordinates to drawer
            function draw(event) {
 
               // get the touch coordinates.  Using the first touch in case of multi-touch
               var coors = {
                  x: event.targetTouches[0].pageX,
                  y: event.targetTouches[0].pageY
               };
 
               // Now we need to get the offset of the canvas location
               var obj = sigCanvas;
 
               if (obj.offsetParent) {
                  // Every time we find a new object, we add its offsetLeft and offsetTop to curleft and curtop.
                  do {
                     coors.x -= obj.offsetLeft;
                     coors.y -= obj.offsetTop;
                  }
				  // The while loop can be "while (obj = obj.offsetParent)" only, which does return null
				  // when null is passed back, but that creates a warning in some editors (i.e. VS2010).
                  while ((obj = obj.offsetParent) != null);
               }
 
               // pass the coordinates to the appropriate handler
               drawer[event.type](coors);
            }
 

            // attach the touchstart, touchmove, touchend event listeners.
            sigCanvas.addEventListener('touchstart', draw, false);
            sigCanvas.addEventListener('touchmove', draw, false);
            sigCanvas.addEventListener('touchend', draw, false);
 
            // prevent elastic scrolling
            sigCanvas.addEventListener('touchmove', function (event) {
               event.preventDefault();
            }, false); 
         }
         else {
 
            // start drawing when the mousedown event fires, and attach handlers to
            // draw a line to wherever the mouse moves to
            $("#canvasSignature").mousedown(function (mouseEvent) {
               var position = getPosition(mouseEvent, sigCanvas);
 
               context.moveTo(position.X, position.Y);
               context.beginPath();
 
               // attach event handlers
               $(this).mousemove(function (mouseEvent) {
                  drawLine(mouseEvent, sigCanvas, context);
               }).mouseup(function (mouseEvent) {
                  finishDrawing(mouseEvent, sigCanvas, context);
               }).mouseout(function (mouseEvent) {
                  finishDrawing(mouseEvent, sigCanvas, context);
               });
            });
 
         }
      }
 
      // draws a line to the x and y coordinates of the mouse event inside
      // the specified element using the specified context
      function drawLine(mouseEvent, sigCanvas, context) {
 
         var position = getPosition(mouseEvent, sigCanvas);
 
         context.lineTo(position.X, position.Y);
         context.stroke();
      }
 
      // draws a line from the last coordiantes in the path to the finishing
      // coordinates and unbind any event handlers which need to be preceded
      // by the mouse down event
      function finishDrawing(mouseEvent, sigCanvas, context) {
         // draw the line to the finishing coordinates
         drawLine(mouseEvent, sigCanvas, context);
 
         context.closePath();
 
         // unbind any events which could draw
         $(sigCanvas).unbind("mousemove")
                     .unbind("mouseup")
                     .unbind("mouseout");
      }
   </script>
   
</head>
 
<body>
   <h1>Canvas test</h1>
 
   <div id="canvasDiv">
      <!-- It's bad practice (to me) to put your CSS here.  I'd recommend the use of a CSS file! -->
      <canvas id="canvasSignature" width="500px" height="500px" style="border:2px solid #000000;"></canvas>
   </div>
</body>
</html> 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
United States United States
I've been a developer since 2004. I work in C#, ASP, WPF, XAML, Silverlight, Windows Store, HTML/JavaScript/CSS, Java, Delphi, and SQL. I write for web, desktop, Android, Windows Mobile, Windows Store, and database servers.

Comments and Discussions

 
QuestionI did a simple web drawing thing a while back (Angular Directive to draw) Pin
Sacha Barber24-Mar-15 23:13
Sacha Barber24-Mar-15 23:13 
QuestionOnly works sometimes... Pin
Ricardo Santos25-Sep-14 3:54
Ricardo Santos25-Sep-14 3:54 
AnswerRe: Only works sometimes... Pin
gardnerp25-Sep-14 4:45
gardnerp25-Sep-14 4:45 
GeneralRe: Only works sometimes... Pin
Ricardo Santos25-Sep-14 4:50
Ricardo Santos25-Sep-14 4:50 
GeneralRe: Only works sometimes... Pin
gardnerp25-Sep-14 4:56
gardnerp25-Sep-14 4:56 
BugLines aren't placed correctly Pin
SYKKID3-Dec-13 5:52
SYKKID3-Dec-13 5:52 
GeneralRe: Lines aren't placed correctly Pin
gardnerp3-Dec-13 6:08
gardnerp3-Dec-13 6:08 
GeneralRe: Lines aren't placed correctly Pin
SYKKID4-Dec-13 4:10
SYKKID4-Dec-13 4:10 
GeneralOff Topic Pin
OriginalGriff9-Dec-13 9:01
mveOriginalGriff9-Dec-13 9:01 
GeneralRe: Off Topic Pin
gardnerp9-Dec-13 9:03
gardnerp9-Dec-13 9:03 
GeneralRe: Off Topic Pin
gardnerp9-Dec-13 9:05
gardnerp9-Dec-13 9:05 
GeneralRe: Off Topic Pin
OriginalGriff9-Dec-13 9:15
mveOriginalGriff9-Dec-13 9:15 
Questionlayout changes Pin
Matiaan7-Apr-13 12:00
Matiaan7-Apr-13 12:00 
Questionhow to change pixel size !!? Pin
shobeir,fatehi31-Jan-13 16:05
shobeir,fatehi31-Jan-13 16:05 
QuestionTouchend not working Pin
hensolberg2-Aug-12 0:22
hensolberg2-Aug-12 0:22 
AnswerRe: Touchend not working Pin
gardnerp2-Aug-12 3:58
gardnerp2-Aug-12 3:58 
GeneralRe: Touchend not working Pin
Suresh koppisetty23-Apr-13 1:39
Suresh koppisetty23-Apr-13 1:39 
reason for touchend not working is because you have a put a condition
event.targetTouches[0] != undefined
in draw function , where as touchend has no targetTouches so its never called. touchend has last coordinates in "changedTouches" .To make it work change your draw function to this.

C#
function draws(event) {
    // console.log(event);
    //event.preventDefault();

    if(event.targetTouches[0] != undefined){
     var coors = {
       x: event.targetTouches[0].pageX,
       y: event.targetTouches[0].pageY
    };
    var obj = sigCanvas;
    if (obj.offsetParent) {
       do {
          coors.x -= obj.offsetLeft;
          coors.y -= obj.offsetTop;
       }
       while ((obj = obj.offsetParent) != null);
    }
    console.log("Event: "+ event.type);
    drawer[event.type](coors);
    }
    if(event.type == 'touchend'){
       //console.log(event);
       var coors = {
       x: event.changedTouches[0].pageX,
       y: event.changedTouches[0].pageY
    };
       drawer[event.type](coors);

     }
    //console.log(event);
 }

GeneralMy vote of 3 Pin
Donsw30-Jun-12 5:15
Donsw30-Jun-12 5:15 
NewsA minor note - This wasn't meant to be an article! Pin
gardnerp30-Apr-12 5:35
gardnerp30-Apr-12 5:35 
QuestionWorks 50% of the time Pin
Dewey27-Apr-12 13:51
Dewey27-Apr-12 13:51 
AnswerRe: Works 50% of the time Pin
gardnerp30-Apr-12 2:36
gardnerp30-Apr-12 2:36 
GeneralRe: Works 50% of the time Pin
Dewey4-May-12 15:55
Dewey4-May-12 15:55 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.