验证鼠标位置是否在 HTML5 Canvas 中的旋转矩形内

Validate if mouse position is within rotated rectangle in HTML5 Canvas

我正在尝试使用 HTML5 canvas 功能。我在 canvas 上设置了一个矩形,它被旋转了。当我在旋转的矩形内单击时,它不会返回 true。也许我只是在理解解决方案时绊倒了。我做错了什么?我有下面的代码。

我正在使用参考的解决方案:
Mouse position within rotated rectangle in HTML5 Canvas

        <?php

    $canvas_width=800;
    $canvas_height=1336;


    echo <<<_END



    <canvas id="myCanvas" width=$canvas_width height=$canvas_height style="border:1px solid #d3d3d3;">
    Your browser does not support the HTML5 canvas tag.
    </canvas>

    <script>

    //Get the canvas element by using the getElementById method.
               canvas = document.getElementById('myCanvas');

               HEIGHT = canvas.height;
               WIDTH = canvas.width;
               CANVAS_LEFT = 9;
               CANVAS_RIGHT = canvas.width+CANVAS_LEFT;

               CANVAS_TOP = 9;
               CANVAS_BOTTOM = canvas.height+CANVAS_TOP;

                    lastMouseX = 0;                 // The last seen mouse X coordinate
                        lastMouseY = 0;                 // the last seen mouse Y coordinate
                rectangleDrawAndRotated=false;
                    mouseX =0;
                mouseY=0;
                    offsetX = 0;
                        offsetY = 0;
                originX=0;
                originY=0;
                 width=0;
                height=0;

    //Get a 2D drawing context for the canvas.

                ctx = canvas.getContext('2d');


            myimage=new Image()
            myimage.src='/Farm_planner/images/The_Farm_at_Dover_Vineyards_Google_Maps.png'  

            myimage.onload=function()
            {
            ctx.drawImage(myimage,1,1,800,1336)
            }



    // When true, moving the mouse draws on the canvas


    isDrawing = false;
    x = 0;
    y = 0;


    // event.offsetX, event.offsetY gives the (x,y) offset from the edge of the canvas.

    // Add the event listeners for mousedown, mousemove, and mouseup

      canvas.addEventListener('mousedown', e => {
      x = e.offsetX;
      y = e.offsetY;
      isDrawing = true;

       console.log("mouse down",x,y,width,height);

       if (rectangleDrawAndRotated ===true){
         originX = x + width/2;
         originY = y + height/2;


       getMouse(e);

    //   get the locations of the mouse and assign to mouseX and mouseY


       clickState=false;
       console.log(clickState,mouseX, mouseY,x,y);

      if (clickedOnRectangle(x,y)) clickState=true;


       console.log(clickState,mouseX, mouseY,x,y);
            }

    });

    canvas.addEventListener('mousemove', e => {
      if (isDrawing === true) {
     //   drawLine(ctx, x, y, e.offsetX, e.offsetY);
     //   x = e.offsetX;
     //   y = e.offsetY;
      }
    });

    window.addEventListener('mouseup', e => {
      if (isDrawing === true) {
        drawLine(ctx, x, y, e.offsetX, e.offsetY);
        isDrawing = false;
        mouseX =0;
        mouseY=0;
        rectangleDrawAndRotated=true;

            console.log("mouse up",x,y,width,height);
      }
    });

    function drawLine(ctx, x1, y1, x2, y2) {
    // ctx.beginPath();
    //  ctx.strokeStyle = 'black';
        ctx.lineWidth = 3;
    //  ctx.moveTo(x1, y1);
    //  ctx.lineTo(x2, y2);
    //  ctx.stroke();
    //  ctx.closePath();
            width=x2-x1;
            height=y2-y1;
            xCoord=x1;
            yCoord=y1;

        drawRectangle(x1,y1,width,height)   ;

        rotateDrawing(x1,y1,width,height);
        lastMouseX = 0;                 // The last seen mouse X coordinate
        lastMouseY = 0;                 // the last seen mouse Y coordinate  

    }



       function drawRectangle(xCoord,yCoord,width,height) {

      //  ctx.strokeRect(xCoord,yCoord,width,height);
            ctx.rect(xCoord,yCoord,width,height);
             originX = xCoord + width/2;
             originY = yCoord + height/2;
             r=45*(Math.PI / 180);  

      }


       function clickedOnRectangle(x,y) {

     //   dtermine if the user clicked on the area of the rectangle that has been rotated

     // Our origin of rotation is the center of the rectangle
     // Our rectangle has its upper-left corner defined by x,y, its width
     // defined in w, height in h, and rotation(in radians) in r.  

     // translate mouse point values to origin

        dx = mouseX - originX;
        dy = mouseY - originY;

      // distance between the point and the center of the rectangle

        var h1 = Math.sqrt(dx*dx + dy*dy);
        var currA = Math.atan2(dy,dx);

      // Angle of point rotated around origin of rectangle in opposition

        var newA = currA - r;

      // New position of mouse point when rotated

        var x2 = Math.cos(newA) * h1;
        var y2 = Math.sin(newA) * h1;

        console.log(x,y,width,height,mouseX,mouseY,originX,originY,dx,dy,h1,currA,r,newA,x2,y2)

      // Check relative to center of rectangle

        if (x2 > -0.5 * width && x2 < 0.5 * width && y2 > -0.5 * height && y2 < 0.5 * height){
            console.log('true');
            return true;
        }

       }

    // Sets mouseX and mouseY variables taking into account padding and borders
                    function getMouse(e) {
                            var element = canvas;
                            var offsetX = 0;
                            var offsetY = 0;

    // Calculate offsets
                            if (element.offsetParent) {
                                    do {
                                            offsetX += element.offsetLeft;
                                            offsetY += element.offsetTop;
                                    } while ((element = element.offsetParent));
                            }   

    // Calculate the mouse location
                            mouseX = e.pageX - offsetX;
                            mouseY = e.pageY - offsetY;

    // Calculate the change in mouse position for the last
    // time getMouse was called
                            changeInX = mouseX - lastMouseX;
                            changeInY = mouseY - lastMouseY;

    // Store the current mouseX and mouseY positions
                            lastMouseX = mouseX;
                            lastMouseY = mouseY;



                    }      



          function rotateDrawing(xCoord,yCoord,width,height) 
    {
            ctx.setTransform(1,0,0,1,0,0);
            ctx.translate(xCoord+.5*width,yCoord+.5*height );
            r=45*(Math.PI / 180);  // 45 degrees  as radian
            ctx.rotate(r); // 
            ctx.fillStyle = "red";
            ctx.fillRect(-.5*width, -.5*height, width, height);
            console.log(xCoord,yCoord,width,height)
            }




    </script>    

    _END;

