EDIT: I have better rewrite the question, I can see was badly worded. Well worthy of a down vote... Apologies.
I'm trying to get x,y coordinates when the user clicks inside a canvas element.
I believe I have a correct solution. I have constructed a unit-test, which my solution passes.
What I'm asking is whether it is possible to construct a unit-test for which my solution fails. Maybe by CSS-scaling the canvas element, enclosing in an iframe, etc. This question is about strengthening the unit test.
As I am newcomer to web development, I'm guessing there are awkward scenarios that I am currently unable to anticipate.
Here is my unit test:
function getNumericStyleProperty(style, prop){
return parseInt(style.getPropertyValue(prop),10) ;
}
function element_position(e) {
var x = 0, y = 0;
var inner = true ;
do {
x += e.offsetLeft;
y += e.offsetTop;
var style = getComputedStyle(e,null) ;
var borderTop = getNumericStyleProperty(style,"border-top-width") ;
var borderLeft = getNumericStyleProperty(style,"border-left-width") ;
y += borderTop ;
x += borderLeft ;
if (inner){
var paddingTop = getNumericStyleProperty(style,"padding-top") ;
var paddingLeft = getNumericStyleProperty(style,"padding-left") ;
y += paddingTop ;
x += paddingLeft ;
}
inner = false ;
} while (e = e.offsetParent);
return { x: x, y: y };
}
var c = document.getElementById('c');
var t = c.getContext('2d');
t.font = '10px monospace';
c.addEventListener('click', function(e) {
t.fillStyle = "white"
t.fillRect(0, 0, c.width, c.height);
t.fillStyle = "black"
t.fillText('page: ' + e.pageX
+ ", " + e.pageY, 16, 16*1 );
var bcr = e.target.getBoundingClientRect();
t.fillText('BoundingClientRect: ' + bcr.left
+ ", " + bcr.top , 16, 16*2);
// Method 1
var style = getComputedStyle(e.target,null) ;
var borderTop = getNumericStyleProperty(style,"border-top-width") ;
var borderLeft = getNumericStyleProperty(style,"border-left-width") ;
var paddingTop = getNumericStyleProperty(style,"padding-top") ;
var paddingLeft = getNumericStyleProperty(style,"padding-left") ;
t.fillText('client : ' + e.clientX
+ ", " + e.clientY, 16, 16*3);
t.fillText('bcr.x-client-border-padding: '
+ (e.clientX - bcr.left - borderLeft - paddingLeft)
+ ", " + (e.clientY - bcr.top - borderTop - paddingTop), 16, 16*4);
// Method 2
var p = element_position(e.target);
t.fillText('element_position: ' + p.x
+ ", " + p.y, 16, 16*5);
t.fillText('e.page - element_position(): '
+ (e.pageX - p.x)
+ ", " + (e.pageY - p.y), 16, 16*6);
}, false);
body {
margin: 1em;
background: #8888ff;
padding: 1em;
}
.myDiv {
position: absolute;
left: 20px;
top: 40px;
border: solid #88ff88 10px;
background: green;
margin: 1em;
padding: 0.5em;
}
canvas {
border: solid red 20px;
position: relative;
left: 20px;
top: 0px;
padding: 10px;
background: brown;
margin: 1em
}
<p style="background:white">body</p>
<div class="myDiv">
<p style="background:white">myDiv</p>
<canvas id="c" width="300" height="200" style="cursor:crosshair"> </canvas>
</div>
How could this unit-test be improved? I'm trying to construct the simplest "most awkward scenario".
Can anyone adapt it so that it no longer returns the correct click position within the canvas?
EDIT: blurb from the original question moved here:
There are a lot of bad solutions. The Internet seems full of copy-paste coding when I google this one. Although I have solutions I could work with, I would like to examine this problem more closely and see whether a robust generic solution can be achieved.
Here are various solutions I've found:
getting mouse position relative to content area of an element -- this question has an excellent answer (together with live example) which still exhibits the same offset problem.How do I get the coordinates of a mouse click on a canvas element? <-- this question is hopelessly cluttered.
http://miloq.blogspot.in/2011/05/coordinates-mouse-click-canvas.html <-- also exhibits the same behaviour.
Getting cursor position in a canvas without jQuery <-- uses
document.documentElement
which might be an alternative to faffling with CSS margin/border/padding, or just an error. Part of the problem is that it is such a common question, everyone has tried to do it, but there is no unique solution. So there is a lot of clutter. Another part of the problem is that the underlying browser APIs keep shifting.Another part of the problem is that nobody seems to be testing against a setup that evinces failure from inferior methods, and that's what I'm trying to address here.