You target canvas, so you target only recent browsers.
So you can forget about the pageX stuff of Method 4.
Method 1 fails in case of nested canvas.
Method 3 is just like Method 2, but slower since you do it by hand.
-->> The way to go is option 2.
Now since you worry about performances, you don't want to call to the DOM
on each mouse move : cache the boundingRect left and top inside some var/property.
If your page allows scrolling, do not forget to handle the 'scroll' event
and to re-compute the bounding rect on scroll.
The coordinates are provided in css pixels : If you scale the Canvas with css,
be sure its border is 0 and use offsetWidth and offsetHeight to compute correct
position. Since you will want to cache also those values for performances and avoid too many globals, code will look like :
var mouse = { x:0, y:0, down:false };
function setupMouse() {
var rect = cv.getBoundingClientRect();
var rectLeft = rect.left;
var rectTop = rect.top;
var cssScaleX = cv.width / cv.offsetWidth;
var cssScaleY = cv.height / cv.offsetHeight;
function handleMouseEvent(e) {
mouse.x = (e.clientX - rectLeft) * cssScaleX;
mouse.y = (e.clientY - rectTop) * cssScaleY;
}
window.addEventListener('mousedown', function (e) {
mouse.down = true;
handleMouseEvent(e);
});
window.addEventListener('mouseup', function (e) {
mouse.down = false;
handleMouseEvent(e);
});
window.addEventListener('mouseout', function (e) {
mouse.down = false;
handleMouseEvent(e);
});
window.addEventListener('mousemove', handleMouseEvent );
};
Last word : performance testing an event handler is, to say the least, questionable, unless you can ensure that the very same moves/clicks are performed during each test. There no way to handle things faster than in the code above. Well, you might save 2 muls if you are sure canvas isn't css scaled, but anyway as of now the browser overhead for input handling is so big that it won't change a thing.