如何检查鼠标单击是否在 JavaScript 中的 HTML5 Canvas 上的旋转文本内?

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

我在 canvas 坐标 X、Y 上绘制了一个文本并保存了它们。我有一个简单的方法来检查鼠标点击是否发生在文本边界内。问题是当我将文本旋转 45 度时,我无法检查旋转文本中是否发生了鼠标单击。

简而言之,如何检查鼠标点击是否在旋转的文本或形状内?

创建一个与文本旋转相同角度但不绘制的矩形对象。

然后使用:

// 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

演示:

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>

请勿直接使用以下代码。在这里,我试图仅解释您如何处理此类问题的逻辑。您可能需要根据您的问题编写代码,或者扩展此解决方案以适应您的问题

这更像是一个数学问题,你必须找出一个点是否在旋转的矩形内(与@user1693593 所说的相同) 你可以找到一个覆盖 text(rect(x1: text.x1, y1: text.y1, x2: text.x2, y2: text.y2) 假设 (text.x1, text.y1) 表示 top-left 文本角。 现在将矩形围绕其中心旋转 theta 角并找出 x1,y1,x2,y2:

假设所有角度计算都将发生在 +ve 个角度中。

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

现在计算中心点和点 (x2, y2) 之间的角度(从中心到矩形的任何角的角度都是相同的,我们正在计算 (x2, y2) 因为它会给我们正角度)

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);

现在计算角与中心的最终角度

(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)}

现在找出矩形的旋转点:

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

旋转点后它们的顺序可能会发生变化,以确保正确的顺序根据 x-axis 对它们进行排序,如果两个点具有相同的 x-axis 然后根据 [= 对它们进行排序39=](使用任何排序) 现在我们得到了排序点。根据它们的位置命名它们 p0、p1、p2、p3 从这些点找到旋转矩形的新边界,在x方向和y方向找到边界:

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;

得到x和y方向的边界点后,我们可以很容易地设置中点条件,并可以判断一个点(鼠标点)是否在矩形上被点击:

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

如果 clickedInside 为真则鼠标点击发生在 rect 内