HTML5 Canvas Scrolling Messes with Mouse Position

canvas, html, mouse-position, scrollbar

Solution

I've experienced something like this before; I eventually figured it out by using something similar to what you had attempted; I replaced .x and .y with .pageX and .pageY

if (e.pageX || e.pageY) { 
    x = e.pageX;
    y = e.pageY;
}

As far as I am aware, this is because .x and .y do not grab the coordinates relative to the element, but rather relative to the body; in other words, they do not account for scrolling, while pageX and pageY do.

Test case with .x and .y

Test case with .pageX and .pageY

Problem

I am messing around with HTML5 right now and I wanted to program a little browser games - just for fun. I created a canvas in which a background image is loaded - its kind of a hexagonal grid. To find out which hexagon is clicked I use circles an their centers/radius. I explain this, because this way you can understand the code I post more quickly. This all works really fine until I use the scrollbars - then everything is messed up. It just seems that I does't get the coordinates right. Because the grid is a little bit bigger, I have to use scrollbars especially on smaller screens. So here is the code The Website ``` <html> <head> <script type="text/javascript" src="worldmap.js"></script> <script type="text/javascript" src="worldmapMouseEvents.js"></script> </head> <body onload="draw()"> Xcoord: <div id="xcoord">0</div>&nbsp; Ycoord: <div id="ycoord">0</div><br> Spalte: <div id="column">0</div><br> Reihe: <div id="row">0</div><br> <canvas id="canvas" width="1100" height="1100" style="border: 1px solid black;" onmousemove="getMousePosition()" onmousedown="getCell()"> </canvas> </body> </html> ``` The file worldmap.js which displays the grid ``` function draw(){ var c=document.getElementById("canvas"); var ctx=c.getContext("2d"); var img = new Image(); img.onload = function(){ ctx.drawImage(img,0,0); ctx.stroke(); }; img.src = './pics/grid.jpg'; } ``` And here the more source file worldmapMouseEvents.js which acts strangely after scrolling ``` function getMousePosition() { var x = new Number(); var y = new Number(); var canvas = document.getElementById("canvas"); if (event.x != undefined && event.y != undefined) { x = event.x; y = event.y; } else { x = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft; y = event.clientY + document.body.scrollTop + document.documentElement.scrollTop; } x -= canvas.offsetLeft; y -= canvas.offsetTop; return [x,y]; } ``` Here the function that calculates which hexagon is clicked by using circles (The math is correct and its pretty simple to (xCoord - xCenter)^2 + (yCoord -yCenter)^2. If the radius^2 is equal or smaller its the point is within the circle. Those arrays in the beginning are just center coordinates of the grid.) ``` function getCell(){ var xOddRows = new Array(25, 65, 105, 145, 185, 225, 265, 305, 345, 385, 425, 465, 505, 545, 585, 625, 665, 705, 745, 785, 825, 865, 905, 945, 985); var yOddRows = new Array(35, 115, 195, 275, 355, 435, 515, 595, 675, 755, 835, 915, 995); var xEvenRows = new Array(45, 84, 125, 165, 205, 245, 285, 325, 365, 405, 445, 485, 525, 565, 605, 645, 685, 725, 765, 805, 845, 885, 925, 965, 1005); var yEvenRows = new Array(75, 155, 235, 315, 395, 475, 555, 635, 715, 795, 875, 955); var position = getMousePosition(); var x = position[0]; var y = position[1]; for(var yOddRowsRunner = 0; yOddRowsRunner < 13; yOddRowsRunner++){ for( var xOddRowsRunner = 0; xOddRowsRunner < 25; xOddRowsRunner++){ var circle = (x - xOddRows[xOddRowsRunner])*(x - xOddRows[xOddRowsRunner]) + (y - yOddRows[yOddRowsRunner])*(y - yOddRows[yOddRowsRunner]); var radius = (20 * 20); if(radius >= circle){ yPos = (2 * yOddRowsRunner) +1 ;//This is just for nicer output return [yPos, xOddRowsRunner]; } } } for(var yEvenRowsRunner = 0; yEvenRowsRunner < 12; yEvenRowsRunner++){ for( var xEvenRowsRunner = 0; xEvenRowsRunner < 25; xEvenRowsRunner++){ var circle = (x - xEvenRows[xEvenRowsRunner])*(x - xEvenRows[xEvenRowsRunner]) + (y - yEvenRows[yEvenRowsRunner])*(y - yEvenRows[yEvenRowsRunner]); var radius = (20 * 20); if(radius >= circle){ yPos = (2 * yEvenRowsRunner) +2; //This is just for nicer output return [yPos, xEvenRowsRunner]; } } } return null; } ``` So this is the complete code and like I said, it works fine as long as you don't use the scrollbars. I really appreciate your help - this whole thing drives me nuts.

Original source