Why the cursor and paint position don't match:
canvas.width = logical pixels (e.g., 800)canvas.getBoundingClientRect().width = CSS rendered pixels (e.g., 400px on screen)Fix: use the correct scale factor
function getImageCoordsFromEvent(ev){
const rect = canvas.getBoundingClientRect();
let localX = ev.offsetX || (ev.clientX - rect.left);
let localY = ev.offsetY || (ev.clientY - rect.top);
localX = Math.min(rect.width - 1, Math.max(0, localX));
localY = Math.min(rect.height - 1, Math.max(0, localY));
const scaleX = canvas.width / rect.width;
const scaleY = canvas.height / rect.height;
return {
x: Math.min(canvas.width - 1, Math.max(0, Math.round(localX * scaleX))),
y: Math.min(canvas.height - 1, Math.max(0, Math.round(localY * scaleY))),
clientX: ev.clientX,
clientY: ev.clientY
};
}