IQAndreas
IQAndreas

Reputation: 8468

How to reliably get the exact location of a click event on a canvas?

How do I get the exact point that was clicked on a canvas?

JS-Fiddle: http://jsfiddle.net/IQAndreas/yRMZ6/

None of the "built in" event properties (clientX, pageX, screenX) get the value I am searching for.

Searching Google or previous question reveals several answers, but most of them assume things like "the canvas must be fullscreen", or for some other reason, they fail to work in the test above.

Upvotes: 1

Views: 362

Answers (2)

markE
markE

Reputation: 105035

You can use .getBoundingClientRect to get the canvas element position--including scrolling:

var BB=canvas.getBoundingClientRect();

Then you can get the mouse position relative to the canvas using event.clientX and event.clientY adjusted by the bounding box of the canvas element.

Note about borders and padding: You can click on the border of a canvas element and it will fire a canvas click event. This means [0,0] on the canvas is on the top-left corner of the canvas border. However the drawing area of a canvas is inside the border. Therefore, if you want to get the x,y of a click relative to the canvas drawing area you must also subtract the border size. The same is true about padding. Therefore if you want to get the x,y of a click relative to the canvas drawing area you must also subtract the padding size.

function handleMousedown(e){

    var BB=canvas.getBoundingClientRect();
    var x=e.clientX-BB.left-borderLeftWidth-paddingLeft;
    var y=e.clientY-BB.top-borderTopWidth-paddingTop;
    console.log(x,y);

}

To get the border and padding you can use .getComputedStyle:

// a function using getComputedStyle to fetch resolved CSS values

  function getStyle(elem,stylename){
      return(
          window
          .getComputedStyle(elem,null)
          .getPropertyValue(stylename)
      );
  }

// Fetch border and padding

var borderLeftWidth=getStyle(canvas,"border-left-width");
var borderTopWidth=getStyle(canvas,"border-top-width");
var paddingLeft=getStyle(canvas,"padding-left");
var paddingTop=getStyle(canvas,"padding-top");

Upvotes: 0

Flash Thunder
Flash Thunder

Reputation: 12036

The main problem in your example is padding and real position of canvas start...

You can obtain padding using getComputedStyle function, and find real canvas start on page with this function:

function getPos(el) {
    var pl = parseInt(window.getComputedStyle(el, null).getPropertyValue('padding-left'));
    var pt = parseInt(window.getComputedStyle(el, null).getPropertyValue('padding-top'));
    for (var lx=0, ly=0;
         el != null;
         lx += el.offsetLeft, ly += el.offsetTop, el = el.offsetParent);
    return {x: lx + pl,y: ly + pt};
}

Workin' example on JSFiddle

Please note that border affects that aswell, so you may want to add window.getComputedStyle(el, null).getPropertyValue('border-top') and window.getComputedStyle(el, null).getPropertyValue('border-left') aswell.

Upvotes: 1

Related Questions