7

I am trying to use canvas so that with a mouse a person can write their signature. Everything works until I stretch or scroll the screen then it draws the line in a different place away from the mouse.

The Code:

function onMouseUp(event) {
    'use strict';
    mousePressed = false;
}
function onMouseMove(event) {
    'use strict';
    if (mousePressed) {
        event.preventDefault();
        mouseX = event.clientX - can.offsetLeft - mleft;
        mouseY = event.clientY - can.offsetTop - mtop;
        ctx.lineTo(mouseX, mouseY);
        ctx.stroke();
    }
}
function onMouseDown(event) {
    'use strict';
    mousePressed = true;
    mouseX = event.clientX - can.offsetLeft - mleft;
    mouseY = event.clientY - can.offsetTop - mtop;
    ctx.beginPath();
    ctx.moveTo(mouseX, mouseY);
}
can.addEventListener('mousemove', onMouseMove, false);
can.addEventListener('mousedown', onMouseDown, false);
can.addEventListener('mouseup', onMouseUp, false);

HTML looks like: <canvas id="signature" width="567" height="150"></canvas>

kqlambert
  • 2,693
  • 6
  • 33
  • 50

5 Answers5

2

event.clientX/Y is relative to the top left corner of the viewport. So scroll isn't taken into account. event.pageX/Y is relative to the document. So it is the position on screen that the event happened including scroll. You can change all references to clientX to pageX and clientY to pageY and it should work.

Explanation of each screen/page/client XY.

Community
  • 1
  • 1
Jonathan Kuhn
  • 15,279
  • 3
  • 32
  • 43
2

It seems like you just need a more reliable method of getting the relative coordinates when the page reflows.

@RyanArtecona wrote the following function in response to this question about mouse coordinates relative to a canvas:

function relMouseCoords(event){
    var totalOffsetX = 0;
    var totalOffsetY = 0;
    var canvasX = 0;
    var canvasY = 0;
    var currentElement = this;

    do{
        totalOffsetX += currentElement.offsetLeft - currentElement.scrollLeft;
        totalOffsetY += currentElement.offsetTop - currentElement.scrollTop;
    }
    while(currentElement = currentElement.offsetParent)

    canvasX = event.pageX - totalOffsetX;
    canvasY = event.pageY - totalOffsetY;

    return {x:canvasX, y:canvasY}
}
HTMLCanvasElement.prototype.relMouseCoords = relMouseCoords;

This is convenient because it adds a function to get the relative coordinates right onto the prototype of the HTMLCanvasElement function, which means you can just pass in a reference to the canvas you want to use, and get coordinates relative to it.

Using this you could rewrite your mousedown function (and you'll want to do the others as well, but just for an example) as follows:

function onMouseDown(event) {
    'use strict';
    mousePressed = true;
    // get a reference to the 'signature' canvas
    var canvas = document.getElementById('signature');
    // this returns an object with 'x' and 'y' properties
    var mouse = canvas.relMouseCoords(event)
    ctx.beginPath();
    // use the coordinates you got
    ctx.moveTo(mouse.x, mouse.y);
}
Community
  • 1
  • 1
jshanley
  • 9,048
  • 2
  • 37
  • 44
1

Change these two lines

mouseX = event.clientX - can.offsetLeft - mleft;
mouseY = event.clientY - can.offsetTop - mtop;

to

mouseX = event.offsetX || event.layerX;
mouseY = event.offsetY || event.layerY;

in both of your handlers. The browser can handle the relative coordinates for you without having to do any special math. offsetX/Y seems Chrome/IE specific and layerX/Y gets you Firefox support.

Here is a jsfiddle. I made a couple slight declaration changes to get your use stricts to work, since we seem to be missing a little of the code.

mafafu
  • 1,226
  • 1
  • 17
  • 22
0

Add the scroll offset of the screen to the mouseX and mouseY. with jQuery it would look like this

mouseX = event.clientX - can.offsetLeft - mleft + $(window).scrollLeft;
mouseY = event.clientY - can.offsetTop - mtop + $(window).scrollTop;
one stevy boi
  • 577
  • 6
  • 24
0

This is not a simple answer. The best way to figure this out is to start with a good foundation and then make incremental changes for your situation.. The best article I have seen on this subject is from the Internet Explorer Team:

Handling Multi-touch and Mouse Input in All Browsers

This article will give you a great foundation to capturing mouse input correctly.

Domin8urMind
  • 1,314
  • 8
  • 10