ONESHOTGEMS

For game developers

Make the drawn target and pointer test share one coordinate map

A canvas button can look centered under a pointer and still miss because the event is measured in viewport pixels while the game draws in logical-world units. Pick one coordinate system for hit testing, then convert each pointer position through the same display transform used to draw the playfield. This guide focuses on that conversion. It complements responsive-layout planning by tracing a single pointer from the page to a logical target, including the letterbox area around a fixed-size game.

Subtract the canvas origin and scale the point

Start with the event's clientX and clientY and the rectangle returned by canvas.getBoundingClientRect(). The rectangle is positioned relative to the viewport, so subtract its left and top before scaling. If the logical game is 800 by 450 and the displayed rectangle is 400 by 225, multiply the local x and y by two. A pointer at the displayed center then maps to logical (400, 225), regardless of the page's scroll position.

Use the actual content rectangle, not assumptions based on window width. Account for CSS borders or padding outside the canvas, and refresh the mapping after a resize or orientation change. If the game uses a camera offset, letterboxing, or another world transform, invert those operations in reverse order before comparing the point with a game's hit shapes.

Test the whole surface, including dead space

Place a temporary crosshair at the converted pointer location and test all four canvas corners, the center, and each edge of a target. A simple calibration check is to click the center of a drawn circle and confirm the reported world point is near the circle's center. Then click just outside it to check that the hit boundary matches the intended forgiving margin. MDN documents clientX as viewport-relative and getBoundingClientRect() as returning viewport-relative element bounds; pairing those measurements avoids mixing coordinate spaces.

Keep rendering and hit regions linked

Store a target's world position and dimensions once, then use that data both to draw it and to test the pointer against it. Avoid maintaining separate hand-entered screen coordinates for the visible icon and click region. Retest after changing canvas scale, CSS size, device pixel ratio, or camera offset. If the coordinate probe is correct but a target still misses, inspect its shape math and input ordering instead of adding arbitrary pixel offsets.

Questions about canvas hit testing coordinates

Should I use offsetX and offsetY for canvas hits?

They can be convenient for a simple untransformed canvas, but explicit client coordinates, element bounds, and your game transform make each conversion step clearer when layout or camera scaling changes.

Does devicePixelRatio belong in pointer conversion?

Only if your pointer point and hit shapes use backing-store pixels. A common approach maps viewport coordinates into logical game units, keeping device-pixel scaling inside the rendering transform.

Sources and further reading

Report a correction · How these guides are made

Follow your curiosity