holyredbeard
holyredbeard

Reputation: 21188

Drawing with canvas doesn't follow cursor

I'm creating a drawing application with HTML5 canvas. It works accept for one thing. The drawing happens like ~50px down/right from the cursor. Below is my code, is it possible to tell why this is happening?

var letsdraw = false;

var theCanvas = document.getElementById('paint');
var ctx = theCanvas.getContext('2d');
theCanvas.width  = 420;
theCanvas.height = 300;


$('#paint').mousemove(function(e) {
    if (letsdraw === true){
        ctx.strokeStyle = 'blue';
        ctx.lineWidth = 100;
        ctx.lineCap = 'round';
        ctx.beginPath();
        ctx.moveTo(e.pageX, e.pageY);
        ctx.lineTo(e.pageX, e.pageY);           
        ctx.stroke();
    }
});

$('#paint').mousedown(function(){
    letsdraw = true;
});

$('#paint').mouseup(function(){ 
    letsdraw = false;
});

Upvotes: 0

Views: 4190

Answers (2)

Braden Best
Braden Best

Reputation: 8998

You can get accurate mouse coordinates by subtracting the canvas's offsetLeft and offsetTop from the X and Y coordinates, respectively. On another note, imagine if in ms paint or photoshop, you drew only by moving the mouse, and it didn't matter whether or not you had the mouse button down, it would draw anyway. Wouldn't that be annoying and unintuitive? Instead, you can pull the relevant data from the mouse events, and check them in an interval.

Luckily, this kind of stuff is simple enough to do that libraries like jQuery and prototype aren't really necessary, and it can be done in "raw" JavaScript.

Here's my whack at it, for example:

var mouse = [0,0], mouseDown = false, last = [0,0], fps = 24
ctx = canvas.getContext('2d');
getMouse = function(e){
    var X,Y;
    X = e.pageX || e.clientX || e.offsetX;
    Y = e.pageY || e.clientY || e.offsetY;
    X = X - canvas.offsetLeft;
    Y = Y - canvas.offsetTop;
    mouse = [X,Y];
}
canvas.onmousedown = function(e){
    getMouse(e);
    mouseDown = true;
    last = mouse;
}
canvas.onmouseup = function(){
    mouseDown = false;
}
canvas.onmousemove = getMouse;
setInterval(function(){
    if(mouseDown){
        ctx.beginPath();
        ctx.moveTo(last[0],last[1]);
        ctx.lineTo(mouse[0],mouse[1]);
        ctx.stroke();
        ctx.closePath();
        last = mouse;
    }
},1000/fps);

You can see it in action here. Click and drag to draw.


I hope this is helpful.

Upvotes: 0

PriorityMark
PriorityMark

Reputation: 3247

A couple of items I see. First, for your core problem, you're only looking at pageX and pageY, but you're not taking in to account the offset of the canvas. So, if the canvas is 50 px down on the page, you're going to be drawing in the wrong location.

Also, you won't want to use moveTo and lineTo both in the mousemove, as this isn't valid syntax. You're basically saying "draw a line from point (x,y) to (x,y). Here's an updated bit of code for you, you can find the jsfiddle for it here: http://jsfiddle.net/fordlover49/wPx4d/

$(function() {
    var letsdraw = false;

    var theCanvas = document.getElementById('paint');
    var ctx = theCanvas.getContext('2d');
    theCanvas.width = 420;
    theCanvas.height = 300;

    var canvasOffset = $('#paint').offset();

    $('#paint').mousemove(function(e) {
        if (letsdraw === true) {
            ctx.lineTo(e.pageX - canvasOffset.left, e.pageY - canvasOffset.top);
            ctx.stroke();
        }
    });

    $('#paint').mousedown(function() {
        // setup all of the properties for your line on mousedown, not mousemove
        letsdraw = true;
        ctx.strokeStyle = 'blue';
        ctx.lineWidth = 10;
        ctx.lineCap = 'round';
        ctx.beginPath();
        ctx.moveTo(e.pageX - canvasOffset.left, e.pageY - canvasOffset.top);
    });

    $(window).mouseup(function() {
        // bind to the window mouse up, that way if you mouse up and you're not over 
        // the canvas you'll still get the release of the drawing.
        letsdraw = false;
    });
});

Upvotes: 4

Related Questions