Signature Pad with HTML5 Canvas

If you hurry and don’t want explanations click here to see the final result 🙂

Long time has passed since everything is migrating from real world to digital world. let’s create digital signature pad with HTML5 Canvas technology. It will be little area on web-page and with mouse a user will be able to sign as it is in some classical painting software.

The only markup (for example: canvas.html file) we will need looks like this:

<html>
    <head>
        <title>Signature Pad</title>
        <script type="text/javascript">
            //javascript code goes here ...
        </script>
    <head>
    <body>
       <canvas width="300" height="200" id="canvas"></canvas>
    </body>
</html>

We marked-up a simple html page, with title: “Signature Pad” and in the body of document there is a canvas element. For simplicity lets write JavaScript code inside html (it is not a good pattern, but the aim of this post is idea and realization of making signature pad in Canvas). So in the head part of our markup we have script tag.

Before we start coding lets explain general idea. We will need to listen to mouse events: when mouse is moving on canvas element and mouse button is pressed then we should draw a line from previous point to current point. Actually, event fires too fast and our drown lines looks like a point. Finally, there is natural signature curve.

Let’s formulate technical tasks and then write solutions:
Tasks:

1.

Function that draws a line on canvas from the first point to the second point.

2.

Listen to moment when mouse button is pressed, save the state and put a dot.

3.

Listen to moment when mouse button is released and save the state.

4.

Listen to mouse move event all the time and when mouse button is in pressed state draw a line from previous (x,y) to current (x,y).

Solutions:

1.

Why to draw a line and not a point? Because canvas doesn’t have this feature 🙂 So let’s talk a little about canvas. To draw on canvas firstly we must retrieve drawing context from it, in this case two dimensional context (there is no three dimensional context implemented yet). The idea of drawing with canvas is that firstly you have to create a path. Then move to some (x,y) point and then from that point do what you need (In this case draw a line) then again move to some point and do what you need until you complete your task but nothing will appear on canvas because path needs to be filled with “ink” and then you have to close path. Therefore our JavaScript function drawLine will look like this:

    drawLine = function(x1, y1, x2, y2){
        context.beginPath(); //create a path
        context.moveTo(x1, y1); //move to
        context.lineTo(x2, y2); //draw a line
        context.stroke(); // filled with "ink"
        context.closePath(); //close path
    };

But here we have one side efect “context” is not defined here. Let’s define it and not only “context” but all other staff in our script tag when document is ready:

<script type="text/javascript">
    //fires when document is loaded and DOM is ready.
    window.onload = function(){
        var context, canvas, drawLine;
        canvas = document.getElementById('canvas'); //retrieve canvas from dom by id that we have assigned
        context = canvas.getContext('2d'); //retrieve context
        //definition of function drawLine goes below.
    }
</script>

Let’s note that all our further definitions of functions and variables goes in window.onload = function(){ … } function!

2.

This is a simple task, we will assign listener on canvas’ onmousedown event.

    canvas.onmousedown = function(evt){
        mouseIsPressed = true; //save that mouse is pressed
        drawLine(evt.offsetX, evt.offsetY, evt.offsetX + 1, evt.offsetY + + 1) //draw short line that looks like a dot
    };

3.

Similarly, we will assign listener on canvas’ onmouseup event.

    canvas.onmouseup = function(evt){
        mouseIsPressed = false; //save that mouse is released
    };

4.

And finally, canvas’ onmousemove. This handler has to do the following: get current X and Y coordinates of mouse, check if mouse is pressed, if is pressed then draw a line from previous coordinates to current coordinates, and last, save current coordinates to another variables as previous coordinates.

    canvas.onmousemove = function(evt){
        x = evt.offsetX; y = evt.offsetY; //get current X and Y
        if(mouseIsPressed){
            drawLine(prevX, prevY, x, y);  //draw a line on canvas from previous to current point.
        }
        prevX = x; prevY = y; //save previous x and y in both case, weather mouse is pressed or not
    };

But there is a little problem, the canvas element is not visible on page. This is because both, canvas and page’s background color is white. So, let’s do borders to canvas element that is was seen where is it on page. For this we will need to add one line in onload function that will apply CSS style to canvas. But let’s do it in clever way. When we get evt.offsetX or evt.offsetY it returns coordinates related to canvas edges include border width. So, let’s save border width in variable and subtract that value while drawing line in function drawLine. The change will look like this:

    context.moveTo(x1 - borderWidth, y1 - borderWidth); //move to
    context.lineTo(x2 - borderWidth, y2 - borderWidth); //draw a line

and in onload function add a line:

    canvas.style.border = borderWidth + " px solid #00F000";

If me merge JavaScript functions and add variable declarations in onload function described above, finally, we will get this result :

<html>
    <head>
        <title>Signature Pad</title>
        <script type="text/javascript">
			//fires when document is loaded and DOM is ready.
			window.onload = function(){
				var context, canvas, drawLine, mouseIsPressed, x, y, prevX, prevY, borderWidth;

				canvas = document.getElementById('canvas'); //retrieve canvas from dom by id that we have assigned
				context = canvas.getContext('2d'); //retrieve context
				borderWidth = 5; //let border width will be 5 pixel
				canvas.style.border = borderWidth + " px solid #00F000"; // 5 pixel width solid green border

				drawLine = function(x1, y1, x2, y2){
					context.beginPath(); //create a path
					context.moveTo(x1 - borderWidth, y1 - borderWidth); //move to
					context.lineTo(x2 - borderWidth, y2 - borderWidth); //draw a line
					context.stroke(); // filled with "ink"
					context.closePath(); //close path
				};

				canvas.onmousedown = function(evt){
					mouseIsPressed = true; //save that mouse is pressed
                                        drawLine(evt.offsetX, evt.offsetY, evt.offsetX + 1, evt.offsetY + + 1) //draw short line that looks like a dot
				};

			        canvas.onmouseup = function(evt){
					mouseIsPressed = false; //save that mouse is released
				};

				canvas.onmousemove = function(evt){
					x = evt.offsetX; y = evt.offsetY; //get current X and Y
					if(mouseIsPressed){
						drawLine(prevX, prevY, x, y);  //draw a line on canvas from previous to current point.
					}
					prevX = x; prevY = y; //save previous x and y in both case, weather mouse is pressed or not
				};

			}
        </script>
    <head>
    <body>
       <canvas width="300" height="200" id="canvas"></canvas>
    </body>
</html>

Canvas has a method toDataURL that returns image in base64 format in “image/png” or “image/jpeg”. From base64 we can convert it into binary image. So this way we can get signature image with help of canvas.