Ellipse - 鼠标碰撞检测
Ellipse - Mouse collision detection
我想知道如何判断鼠标是否在 HTML5 Canvas 上的椭圆上。我需要比边界框检查更精确。
抱歉,这个问题太模糊了。我完全被难住了。
任何帮助将不胜感激。
到目前为止我有这个:
// This is a pretend object. m.x and m.y will have the position of the mouse.
var m = {
x:245,
y:341,
onEnter: function(){}
};
m.onEnter = function () {
console.log('The mouse entered the ellipse!');
};
// The important parts of my ellipse object
var e = {
width:100,
height:50,
x:132,
y:143
};
// This is already working - I use a bounding-box first to increase performance.
if (m.x >= e.x - (e.width/2) && m.x <= e.x + (e.width/2) && m.y >= e.y - (e.height/2) && m.y <= e.y + (e.height/2)) {
if (/* I havn't got the slightest idea what to put here. */) {
m.onEnter();
}
}
对于模糊的初始答案表示歉意,这需要改进,但为了让事情顺利进行...
假定椭圆是平面上围绕两个焦点(F1 和 F2)定义的曲线,使得曲线上每个点到两个焦点的距离之和为常数。
也就是说,对于椭圆上的任意一点P,两个距离F1P + F2P是一个常数。该常数(显然且有帮助)等于所述椭圆的较长(长)轴 A 的长度。
因此,对于这个问题,我怀疑你的椭圆的重要部分不是宽度、高度、x、y,而是它的两个焦点 F1 和 F2(与定义它的椭圆中心等距的 2 个点)和长轴的长度。
然后...对于任何给定的鼠标点击点 M,如果 F1M + F2M < A 的 2 个距离之和,那么您的鼠标点击点在椭圆内。
@pvg 的重复答案是可以的,但是那个重复的答案应该指出他们使用的变量是如何计算的:
// Given cx,cy,a,b defining an ellipse
function isInEllipse(mouseX,mouseY){
var dx=mouseX-cx;
var dy=mouseY-cy;
return ((dx*dx)/(a*a)+(dy*dy)/(b*b)<=1);
}
这是示例代码和演示:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
function reOffset(){
var BB=canvas.getBoundingClientRect();
offsetX=BB.left;
offsetY=BB.top;
}
var offsetX,offsetY;
reOffset();
window.onscroll=function(e){ reOffset(); }
window.onresize=function(e){ reOffset(); }
var PI=Math.PI;
var PI2=PI*2;
var cx=cw/2;
var cy=ch/2;
var a=120;
var b=80;
var points=getPointsOnEllipse(cx,cy,a,b);
$("#canvas").mousemove(function(e){handleMouseMove(e);});
drawEllipse(points);
function dot(x,y,color){
ctx.beginPath();
ctx.arc(x,y,3,0,PI2);
ctx.closePath();
ctx.fillStyle=color;
ctx.fill();
}
function isInEllipse(x,y){
var dx=x-cx;
var dy=y-cy;
return ((dx*dx)/(a*a)+(dy*dy)/(b*b)<=1);
}
function drawEllipse(points){
ctx.beginPath();
ctx.moveTo(points[0].x,points[0].y);
for(var j=0;j<points.length;j++){
ctx.lineTo(points[j].x,points[j].y);
}
ctx.closePath();
ctx.lineWidth=1;
ctx.strokeStyle='forestgreen';
ctx.stroke();
}
function getPointsOnEllipse(cx,cy,a,b){
var startAngle=-PI/2;
var lastX=cx-(a*Math.cos(startAngle));
var lastY=cy+(b*Math.sin(startAngle));
var points=[];
for(var i=0;i<1000;i++){
var angle=startAngle+PI2/1000*i;
var x=cx-(a*Math.cos(angle));
var y=cy+(b*Math.sin(angle));
var dx=x-lastX;
var dy=y-lastY;
var length=parseInt(Math.sqrt(dx*dx+dy*dy));
var eAngle=(Math.atan2(dy,dx)+PI2)%PI2;
if(length>0){
points.push({x:x,y:y,angle:eAngle});
lastX=x;
lastY=y;
}
}
return(points);
}
function handleMouseMove(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
var hit=isInEllipse(mouseX,mouseY);
var color=(hit)?'red':'green';
dot(mouseX,mouseY,color);
}
body{ background-color: ivory; }
#canvas{border:1px solid red; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4>Move mouse in & out of ellipse.<br>Red mouse dots are inside ellipse, Green outside.</h4>
<canvas id="canvas" width=300 height=300></canvas>
2DRenderingContext 有一个检测点是否在路径中的方法:
CanvasRenderingContext2D.isPointInPath()
您可以将其用于各种路径,而不受几何形式的影响。缺点之一:它只能在绘制时使用,因此您必须在鼠标事件中重绘场景。这对于静态场景可能是不需要的,但如果你有动画,这应该不是问题。
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/isPointInPath
我想知道如何判断鼠标是否在 HTML5 Canvas 上的椭圆上。我需要比边界框检查更精确。
抱歉,这个问题太模糊了。我完全被难住了。
任何帮助将不胜感激。
到目前为止我有这个:
// This is a pretend object. m.x and m.y will have the position of the mouse.
var m = {
x:245,
y:341,
onEnter: function(){}
};
m.onEnter = function () {
console.log('The mouse entered the ellipse!');
};
// The important parts of my ellipse object
var e = {
width:100,
height:50,
x:132,
y:143
};
// This is already working - I use a bounding-box first to increase performance.
if (m.x >= e.x - (e.width/2) && m.x <= e.x + (e.width/2) && m.y >= e.y - (e.height/2) && m.y <= e.y + (e.height/2)) {
if (/* I havn't got the slightest idea what to put here. */) {
m.onEnter();
}
}
对于模糊的初始答案表示歉意,这需要改进,但为了让事情顺利进行...
假定椭圆是平面上围绕两个焦点(F1 和 F2)定义的曲线,使得曲线上每个点到两个焦点的距离之和为常数。
也就是说,对于椭圆上的任意一点P,两个距离F1P + F2P是一个常数。该常数(显然且有帮助)等于所述椭圆的较长(长)轴 A 的长度。
因此,对于这个问题,我怀疑你的椭圆的重要部分不是宽度、高度、x、y,而是它的两个焦点 F1 和 F2(与定义它的椭圆中心等距的 2 个点)和长轴的长度。
然后...对于任何给定的鼠标点击点 M,如果 F1M + F2M < A 的 2 个距离之和,那么您的鼠标点击点在椭圆内。
@pvg 的重复答案是可以的,但是那个重复的答案应该指出他们使用的变量是如何计算的:
// Given cx,cy,a,b defining an ellipse
function isInEllipse(mouseX,mouseY){
var dx=mouseX-cx;
var dy=mouseY-cy;
return ((dx*dx)/(a*a)+(dy*dy)/(b*b)<=1);
}
这是示例代码和演示:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
function reOffset(){
var BB=canvas.getBoundingClientRect();
offsetX=BB.left;
offsetY=BB.top;
}
var offsetX,offsetY;
reOffset();
window.onscroll=function(e){ reOffset(); }
window.onresize=function(e){ reOffset(); }
var PI=Math.PI;
var PI2=PI*2;
var cx=cw/2;
var cy=ch/2;
var a=120;
var b=80;
var points=getPointsOnEllipse(cx,cy,a,b);
$("#canvas").mousemove(function(e){handleMouseMove(e);});
drawEllipse(points);
function dot(x,y,color){
ctx.beginPath();
ctx.arc(x,y,3,0,PI2);
ctx.closePath();
ctx.fillStyle=color;
ctx.fill();
}
function isInEllipse(x,y){
var dx=x-cx;
var dy=y-cy;
return ((dx*dx)/(a*a)+(dy*dy)/(b*b)<=1);
}
function drawEllipse(points){
ctx.beginPath();
ctx.moveTo(points[0].x,points[0].y);
for(var j=0;j<points.length;j++){
ctx.lineTo(points[j].x,points[j].y);
}
ctx.closePath();
ctx.lineWidth=1;
ctx.strokeStyle='forestgreen';
ctx.stroke();
}
function getPointsOnEllipse(cx,cy,a,b){
var startAngle=-PI/2;
var lastX=cx-(a*Math.cos(startAngle));
var lastY=cy+(b*Math.sin(startAngle));
var points=[];
for(var i=0;i<1000;i++){
var angle=startAngle+PI2/1000*i;
var x=cx-(a*Math.cos(angle));
var y=cy+(b*Math.sin(angle));
var dx=x-lastX;
var dy=y-lastY;
var length=parseInt(Math.sqrt(dx*dx+dy*dy));
var eAngle=(Math.atan2(dy,dx)+PI2)%PI2;
if(length>0){
points.push({x:x,y:y,angle:eAngle});
lastX=x;
lastY=y;
}
}
return(points);
}
function handleMouseMove(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
var hit=isInEllipse(mouseX,mouseY);
var color=(hit)?'red':'green';
dot(mouseX,mouseY,color);
}
body{ background-color: ivory; }
#canvas{border:1px solid red; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4>Move mouse in & out of ellipse.<br>Red mouse dots are inside ellipse, Green outside.</h4>
<canvas id="canvas" width=300 height=300></canvas>
2DRenderingContext 有一个检测点是否在路径中的方法:
CanvasRenderingContext2D.isPointInPath()
您可以将其用于各种路径,而不受几何形式的影响。缺点之一:它只能在绘制时使用,因此您必须在鼠标事件中重绘场景。这对于静态场景可能是不需要的,但如果你有动画,这应该不是问题。
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/isPointInPath