是的,您正在解决这个问题,将您的矩形视为多边形,您不必担心旋转,而且您可以拥有比矩形更复杂的形状。

我正在使用光线投射算法: https://github.com/substack/point-in-polygon/blob/master/index.js
这样,我们需要做的就是检查鼠标是否在多边形内,仅此而已。

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext("2d");
const rect = canvas.getBoundingClientRect();

const poly = [[89, 9], [13, 19], [19, 56], [98, 36], [89, 9]]

function draw(p) {
  p.map(x => ctx.lineTo(x[0], x[1]));
  ctx.stroke();
}

function inside(p, vs) {
  var inside = false;
  for (var i = 0, j = vs.length - 1; i < vs.length; j = i++) {
    var xi = vs[i][0], yi = vs[i][1];
    var xj = vs[j][0], yj = vs[j][1];
    var intersect = ((yi > p[1]) != (yj > p[1])) && (p[0] < (xj - xi) * (p[1] - yi) / (yj - yi) + xi);
    if (intersect) inside = !inside;
  }
  return inside;
};

draw(poly)
canvas.addEventListener('mousemove', function(evt) {
  ctx.clearRect(100, 0, canvas.width, canvas.height);
  let x = inside([ evt.clientX - rect.left, evt.clientY - rect.top ], poly)
  ctx.fillText(x, 110, 20);
}, false);
<canvas id="canvas"></canvas>

我是在 mousemove 上做的,所以你可以马上看到变化...
但同样适用于您喜欢的任何活动