0

I was aware of the usual method for finding the click position relative to the canvas, as has been documented before, which in brief is:

  1. Grab event.pageX and event.pageY values to get the position of the click relative to the document
  2. subtract the x and y coords of the canvas on the page, either with canvasEl.offsetLeft/canvas.El.offsetTop or using jQuery's $(canvasEl).offset(), recursing up through parents if necessary
  3. Subtract the scroll position of the page and any parent elements, if any.

Sadly, this doesn't work when both the following are true:

  1. The canvas is part of a Polymer (and I assume any other WebComponent solution that polyfills Shadow DOM) element
  2. The canvas is positioned within a scrolling parent. I did some investigating into this and it looked like Polymer was skipping an ancestor when crossing the shadow boundary, meaning the scroll offset isn't calculated correctly.
Community
  • 1
  • 1
Tom Jardine-McNamara
  • 2,418
  • 13
  • 24

1 Answers1

1

Whenever I've come across this problem, even outside of WebComponents, my initial reaction has always been why is it so hard to get the coordinates of a click on a canvas? Surely that's pretty crucial? Shouldn't the coordinates be calculated for you already?

It turns out that they have, almost. As described elsewhere on SO, The canvas API has a method getBoundingClientRect() which returns a DOMRect (ClientRect in Chrome):

{
    x: 348,
    y: 180.35000610351562,
    width: 128,
    height: 128,
    top: 180.35000610351562,
    right: 476,
    bottom: 308.3500061035156,
    left: 348
}

So the following will reliably get the coordinates of a tap/click relative to the canvas element, come scroll or high water:

var x = event.pageX,
    y = event.pageY; // (or your preferred method, e.g. jQuery)
    bounds = event.target.getBoundingClientRect();

x = x - bounds.left;
y = y - bounds.top;

The above is from Firefox; I found Chrome doesn't include the x and y properties, so probably best to stick to left and top. I haven't tested it on IE or Safari.

I hope this proves useful to someone else - it's been driving me nuts over the past few months. Many thanks to the questions and answers linked to here.

Finally, this answer is a neat solution whether you're using Polymer/WebComponents or not - it just so happens that that was my in-road into the problem and really threw the issue into relief.

Community
  • 1
  • 1
Tom Jardine-McNamara
  • 2,418
  • 13
  • 24