4

I'm trying to draw a rectangle (or other path) at the cursors position.

The issue is, if you move your mouse fast enough, the drawing lags behind the cursor considerably (chases it).

To reproduce/ test the issue, I've tried to produce code that is as lean as possible. However there's still a noticeable gap [between the cursor and the rectangle] due to rendering latency, even on a computer with decent specs (Chrome Beta 37, Fedora 20, i7 4770k, etc)

Can anyone posit to the cause, or suggest improvements to the following code to reduce latency:

http://jsfiddle.net/AGp2w/4/

var canvas = document.getElementsByTagName('canvas')[0];
var canvasDim = {
    width: canvas.width,
    height: canvas.height
};
var canvasOffset = canvas.getBoundingClientRect();

var context = canvas.getContext('2d');
context.stroke = "#000000";
context.fill = "#000000";

var currentPosition = {x:0, y:0};
var previousPosition = currentPosition;
var onlyClearPreviousPositon = true;

canvas.onmousemove = function(e){
    currentPosition = {
        x: e.clientX - canvasOffset.left,
        y: e.clientY - canvasOffset.top
    };
};
function drawAtCursor(){
    if (onlyClearPreviousPositon){
        // experiment - try not clearing the whole canvas 
        context.clearRect(previousPosition.x - 4, previousPosition.y - 4, 8, 8);
        previousPosition = currentPosition;
    } else {
        context.clearRect(0, 0, canvasDim.width, canvasDim.height);
    }
    context.fillRect(currentPosition.x - 4, currentPosition.y - 4, 8, 8);
    window.requestAnimationFrame(drawAtCursor);   
}

drawAtCursor();
Mikko Ohtamaa
  • 82,057
  • 50
  • 264
  • 435
nathan-m
  • 8,875
  • 2
  • 18
  • 29
  • The bottleneck is not in your code. The frequency of triggering `mousemove` event is limited by the browser and I don't think there's a way around it. See also http://stackoverflow.com/questions/5258424/how-to-set-mousemove-update-speed – pawel Jul 30 '14 at 12:10
  • BTW to remove *some* latency you could ditch the `requestAnimationFrame` callback and draw directly in the `onmouvemove` callback, like this: http://jsfiddle.net/AGp2w/5/ but the difference is barely noticeable. – pawel Jul 30 '14 at 12:13
  • @pawel Yeah tried removing `requestAnimationFrame` - didn't really work, and probably not advisable. – nathan-m Jul 30 '14 at 12:53
  • Perhaps someone has tried polling for mouse position and computing as a vector. Then you could render where the mouse "should" be...... – nathan-m Jul 30 '14 at 13:01

1 Answers1

1

This has a tiny bit less latency, but is not useful in a real app:

function handleMouseMove(e){
    ctx.clearRect(mouseX-1,mouseY-1,9,9);
    mouseX=e.clientX-offsetX;
    mouseY=e.clientY-offsetY;
    ctx.fillRect(mouseX,mouseY,8,8);
}

The mouse pointer will always be quicker than drawing, so your best bet is not to give the user's eye a reason to perceive latency:

Turn off the mouse cursor while the user is drawing.

http://jsfiddle.net/m1erickson/Cf5TX/

The moving rectangle will act as the mouse cursor, but if the user needs a visual guide, you can:

Also draw crosshairs using a couple of lines.

markE
  • 102,905
  • 11
  • 164
  • 176
  • 1
    Hi MarkE, this is a great way of sidestepping the issue; something that I have done in the past. However I'm still looking for any better solution that doesn't hide the existing cursor. – nathan-m Jul 30 '14 at 22:51