I am using an HTML canvas to draw details on an image.
One of the details I am trying to draw is the direction of the North Pole, provided as an angle between 0-360 degrees. I want to paint a little sign somewhere along the side of the image pointing towards north.
I want to convert the angle into a point on the sides of the rectangular image whereby
- 0 degrees is at coordinates { x: width / 2, y: 0 }
- 90 degrees is at coordinates { x: width , y: height / 2 }
- 180 degrees is at coordinates { x: width / 2, y: height }
- 270 degrees is at coordinates { x: 0 , y: height / 2 }
After many attempts I came up with a function that works almost as intended. I draw a 'ray' from the center of the rectangle to a point on the side of the rectangle with the angle provided. I can then calculate the slope and use that to get the position of the missing x or y value.
The function does not work as intended, mostly when it comes to angles that are closer to the corners. I suspect (but remember too little from school geometry) that it has something to do with the radian.
interface Point {
x: number;
y: number;
}
interface Line {
point1: Point;
point2: Point;
}
function calcSlope(line: Line): number {
return (line.point1.y - line.point2.y) / (line.point1.x - line.point2.x);
}
/**
* takes an angle in degree and rectangle dimensions returning point on rectangle's outline representing angle
*/
function convertAngleToPoint(
width: number,
height: number,
angle = 360
): Point | null {
// Calculate the midpoint of the rectangle
const centerX = width / 2;
const centerY = height / 2;
// Calculate the endpoint of the line from the midpoint to (width/2, 0)
const endX = width / 2;
const endY = 0;
// Calculate the angle in radians
const angleInRadians = (angle * Math.PI) / 180;
// Calculate the coordinates of the ray
const targetX =
Math.cos(angleInRadians) * (endX - centerX) -
Math.sin(angleInRadians) * (endY - centerY) +
centerX;
const targetY =
Math.sin(angleInRadians) * (endX - centerX) +
Math.cos(angleInRadians) * (endY - centerY) +
centerY;
const slope = calcSlope({
point1: { x: centerX, y: centerY },
point2: { x: targetX, y: targetY },
});
if (angle === 0) {
return { x: width / 2, y: 0 };
}
if (angle < 45) {
// label on top
const x = targetX + targetY / slope;
return { x, y: 0 };
}
if (angle < 135) {
// label right
const y = targetY + (width - targetX) * slope;
return { x: width, y };
}
if (angle < 225) {
// label bottom
const x = targetX + (height - targetY) / -slope;
return { x, y: height };
}
if (angle < 315) {
// label left
const y = targetY + (0 - targetX) * -slope;
return { x: 0, y };
}
if (angle < 361) {
// label on top
const x = targetX + targetY / slope;
return { x, y: 0 };
}
return null;
}