验证鼠标位置是否在 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 上做的,所以你可以马上看到变化...
但同样适用于您喜欢的任何活动
我正在尝试使用 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 上做的,所以你可以马上看到变化...
但同样适用于您喜欢的任何活动