Я думаю, что это не лучший способ сделать это, но он должен работать:
const getVectorAngle = ([x1, y1], [x2, y2]) => {
const x = x2 - x1
const y = y2 - y1
return (((Math.acos(y / Math.sqrt(x * x + y * y)) * (Math.sign(x) || 1)) * 180 / Math.PI) + 360) % 360
}
console.log(getVectorAngle([100, 100], [96, 105])) //321.3401
console.log(getVectorAngle([100, 100], [100, 101])) //0
console.log(getVectorAngle([100, 100], [101, 101])) //45
console.log(getVectorAngle([100, 100], [101, 100])) //90
console.log(getVectorAngle([100, 100], [101, 99])) //135
console.log(getVectorAngle([100, 100], [100, 99])) //180
console.log(getVectorAngle([100, 100], [ 99, 99])) //225
console.log(getVectorAngle([100, 100], [ 99, 100])) //270
console.log(getVectorAngle([100, 100], [ 99, 101])) //315
console.log(getVectorAngle([100, 100], [100, 100])) //NaN, start and end values are the same
Вот как это работает:
Visalisation made by Геометрия Geogebra
r - вектор смещения, который задается, и мы ищем α (альфа), угол этого вектора.
const getVectorAngle = ([x1, y1], [x2, y2]) => {
const x = x2 - x1
const y = y2 - y1
return (
(
( //Getting angle by `y = cos(alpha) * r` -> `alpha = cos^-1(y / r)`
Math.acos(
y /
Math.sqrt(x * x + y * y) //Pythagorean theorem to get the length of r, `r^2 = x^2 + y^2` -> `r = sqrt(x^2 + y^2)`
) //= angle in interval [0°; 180°] (in radians)
* ( //Detect the direction of angle by changing its sign
Math.sign(x) //Sign of x, +1 if positive, -1 if negative
|| 1 //Return +1 even if x is 0, to avoid cancelling out 180°
)
) //= angle in interval ]-180°; 180°] (still in radians)
* 180 / Math.PI //Convert angle from radians to degrees
) //= angle in degrees
+ 360 //Add 360° to avoid negative values
) //= angle in interval ]180°; 540°]
% 360 //Modulo by 360° to simplify angles >=360°
//= angle in degrees in interval [0°; 360°[
}