I’m trying to have a HTML5 page that includes a customer signature box. This would be used on tablets for the most part. This is done with a Canvas element, and JavaScript events on the mouse.
Issue 1: The Y portion works perfectly, but the X portion will ONLY work if I set my canvas with to 300. If the width is 500, then the X portion is correct at x-coord 0. When the user draws to x-coord 300, the line on the screen is now at the 500px mark on the canvas. NOWHERE in my code do I set anything to 300px, so I just don’t get what’s up.
Issue 2: I have code to stop scrolling on tablets and allow the user to sign in the canvas (see “prevent” var in JavaScript). That does not work at all.
HTML:
<div id="canvasDiv">
<canvas id="canvasSignature"></canvas>
</div>
CSS: (Makes the width 100% up to 500px, and always 150px high)
#canvasDiv
{
float: left;
width: 100%;
height: 150px;
max-width: 500px;
}
#canvasSignature
{
width: 100%;
height: 100%;
background-color: #F0F0F0;
border: 1px solid Black;
cursor: crosshair;
}
JavaScript:
<script type="text/javascript">
$(document).ready(function () {
initialize();
});
var prevent = false;
// works out the X, Y position of the click INSIDE the canvas from the X, Y position on the page
function getPosition(mouseEvent, element) {
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;
}
x = x - element.offsetLeft;
return { X: x, Y: y - element.offsetTop };
}
function initialize() {
// get references to the canvas element as well as the 2D drawing context
var element = document.getElementById("canvasSignature");
var context = element.getContext("2d");
// 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, element);
context.moveTo(position.X, position.Y);
context.beginPath();
prevent = true;
// attach event handlers
$(this).mousemove(function (mouseEvent) {
drawLine(mouseEvent, element, context);
}).mouseup(function (mouseEvent) {
finishDrawing(mouseEvent, element, context);
}).mouseout(function (mouseEvent) {
finishDrawing(mouseEvent, element, context);
});
});
document.addEventListener('touchmove', function (event) {
if (prevent) {
event.preventDefault();
}
return event;
}, false);
}
// draws a line to the x and y coordinates of the mouse event inside
// the specified element using the specified context
function drawLine(mouseEvent, element, context) {
var position = getPosition(mouseEvent, element);
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, element, context) {
// draw the line to the finishing coordinates
drawLine(mouseEvent, element, context);
context.closePath();
// unbind any events which could draw
$(element).unbind("mousemove")
.unbind("mouseup")
.unbind("mouseout");
prevent = false;
}
</script>
This is no good! As a rule of thumb you never want to change the CSS width/height of a canvas.
You are literally stretching a canvas sized 300×150 to skew across the entire screen. This is probably the source of 99% of your mouse problems.
The reason is seems fine in the y-direction is purely coincidence: The canvas is by default 300×150 and you have a div that is 150 high, so there is no skewing by the CSS. But if you wanted the div to be 200 high you’d see the problem there too!
You need to set the Canvas height and width as attributes and not as CSS properties:
Or else in JavaScript:
It looks like you want to have the canvas width change dynamically. This is OK, but you have to do one of a few things. One would be to use the window’s
onresizeevent, and set the canvas width equal to the div’s clientWidth every time this happens (if the clientWidth has changed of course). The other would be to do a simple general timer to check for the same thing every half-second or so.Note that I did not check the validity of your getPosition function. There might be other errors there that may be a separate issue, but its probably OK.