加强“获取画布元素上的点击坐标”的单元测试

时间:2015-04-15 16:09:37

标签: html5-canvas mouseclick-event

编辑:我最好重写这个问题,我可以看到措辞严厉。非常值得投票......道歉。

我试图在用户点击画布元素时获取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;
&#13;
&#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保留   移动。

     

问题的另一部分是似乎没有人在测试   一种能够证明劣等方法失败的设置,这就是什么   我试图在这里发言。

1 个答案:

答案 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>