How do I get the coordinates of a mouse click on a canvas element?

后端 未结 22 2388
忘掉有多难
忘掉有多难 2020-11-21 23:56

What\'s the simplest way to add a click event handler to a canvas element that will return the x and y coordinates of the click (relative to the canvas element)?

No

22条回答
  •  醉话见心
    2020-11-22 00:40

    I'm not sure what's the point of all these answers that loop through parent elements and do all kinds of weird stuff.

    The HTMLElement.getBoundingClientRect method is designed to to handle actual screen position of any element. This includes scrolling, so stuff like scrollTop is not needed:

    (from MDN) The amount of scrolling that has been done of the viewport area (or any other scrollable element) is taken into account when computing the bounding rectangle

    Normal image

    The very simplest approach was already posted here. This is correct as long as no wild CSS rules are involved.

    Handling stretched canvas/image

    When image pixel width isn't matched by it's CSS width, you'll need to apply some ratio on pixel values:

    /* Returns pixel coordinates according to the pixel that's under the mouse cursor**/
    HTMLCanvasElement.prototype.relativeCoords = function(event) {
      var x,y;
      //This is the current screen rectangle of canvas
      var rect = this.getBoundingClientRect();
      var top = rect.top;
      var bottom = rect.bottom;
      var left = rect.left;
      var right = rect.right;
      //Recalculate mouse offsets to relative offsets
      x = event.clientX - left;
      y = event.clientY - top;
      //Also recalculate offsets of canvas is stretched
      var width = right - left;
      //I use this to reduce number of calculations for images that have normal size 
      if(this.width!=width) {
        var height = bottom - top;
        //changes coordinates by ratio
        x = x*(this.width/width);
        y = y*(this.height/height);
      } 
      //Return as an array
      return [x,y];
    }
    

    As long as the canvas has no border, it works for stretched images (jsFiddle).

    Handling CSS borders

    If the canvas has thick border, the things get little complicated. You'll literally need to subtract the border from the bounding rectangle. This can be done using .getComputedStyle. This answer describes the process.

    The function then grows up a little:

    /* Returns pixel coordinates according to the pixel that's under the mouse cursor**/
    HTMLCanvasElement.prototype.relativeCoords = function(event) {
      var x,y;
      //This is the current screen rectangle of canvas
      var rect = this.getBoundingClientRect();
      var top = rect.top;
      var bottom = rect.bottom;
      var left = rect.left;
      var right = rect.right;
      //Subtract border size
      // Get computed style
      var styling=getComputedStyle(this,null);
      // Turn the border widths in integers
      var topBorder=parseInt(styling.getPropertyValue('border-top-width'),10);
      var rightBorder=parseInt(styling.getPropertyValue('border-right-width'),10);
      var bottomBorder=parseInt(styling.getPropertyValue('border-bottom-width'),10);
      var leftBorder=parseInt(styling.getPropertyValue('border-left-width'),10);
      //Subtract border from rectangle
      left+=leftBorder;
      right-=rightBorder;
      top+=topBorder;
      bottom-=bottomBorder;
      //Proceed as usual
      ...
    }
    

    I can't think of anything that would confuse this final function. See yourself at JsFiddle.

    Notes

    If you don't like modifying the native prototypes, just change the function and call it with (canvas, event) (and replace any this with canvas).

提交回复
热议问题