html canvas检查该对象是否处于角度

时间:2018-01-11 20:03:14

标签: javascript html math canvas

我有一个圆圈和一个物体。 我想绘制一个带有指定展开的圆弧段,然后检查对象是否处于定义的角度,如果是,则角度颜色为红色,否则为绿色。但是我的代码在某些情况下不起作用......

在这种情况下它起作用: enter image description here

也是这样的: enter image description here

但这里不是: enter image description here

我知道我的角度检测代码部分并不完美,但我不知道我能做些什么。

这是我的代码:

HTML:

<html>
    <head></head>
    <body>
        <canvas id="c" width="800" height="480" style="background-color: #DDD"></canvas>
        <script src="script.js"></script>
    </body>
</html>

JS:

window.addEventListener('mousemove', updateMousePos, false);
var canvas = document.getElementById("c");
var context = canvas.getContext("2d");

//mouse coordinates
var mx = 0, my = 0;

draw();

function draw()
{
    context.clearRect(0, 0, canvas.width, canvas.height);

    //object coordinates
    var ox = 350, oy = 260;

    context.beginPath();
    context.arc(ox,oy,5,0,2*Math.PI);
    context.fill();

    //circle
    var cx = 400, cy = 280;
    var r = 100;
    var segmentPoints = 20;
    var circlePoints = 40;
    var spread = Math.PI / 2;
    var mouseAngle = Math.atan2(my - cy, mx - cx); //get angle between circle center and mouse position

    context.beginPath();
    context.strokeStyle = "blue";
    context.moveTo(cx + r, cy);

    for(var i=0; i<circlePoints; i++)
    {
        var a = 2 * Math.PI / (circlePoints - 1) * i;
        var x = cx + Math.cos(a) * r;
        var y = cy + Math.sin(a) * r;

        context.lineTo(x, y);
    }

    context.lineTo(cx + r, cy);
    context.stroke();

    var objAngle = Math.atan2(oy - cy, ox - cx);

    var lowerBorder = mouseAngle - spread / 2;
    var biggerBorder = mouseAngle + spread / 2;

    /////////////////////////////////////////////ANGLES DETECTION PART
    if(objAngle >= lowerBorder && objAngle <= biggerBorder ||
       objAngle <= biggerBorder && objAngle >= lowerBorder)
    {
        context.strokeStyle = "red";
    }
    else
        context.strokeStyle = "green";

    context.lineWidth = 3;

    //angle center line
    context.beginPath();
    context.moveTo(cx, cy);
    context.lineTo(cx + Math.cos(mouseAngle) * r * 2, cy + Math.sin(mouseAngle) * r * 2);
    context.stroke();

    //draw spread arc
    context.beginPath();
    context.moveTo(cx, cy);

    for(var i=0; i<segmentPoints; i++)
    {
        var a = mouseAngle - spread / 2 + spread / (segmentPoints - 1) * i; 
        var x = cx + Math.cos(a) * r;
        var y = cy + Math.sin(a) * r;

        context.lineTo(x, y);
    }
    context.lineTo(cx, cy);
    context.stroke();

    //show degrees
    context.font = "20px Arial";
    context.fillText((lowerBorder * 180 / Math.PI).toFixed(2), Math.cos(lowerBorder) * r + cx, Math.sin(lowerBorder) * r + cy);
    context.fillText((biggerBorder * 180 / Math.PI).toFixed(2), Math.cos(biggerBorder) * r + cx, Math.sin(biggerBorder) * r + cy);
    context.fillText((mouseAngle * 180 / Math.PI).toFixed(2), Math.cos(mouseAngle) * r + cx, Math.sin(mouseAngle) * r + cy);

    //update
    setTimeout(function() { draw(); }, 10);
}

//getting mouse coordinates
function updateMousePos(evt) 
{
    var rect = document.getElementById("c").getBoundingClientRect();
    mx = evt.clientX - rect.left;
    my = evt.clientY - rect.top;
}

1 个答案:

答案 0 :(得分:1)

