【发布时间】:2023-03-22 13:15:01
【问题描述】:
我有一个用于绘制到 HTML Canvas 的 Rectangle 类。它有一个在它的 draw 方法中应用的旋转属性。如果用户在画布内拖动,则会绘制一个选择框。当矩形在选择框内使用数学时,如何将矩形的active 属性设置为true?这是我在另一种语言和上下文中遇到的问题,因此我没有可用的所有 Canvas 方法(例如isPointInPath)。
我发现了一篇关于查找 Mouse position within rotated rectangle in HTML5 Canvas 的 StackOverflow 帖子,我在 Rectangle 方法 checkHit 中实现了该帖子。但是,它不考虑选择框。它只是看着鼠标 X 和 Y,它仍然关闭。浅蓝色点是矩形围绕其旋转的原点。如果有任何不清楚的地方,请告诉我。谢谢。
class Rectangle
{
constructor(x, y, width, height, rotation) {
this.x = x;
this.y = y;
this.height = height;
this.width = width;
this.xOffset = this.x + this.width/2;
this.yOffset = this.y + ((this.y+this.height)/2);
this.rotation = rotation;
this.active = false;
}
checkHit()
{
// translate mouse point values to origin
let originX = this.xOffset;
let originY = this.yOffset;
let dx = marquee[2] - originX;
let dy = marquee[3] - originY;
// distance between the point and the center of the rectangle
let h1 = Math.sqrt(dx*dx + dy*dy);
let currA = Math.atan2(dy,dx);
// Angle of point rotated around origin of rectangle in opposition
let newA = currA - this.rotation;
// New position of mouse point when rotated
let x2 = Math.cos(newA) * h1;
let y2 = Math.sin(newA) * h1;
// Check relative to center of rectangle
if (x2 > -0.5 * this.width && x2 < 0.5 * this.width && y2 > -0.5 * this.height && y2 < 0.5 * this.height){
this.active = true;
} else {
this.active = false;
}
}
draw()
{
ctx.save();
ctx.translate(this.xOffset, this.yOffset);
ctx.fillStyle = 'rgba(255,255,255,1)';
ctx.beginPath();
ctx.arc(0, 0, 3, 0, 2 * Math.PI, true);
ctx.fill();
ctx.rotate(this.rotation * Math.PI / 180);
ctx.translate(-this.xOffset, -this.yOffset);
if (this.active)
{
ctx.fillStyle = 'rgba(255,0,0,0.5)';
} else {
ctx.fillStyle = 'rgba(0,0,255,0.5)';
}
ctx.beginPath();
ctx.fillRect(this.x, this.y, this.width, this.y+this.height);
ctx.closePath();
ctx.stroke();
ctx.restore();
}
}
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var raf;
var rect = new Rectangle(50,50,90,30,45);
var marquee = [-3,-3,-3,-3];
var BB=canvas.getBoundingClientRect();
var offsetX=BB.left;
var offsetY=BB.top;
var start_x,start_y;
let draw = () => {
ctx.clearRect(0,0, canvas.width, canvas.height);
//rect.rotation+=1;
rect.draw();
ctx.fillStyle = "rgba(200, 200, 255, 0.5)";
ctx.fillRect(parseInt(marquee[0]),parseInt(marquee[1]),parseInt(marquee[2]),parseInt(marquee[3]))
ctx.strokeStyle = "white"
ctx.lineWidth = 1;
ctx.rect(parseInt(marquee[0]),parseInt(marquee[1]),parseInt(marquee[2]),parseInt(marquee[3]))
ctx.stroke()
raf = window.requestAnimationFrame(draw);
}
let dragStart = (e) =>
{
start_x = parseInt(e.clientX-offsetX);
start_y = parseInt(e.clientY-offsetY);
marquee = [start_x,start_y,0,0];
canvas.addEventListener("mousemove", drag);
}
let drag = (e) =>
{
let mouseX = parseInt(e.clientX-offsetX);
let mouseY = parseInt(e.clientY-offsetY);
marquee[2] = mouseX - start_x;
marquee[3] = mouseY - start_y;
rect.checkHit();
}
let dragEnd = (e) =>
{
marquee = [-10,-10,-10,-10];
canvas.removeEventListener("mousemove", drag);
}
canvas.addEventListener('mousedown', dragStart);
canvas.addEventListener('mouseup', dragEnd);
raf = window.requestAnimationFrame(draw);
body
{
margin:0;
}
#canvas
{
width: 360px;
height: 180px;
border: 1px solid grey;
background-color: grey;
}
<canvas id="canvas" width="360" height="180"></canvas>
【问题讨论】:
-
您正在寻找跟踪使用仿射变换矩阵在数学上完成的变换。 1. 为未变换的矩形分配四个 x,y 顶点。 2. 使用矩阵数学计算变换(例如旋转)的顶点。 3. 绘制变换后的矩形。 4. 要对矩形进行“命中测试”,请反转矩阵以获得未转换的 x,y 选取框顶点。 5.命中测试未转换的选框与原始未转换的矩形。关于转换矩阵的信息在 SO 和其他地方很容易获得
标签: javascript canvas html5-canvas trigonometry