Click in Canvas is three pixels off

蹲街弑〆低调 提交于 2020-01-10 05:27:04

问题


I've spent the whole day trying to get a click over my canvas to return the pixel xy offset. What a mission this has been!

This is what I've ended up with:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>JS Bin</title>
</head>
<body>
 <script src="https://code.jquery.com/jquery-1.10.2.js"></script>

  <div id="logX">x</div>
  <div id="logY">y</div>

  <div style="margin-left:100px">
    <div style="margin-left:100px">
      <canvas id="myCanvas" width="100" height="1000" style="border:20px solid #000000;"></canvas>
    </div>
  </div>

  <script>
  var canvas = document.getElementById('myCanvas');
  canvas.addEventListener('click', on_canvas_click, false);

  function getNumericStyleProperty(style, prop) {
    return parseInt(style.getPropertyValue(prop),10);
  }

  function on_canvas_click(ev) {
    var boundingRect = ev.target.getBoundingClientRect();

    var x = ev.clientX - boundingRect.left,
        y = ev.clientY - boundingRect.top;

    var style = getComputedStyle(canvas, null);

    x -= getNumericStyleProperty(style, "margin-left");
    y -= getNumericStyleProperty(style, "margin-top");

    x -= getNumericStyleProperty(style, "border-left-width");
    y -= getNumericStyleProperty(style, "border-top-width");

    x -= getNumericStyleProperty(style, "padding-left");
    y -= getNumericStyleProperty(style, "padding-top");

    $("#logX").text(        ev.target.getBoundingClientRect().left
                   + ", " + ev.clientX
                   + ", " + canvas.offsetLeft
                   + ", " + x
                  );

    $("#logY").text(        ev.target.getBoundingClientRect().top
                   + ", " + ev.clientY
                   + ", " + canvas.offsetTop
                   + ", " + y
                  );
  }

  //$( document ).on( "mousemove", function( event ) {
  //$( "#log" ).text( "pageX: " + event.pageX + ", pageY: " + event.pageY );
  //});
</script>
</body>
</html>

http://jsbin.com/xajeluxija/2/

It produces a white canvas within a thick black border.

Click within the canvas and it will display the XY coordinates.

As you can see, I'm deliberately creating a canvas that requires scrolling, and is not aligned to the left. This is to force a robust solution. (Can the test case be improved?)

It very nearly works! But if you try clicking in the top left corner you will get (1,2).

It should be (0,0).

What is going wrong?

EDIT: 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(?)

EDIT: Now it is 2,2 not 2,1! It is inconsistent! ARGH! I took photos with my camera:

EDIT: On Firefox I get 0.75, 1.91667...

EDIT 15Apr: Two attempts here:
http://jsfiddle.net/Skz8g/47/
http://jsbin.com/taceso/1/


回答1:


As you've discovered, border size is counted in calculating mouse position.

So wrap your canvas in a container div with the container div having the 20px border.

This takes away the extra calculations needed if the border were on the canvas itself.

Note: I put the styles for #borderDiv & #myCanvas in a Style section in the Header.

var canvas = document.getElementById('myCanvas');
canvas.addEventListener('click', on_canvas_click, false);

var context=canvas.getContext('2d');

context.fillStyle='red';
context.fillRect(0,0,10,1);
context.fillRect(0,0,1,10);

function getNumericStyleProperty(style, prop) {
  return parseInt(style.getPropertyValue(prop),10);
}

function on_canvas_click(ev) {
  var boundingRect = ev.target.getBoundingClientRect();
  var x = ev.clientX - boundingRect.left,
      y = ev.clientY - boundingRect.top;

  $("#logX").text("x="+x);
  $("#logY").text("y="+y);
}
#borderDiv{margin:0px; width:100px; height:1000px; border:20px solid black;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<div id="logX">x</div>
<div id="logY">y</div>

<div style="margin-left:100px">
  <div style="margin-left:100px">
    <div id='borderDiv'>
      <canvas id="myCanvas" width=100 height=1000 style="cursor:crosshair"></canvas>
    </div>
  </div>
</div>


来源:https://stackoverflow.com/questions/29607924/click-in-canvas-is-three-pixels-off

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!