Trigonometry in JavaScript

In a few previous posts I have used the excellent math.js library which provides a flexible and extensive range of functionality to complement JavaScript's own Math object. This includes a wider selection of trigonometric functions than Math and in this post I will use them to provide a crash course in trigonometry.

Core Concepts

If we have the length of two sides of a right-angled triangle*, or the length of one side and one angle, we can calculate the other lengths and angles. This is known as "solving" the triangle, and is used in areas as diverse as surveying to 3D graphics. The functions involved, particularly the sine, can also be used as the basis for formulas representing cyclical or oscillating behaviour, and is even used in JPEG compression.

* Sometimes called a "right triangle" although there is no such thing as a left triangle or a wrong triangle!

The diagram below shows two right angled triangles, both with one angle of 30°. The sides of the second are all twice as long as the sides of the first, yet the ratios of the lengths of any two sides are the same and will be for any triangle with the same set of angles.

These ratios can easily be calculated for any angle using the trigonometric functions listed below, after which it is trivial to calculate all the sides if we know just one. We can also carry out the process in reverse: if we know the lengths of two sides we can calculate the angles.

In this post I will run through all possible combinations of known angles and sides, solving the triangle for each. I will use the larger of the above triangles but of course any other angles or lengths can be plugged in to the formulas.

Trigonometric Functions

I will cover six trigonometric functions. The first three take angles as input and give us the ratios of the lengths of two sides. The second three are the inverses of the first: they take ratios and give us the corresponding angles.

  • sine (sin) - gives the ratio of the side opposite the angle to the hypotenuse. In our example sin(30) = 0.5, and as you can see the opposite side is 0.5 the length of the hypotenuse.

  • cosine (cos) - gives the ratio of the side adjacent to the angle to the hypotenuse. In our example cos(30) = 0.866, and the adjacent side is 10 * 0.866 = 8.66

  • tangent (tan) - gives the ratio of the sides opposite and adjacent to the angle. Here tan(30) = 0.577, and 8.66 * 0.577 = 5.

  • arcsine (asin) - gives an angle of a triangle from the ratio of the side opposite the angle to the hypotenuse. If that ratio is 0.5 then asin(0.5) = 30°.

  • arccosine (acos) - gives an angle of a triangle from the ratio of the side adjacent to the angle to the hypotenuse. If that ratio is 0.866 then acos(0.866) = 30°.

  • arctangent (atan) - gives an angle of a triangle from the ratio of the side opposite and adjacent to the angle. If that ratio is 0.577 then atan(0.577) = 30°.

A Mnemonic

