How do I check if a mouse click is inside a rotated text on the HTML5 Canvas in JavaScript?

后端 未结 2 1047
有刺的猬
有刺的猬 2021-01-28 05:06

I have drawn a text on the canvas in coordinates X, Y and saved them. I have a simple method that checks if a mouse click has happened inside the text boundaries. The problem is

相关标签:
2条回答
  • 2021-01-28 05:43

    Create a rect object which is rotated at the same angle as the text, but not drawn.

    Then use:

    // set transforms here.
    // add rect representing text region:
    ctx.beginPath();
    ctx.rect(x, y, w, h);  // region for text
    if (ctx.isPointInPath(mx, my)) {
        // we clicked inside the region
    }
    ctx.setTransform(1,0,0,1,0,0);  // reset transforms after test
    

    Demo:

    var canvas = document.querySelector("canvas"),
        ctx = canvas.getContext("2d"),
        txt = "ROTATED TEXT", tw, region;
    
    // transform and draw some rotated text:
    ctx.textAlign = "center";
    ctx.textBaseline = "middle";
    ctx.font = "32px sans-serif";
    ctx.translate(150, 75);
    ctx.rotate(0.33);
    ctx.translate(-150, -75);
    ctx.fillText(txt, 150, 75);
    tw = ctx.measureText(txt).width;
    
    // define a region for text:
    region = {x: 150 - tw*0.5, y: 75 - 16, w: tw, h:32}; // approx. text region
    
    // function to check if mouse x/y is inside (transformed) region
    function isInText(region, x, y) {
      ctx.beginPath();
      ctx.rect(region.x, region.y, region.w, region.h);
      return ctx.isPointInPath(x, y);
    }
    
    // test for demo
    canvas.onmousemove = function(e) {
      var rect = canvas.getBoundingClientRect(),
          x = e.clientX - rect.left,
          y = e.clientY - rect.top;
      
      // just to visualize:
      ctx.clearRect(0,0,300,150);
      ctx.fillStyle = isInText(region, x, y) ? "red" : "black";
      ctx.fillText(txt, 150, 75);
    };
    <canvas></canvas>

    0 讨论(0)
  • 2021-01-28 06:04

    DO NOT USE BELOW CODE DIRECTLY. HERE I'M TRYING TO EXPLAIN ONLY THE LOGIC THAT HOW YOU CAN PROCEED WITH THIS KIND OF PROBLEMS. YOU MAY HAVE TO WRITE CODE ACCORDING TO YOUR PROBLEM, OR EXTEND THIS SOLUTION TO FIT INTO YOUR PROBLEM

    This is more of the mathematical problem where you have to find whether a point is inside rotated Rectangle or not(same as what @user1693593 said) You can find a rectangle that is covering text(rect(x1: text.x1, y1: text.y1, x2: text.x2, y2: text.y2) assuming (text.x1, text.y1) denotes top-left corner of text. Now rotate the rect about it's centre by theta angle and find out x1,y1,x2,y2:

    Assume all angle calculation will happen in +ve angles.

    if theta < 0 then theta = (360 - abs(theta))
    

    Now calculate angle between centre point and point(x2, y2)(Angle from centre to any corner of rect will be same, we are calculating for (x2, y2) because it will give us positive angle)

    var width = (x2-x1);
    var height = (y2-y1)
    var hypotenuse = Math.pow(width*width + height*height, 0.5);
    var innerAngle = Math.acos(x2 - x2 / hypotenuse);
    

    Now calculate final angle of corners from centre

    (x1, y1), angle((Math.PI + baseAngle) + angle) %(Math.PI*2)
    (x2, y1), angle((Math.PI*2) - baseAngle + angle) % (Math.PI*2)}
    (x1, y2), angle((Math.PI - baseAngle) + angle) % (Math.PI*2)}
    (x2, y2), angle(baseAngle + angle) % (Math.PI*2)}
    

    Now find out rotated Points of rectangle:

    point.x = centre.x + (hypotenuse * Math.cos(point.angle));
    point.y = centre.y + (hypotenuse * Math.sin(point.angle));
    

    After rotating points It may happen that their order get changed, to make sure the correct order sort them based on x-axis, if two points have same x-axis then sort them based on y-axis (use any sorting) Now we got sorted points. Name them based on their position p0, p1, p2, p3 Find new boundary of rotated rect from these points, find boundary in x direction and y direction:

    var boundary_x1 = ( (p1.x - p0.x) / (p1.y - p0.y) ) * (mousePos.y - p0.y) + p0.x;
    var boundary_x2 = ( (p3.x - p2.x) / (p3.y - p2.y) ) * (mousePos.y - p2.y) + p2.x;
    var boundary_y1 = ( (p2.y - p0.y) / (p2.x - p0.x)) * (mousePos.x - p0.x) + p0.y;
    var boundary_y2 = ( (p3.y - p1.y) / (p3.x - p1.x)) * (mousePos.x - p1.x) + p1.y;
    

    after getting boundary points in x and y direction we can easily put mid point condition and can find whether a point(mousepoint) is clicked in rect or not:

    var clickedInside = (mousePos.x > boundary_x1 && mousePos.x < boundary_x2) && (mousePos.y > boundary_y1 && mousePos.y < boundary_y2);
    

    if clickedInside is true then mouseclick happened inside rect

    0 讨论(0)
提交回复
热议问题