<!doctype html>
<html>
	<head>
		<meta charset="utf-8">
		<style>
			body {
				background-color: black;
			}
			
			canvas {
				position: absolute;
				margin: auto;
				left: 0;
				right: 0;
				border: solid 1px white;
				border-radius: 10px;
			}
		</style>
	</head>
	
	<body>
		<canvas id="canvas"></canvas>
		<script type="application/javascript">
			
			// Rotation here is being measured in Radians
			// Given two 2D vectors A & B, the angle between them can be drawn from this formula
			// A dot B = length(a) * length(b) * cos(angle)
			// if the vectors are normalized (the length is 1) the formula becomes
			// A dot B = cos(angle)
			// angle = acos(a.x * b.x + a.y * b.y)
			// So here you are concerned with the direction of the two vectors
			// One will be the vector facing outward from the middle of your arc segment
			// The other will be a directional vector from the point you want to do collision with to the center
			// of the circle
			
			var canvasWidth = 180;
			var canvasHeight = 160;
			var canvas = null;
			var ctx = null;
			var bounds = {top: 0.0, left: 0.0};
			
			var circle = {
				x: (canvasWidth * 0.5)|0,
				y: (canvasHeight * 0.5)|0,
				radius: 50.0,
				rotation: 0.0, // In Radians
				arcSize: 1.0
			};
			
			var point = {
				x: 0.0,
				y: 0.0
			};
			
			window.onmousemove = function(e) {
				point.x = e.clientX - bounds.left;
				point.y = e.clientY - bounds.top;
			}
			
			// runs after the page has loaded
			window.onload = function() {
				canvas = document.getElementById("canvas");
				canvas.width = canvasWidth;
				canvas.height = canvasHeight;
				bounds = canvas.getBoundingClientRect();
				ctx = canvas.getContext("2d");
				loop();
			}
			
			function loop() {
				// Update Circle Rotation
				circle.rotation = circle.rotation + 0.025;
				if (circle.rotation > 2*Math.PI) { 
					circle.rotation = 0.0;
				}
				
				// Vector A (Point Pos -> Circle Pos)
				var aX = circle.x - point.x;
				var aY = circle.y - point.y;
				var aLength = Math.sqrt(aX * aX + aY * aY);
				
				// Vector B (The direction the middle of the arc is facing away from the circle)
				var bX = Math.sin(circle.rotation);
				var bY =-Math.cos(circle.rotation); // -1 is facing upward, not +1
				var bLength = 1.0;
				
				// Normalize vector A
				aX = aX / aLength;
				aY = aY / aLength;
				
				// Are we inside the arc segment?
				var isInsideRadius = aLength < circle.radius;
				var isInsideAngle = Math.abs(Math.acos(aX * bX + aY * bY)) < circle.arcSize * 0.5;
				var isInsideArc = isInsideRadius && isInsideAngle;
				
				// Clear the screen
				ctx.fillStyle = "gray";
				ctx.fillRect(0,0,canvasWidth,canvasHeight);
				
				// Draw the arc
				ctx.strokeStyle = isInsideArc ? "green" : "black";
				ctx.beginPath();
				ctx.moveTo(circle.x,circle.y);
				ctx.arc(
					circle.x,
					circle.y,
					circle.radius,
					circle.rotation - circle.arcSize * 0.5 + Math.PI * 0.5,
					circle.rotation + circle.arcSize * 0.5 + Math.PI * 0.5,
					false
				);
				ctx.lineTo(circle.x,circle.y);
				ctx.stroke();
				
				// Draw the point
				ctx.strokeStyle = "black";
				ctx.fillStyle = "darkred";
				ctx.beginPath();
				ctx.arc(
					point.x,
					point.y,
					5.0,
					0.0,
					2*Math.PI,
					false
				);
				ctx.fill();
				ctx.stroke();
				
				// This is better to use then setTimeout()
				// It automatically syncs the loop to 60 fps for you
				requestAnimationFrame(loop);
			}
		
		</script>
	</body>
</html>