A common mnemonic for remembering the trigonometric functions is SOH CAH TOA, which you can think of as three words. (OK, it's not very good but it's all we've got.)

SOHSin Opposite Hypotenuse
CAHCos Adjacent Hypotenuse
TOATan Opposite Adjacent

Radians

Both the JavaScript Math object and the math.js library use radians instead of degrees. The diagram below illustrates how radians work.

The three red lines are all the same length. Draw a line from the centre of a circle to the edge, then draw a line the same length round the edge of the circle, and finally a third line back to the centre. The angle where the lines meet at the centre is 1 radian, and is a more natural unit than the arbitrary degree. In many circumstances radians are actually easier to deal with but as most people are more familiar with degrees I will convert to/from radians.

The numbers round the edge show how to do this, and you can see that 180° = 3.14 radians, or to be precise π radians. The conversion factor is therefore 180/π = 57.29577951 (8dp).

(If you see someone suggest 360/2/π or 360/π/2 ignore it. It's just silly.)

The Other Angle

You may be aware that the internal angles of any triangle total 180°, therefore in a right angled triangle for which you know one other angle you just need to subtract that angle plus 90 from 180. This is so trivial I am not sure it can be classed as trigonometry!

Other angle = 180 - 90 - 30 = 60

The Calculations

This table lists various combinations of known sides and angles, together with calculations of other sides or angles from the known values. You could treat it as a sort of "recipe book" by looking down the left column for the combination of values you have, and then referring to the right column to find out how to calculate other values.

KnownCalculated
angle = 30°
opposite = 5
hypotenuse = 5/sin(30) = 10
adjacent = 5/tan(30) = 8.66
angle = 30°
adjacent = 8.66
hypotenuse = 8.66/cos(30) = 10
opposite = 8.66*tan(30) = 5
angle = 30°
hypotenuse = 10
opposite = 10*sin(30) = 5
adjacent = 10*cos(30) = 8.66
opposite = 5
hypotenuse = 10
angle = asin(5/10) = 30°
adjacent = 8.66
hypotenuse = 10
angle = acos(8.66/10) = 30°
opposite = 5
adjacent = 8.66
angle = atan(5/8.66) = 30°

Time to Write Some Code

The source code for this project is very simple, basically just an implementation of the above table in JavaScript. You can download the files as a ZIP or clone the Github repository from the links below.

Source Code Links

ZIP File
GitHub

This is the main JavaScript file.

trigonometrymathsjs.js

window.onload = function()
{
    let hypotenuse = 0;
    let adjacent = 0;
    let opposite = 0;
    let anglerad = 0;

    anglerad = 0.523598775;
    opposite = 5;
    writeToConsole(`angle = ${rad2deg(anglerad)}°<br />`);
    writeToConsole(`opposite = ${opposite}<br />`);
    hypotenuse = opposite / math.sin(anglerad);
    adjacent = opposite / math.tan(anglerad);
    writeToConsole(`hypotenuse = ${opposite}/sin(${rad2deg(anglerad)}) = ${hypotenuse}<br />`);
    writeToConsole(`adjacent = ${opposite}/tan(${rad2deg(anglerad)}) = ${adjacent}<br /><br />`);

    anglerad = 0.523598775;
    adjacent = 8.66;
    writeToConsole(`angle = ${rad2deg(anglerad)}°<br />`);
    writeToConsole(`adjacent = ${adjacent}<br />`);
    hypotenuse = adjacent / math.cos(anglerad);
    opposite = adjacent * math.tan(anglerad);
    writeToConsole(`hypotenuse = ${adjacent}/cos(${rad2deg(anglerad)}) = ${hypotenuse}<br />`);
    writeToConsole(`opposite = ${adjacent}*tan(${rad2deg(anglerad)}) = ${opposite}<br /><br />`);

    anglerad = 0.523598775;
    hypotenuse = 10;
    writeToConsole(`angle = ${rad2deg(anglerad)}°<br />`);
    writeToConsole(`hypotenuse = ${hypotenuse}<br />`);
    opposite = hypotenuse * math.sin(anglerad);
    adjacent = hypotenuse * math.cos(anglerad);
    writeToConsole(`opposite = ${hypotenuse}*sin(${rad2deg(anglerad)}) = ${opposite}<br />`);
    writeToConsole(`adjacent = ${hypotenuse}*cos(${rad2deg(anglerad)}) = ${adjacent}<br /><br />`);

    opposite = 5;
    hypotenuse = 10;
    writeToConsole(`opposite = ${opposite}<br />`);
    writeToConsole(`hypotenuse = ${hypotenuse}<br />`);
    anglerad = math.asin(opposite/hypotenuse);
    writeToConsole(`angle = asin(${opposite}/${hypotenuse}) = ${rad2deg(anglerad)}°<br /><br />`);

    adjacent = 8.66;
    hypotenuse = 10;
    writeToConsole(`adjacent = ${adjacent}<br />`);
    writeToConsole(`hypotenuse = ${hypotenuse}<br />`);
    anglerad = math.acos(adjacent/hypotenuse);
    writeToConsole(`angle = acos(${adjacent}/${hypotenuse}) = ${rad2deg(anglerad)}°<br /><br />`);

    opposite = 5;
    adjacent = 8.66;
    writeToConsole(`opposite = ${opposite}<br />`);
    writeToConsole(`adjacent = ${adjacent}<br />`);
    anglerad = math.atan(opposite/adjacent);
    writeToConsole(`angle = atan(${opposite}/${adjacent}) = ${rad2deg(anglerad)}°<br /><br />`);
}

function deg2rad(degrees)
{
    return degrees / (180 / math.pi);
}

function rad2deg(radians)
{
    return radians * (180 / math.pi);
}

Firstly, note that the HTML file includes the minimized math.min.js file.

After creating four variables for later repeated use I have implemented each of the six rows in the table by setting variables to the known values, then calculating the unknown values. All of these are then printed out.

As mentioned above all calculations are done in radians, but angles are converted to degrees for output using a simple one-line function rad2deg. Also included is a deg2rad function although this is not used here.

Now open trigonometrymathsjs.htm in your browser.

We are using approximations of irrational numbers and JavaScript's implementation of IEEE754 numbers so none of the calculated values are exact. My original intention was to round them off but I then decided to leave them in their raw state. Of course if you were writing a real-world application these would probably scare your users so you would probably want to round them to the nearest integer or to only a few decimal places.

You can use Math.ceil, floor and round to round numbers up, down or to the nearest integer respectively. You can also use toFixed to round a number to a fixed number of decimal places; this is a method of the number type, not Math.