我试图在用户点击画布元素时获取x,y坐标。
我相信我有一个正确的解决方案。我构建了一个单元测试,我的解决方案通过了。
我要问的是 是否可以构建我的解决方案失败的单元测试 。也许通过CSS缩放canvas元素,封装在iframe等中。这个问题是关于加强单元测试。
由于我是网络开发的新手,我猜测有一些我目前无法预料的尴尬场景。
这是我的单元测试:
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>
&#13;
如何改进这种单元测试?我试图构建最简单的&#34;最尴尬的场景&#34;。
任何人都可以调整它以使 不再在画布中返回正确的点击位置 吗?
编辑:从原来的问题移到这里:
有很多不好的解决方案。互联网似乎充满了 当我谷歌这个时复制粘贴编码。虽然我有解决方案 可以合作,我想更仔细地研究这个问题 看看是否可以实现强大的通用解决方案。
以下是我发现的各种解决方案:
getting mouse position relative to content area of an element - 这个问题有一个很好的答案(连同实例),它仍然表现出相同的偏移问题。How do I get the coordinates of a mouse click on a canvas element? &lt; - 这个问题毫无希望地混乱。
http://miloq.blogspot.in/2011/05/coordinates-mouse-click-canvas.html &lt; - 也表现出相同的行为。
Getting cursor position in a canvas without jQuery &lt; - 使用
document.documentElement
可能是替代 弄脏CSS边距/边框/填充,或只是一个错误。的一部分 问题是,这是一个普遍的问题,每个人都试图这样做 它,但没有独特的解决方案。所以有很多混乱。 问题的另一部分是底层浏览器API保留 移动。问题的另一部分是似乎没有人在测试 一种能够证明劣等方法失败的设置,这就是什么 我试图在这里发言。
答案 0 :(得分:2)
这是因为您没有关注earlier advices given to you。
当您使用getBoundingClientRect()
时,它会添加边框和填充(如果有)。你必须从结果中减去它们。
建议是wrap the canvas in a div而不是这样做,而是应用边框和填充。在您的代码中实现此功能会导致以下更新。
PS:此外,您在评论中标记为“工作”的代码无法正常工作(请参阅控制台,它既不会将任何内容打印到画布上。如果是,它会写在上一个上面代码...)。
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('pageX: ' + e.pageX, 16, 16);
t.fillText('pageY: ' + e.pageX, 16, 16*2);
var bcr = e.target.getBoundingClientRect();
t.fillText('BoundingClientRect.left: ' + bcr.left, 16, 16*3);
t.fillText('BoundingClientRect.top: ' + bcr.top , 16, 16*4);
// fails
t.fillText('clientX : ' + e.clientX, 16, 16*5);
t.fillText('clientY : ' + e.clientY, 16, 16*6);
t.fillText('bcr.x-clientX: ' + (e.clientX - bcr.left), 16, 16*7);
t.fillText('bcr.y-clientY: ' + (e.clientY - bcr.top), 16, 16*8);
// works
var p = element_position(e.eventTarget);
t.fillText('element_position x: ' + p.x, 16, 16*9);
t.fillText('element_position y: ' + p.y, 16, 16*10);
t.fillText('canvas x: ' + (e.pageX - p.x), 16, 16*11);
t.fillText('canvas y: ' + (e.pageY - p.y), 16, 16*12);
}, 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;
}
.wrapper {
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>
<div class="wrapper">
<canvas id="c" width="200" height="200" style="cursor:crosshair"> </canvas>
</div>
</div>