Trigonometry in CSS and JavaScript: Beyond Triangles

In the previous article we looked at how to clip an equilateral triangle with trigonometry, but what about some even more interesting geometric shapes?

This article is the 3rd part in a series on Trigonometry in CSS and JavaScript:

  1. Introduction to Trigonometry
  2. Getting Creative with Trigonometric Functions
  3. Beyond Triangles (this article)

Plotting regular polygons

A regular polygon is a polygon with all equal sides and all equal angles. An equilateral triangle is one, so too is a pentagon, hexagon, decagon, and any number of others that meet the criteria. We can use trigonometry to plot the points of a regular polygon by visualizing each set of coordinates as points of a triangle.

Polar coordinates

If we visualize a circle on an x/y axis, draw a line from the center to any point on the outer edge, then connect that point to the horizontal axis, we get a triangle.

A circle centrally positioned on an axis, with a line drawn along the radius to form a triangle

If we repeatedly rotated the line at equal intervals six times around the circle, we could plot the points of a hexagon.

A hexagon, made by drawing lines along the radius of the circle

But how do we get the x and y coordinates for each point? These are known as cartesian coordinates, whereas polar coordinates tell us the distance and angle from a particular point. Essentially, the radius of the circle and the angle of the line. Drawing a line from the center to the edge gives us a triangle where hypotenuse is equal to the circle’s radius.

Showing the triangle made by drawing a line from one of the vertices, with the hypotenuse equal to the radius, and the angle as 2pi divided by 6

We can get the angle in degrees by diving 360 by the number of vertices our polygon has, or in radians by diving 2pi radians. For a hexagon with a radius of 100, the polar coordinates of the uppermost point of the triangle in the diagram would be written (100, 1.0472rad) (r, θ).

An infinite number of points would enable us to plot a circle.

Polar to cartesian coordinates

We need to plot the points of our polygon as cartesian coordinates – their position on the x and y axis.

As we know the radius and the angle, we need to calculate the adjacent side length for the x position, and the opposite side length for the y position.

Showing the triangle superimposed on the hexagon, and the equations needed to calculate the opposite and adjacent sides.

Therefore we need Cosine for the former and Sine for the latter:

adjacent = cos(angle) * hypotenuse
opposite = sin(angle) * hypotenuse

We can write a JS function that returns an array of coordinates:

const plotPoints = (radius, numberOfPoints) => {

	/* step used to place each point at equal distances */
	const angleStep = (Math.PI * 2) / numberOfPoints

	const points = []

	for (let i = 1; i <= numberOfPoints; i++) {
		/* x & y coordinates of the current point */
		const x = Math.cos(i * angleStep) * radius
		const y = Math.sin(i * angleStep) * radius

		/* push the point to the points array */
		points.push({ x, y })
	}
	
	return points
}

We could then convert each array item into a string with the x and y coordinates in pixels, then use the join() method to join them into a string for use in a clip path:

const polygonCoordinates = plotPoints(100, 6).map(({ x, y }) => {
		return `${x}px ${y}px`
	}).join(',')

shape.style.clipPath = `polygon(${polygonCoordinates})`

See the Pen Clip-path polygon by Michelle Barker (@michellebarker) on CodePen.dark

This clips a polygon, but you’ll notice we can only see one quarter of it. The clip path is positioned in the top left corner, with the center of the polygon in the corner. This is because at some points, calculating the cartesian coordinates from the polar coordinates is going to result in negative values. The area we’re clipping is outside of the element’s bounding box.

To position the clip path centrally, we need to add half of the width and height respectively to our calculations:

const xPosition = shape.clientWidth / 2
const yPosition = shape.clientHeight / 2

const x = xPosition + Math.cos(i * angleStep) * radius
const y = yPosition + Math.sin(i * angleStep) * radius

Let’s modify our function:

const plotPoints = (radius, numberOfPoints) => {
	const xPosition = shape.clientWidth / 2
	const yPosition = shape.clientHeight / 2
	const angleStep = (Math.PI * 2) / numberOfPoints
	const points = []

	for (let i = 1; i <= numberOfPoints; i++) {
		const x = xPosition + Math.cos(i * angleStep) * radius
		const y = yPosition + Math.sin(i * angleStep) * radius

		points.push({ x, y })
	}
	
	return points
}

Our clip path is now positioned in the center.

See the Pen Clip-path polygon by Michelle Barker (@michellebarker) on CodePen.dark

Star polygons

The types of polygons we’ve plotted so far are known as convex polygons. We can also plot star polygons by modifying our code in the plotPoints() function ever so slightly. For every other point, we could change the radius value to be 50% of the original value:

/* Set every other point’s radius to be 50% */
const radiusAtPoint = i % 2 === 0 ? radius * 0.5 : radius
		
/* x & y coordinates of the current point */
const x = xPosition + Math.cos(i * angleStep) * radiusAtPoint
const y = yPosition + Math.sin(i * angleStep) * radiusAtPoint

See the Pen Clip-path star polygon by Michelle Barker (@michellebarker) on CodePen.dark

Here’s an interactive example. Try adjusting the values for the number of points and the inner radius to see the different shapes that can be made.

See the Pen Clip-path adjustable polygon by Michelle Barker (@michellebarker) on CodePen.dark

Drawing with the Canvas API

So far we’ve plotted values to use in CSS, but trigonometry has plenty of applications beyond that. For instance, we can plot points in exactly the same way to draw on a <canvas> with Javascript. In this function, we’re using the same function as before (plotPoints()) to create an array of polygon points, then we draw a line from one point to the next:

const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')

const draw = () => {
	/* Create the array of points */
	const points = plotPoints()
	
	/* Move to starting position and plot the path */
	ctx.beginPath()
	ctx.moveTo(points[0].x, points[0].y)
	
	points.forEach(({ x, y }) => {
		ctx.lineTo(x, y)
	})
	
	ctx.closePath()
	
	/* Draw the line */
	ctx.stroke()
}

See the Pen Canvas polygon (simple) by Michelle Barker (@michellebarker) on CodePen.dark

Spirals

We don’t even have to stick with polygons. With some small tweaks to our code, we can even create spiral patterns. We need to change two things here: First of all, a spiral requires multiple rotations around the point, not just one. To get the angle for each step, we can multiply pi by 10 (for example), instead of two, and divide that by the number of points. That will result in five rotations of the spiral (as 10pi divided by two is five).

const angleStep = (Math.PI * 10) / numberOfPoints

Secondly, instead of an equal radius for every point, we’ll need to increase this with every step. We can multiply it by a number of our choosing to determine how far apart the lines of our spiral are rendered:

const multiplier = 2
const radius = i * multiplier
const x = xPosition + Math.cos(i * angleStep) * radius
const y = yPosition + Math.sin(i * angleStep) * radius

Putting it all together, our adjusted function to plot the points is as follows:

const plotPoints = (numberOfPoints) => {
	const angleStep = (Math.PI * 10) / numberOfPoints
	const xPosition = canvas.width / 2
	const yPosition = canvas.height / 2

	const points = []

	for (let i = 1; i <= numberOfPoints; i++) {
		const radius = i * 2 // multiply the radius to get the spiral
		const x = xPosition + Math.cos(i * angleStep) * radius
		const y = yPosition + Math.sin(i * angleStep) * radius

		points.push({ x, y })
	}
	
	return points
}

See the Pen Canvas spiral – simple by Michelle Barker (@michellebarker) on CodePen.dark

At the moment the lines of our spiral are at equal distance from each other, but we could increase the radius exponentially to get a more pleasing spiral. By using the Math.pow() function, we can increase the radius by a larger number for each iteration. By the golden ratio, for example:

const radius = Math.pow(i, 1.618)
const x = xPosition + Math.cos(i * angleStep) * radius
const y = yPosition + Math.sin(i * angleStep) * radius

See the Pen Canvas spiral by Michelle Barker (@michellebarker) on CodePen.dark

Animation

We could also rotate the spiral, using (using requestAnimationFrame). We’ll set a rotation variable to 0, then on every frame increment or decrement it by a small amount. In this case I’m decrementing the rotation, to rotate the spiral anti-clockwise

let rotation = 0

const draw = () => {
	const { width, height } = canvas
	
	/* Create points */
	const points = plotPoints(400, rotation)
	
	/* Clear canvas and redraw */
	ctx.clearRect(0, 0, width, height)
	ctx.fillStyle = '#ffffff'
	ctx.fillRect(0, 0, width, height)
	
	/* Move to beginning position */
	ctx.beginPath()
	ctx.moveTo(points[0].x, points[0].y)
	
	/* Plot lines */
	points.forEach((point, i) => {
		ctx.lineTo(point.x, point.y)
	})
	
	/* Draw the stroke */
	ctx.strokeStyle = '#000000'
	ctx.stroke()
	
	/* Decrement the rotation */
	rotation -= 0.01
	
	window.requestAnimationFrame(draw)
}

draw()

We’ll also need to modify our plotPoints() function to take the rotation value as an argument. We’ll use this to increment the x and y position of each point on every frame:

const x = xPosition + Math.cos(i * angleStep + rotation) * radius
const y = yPosition + Math.sin(i * angleStep + rotation) * radius

This is how our plotPoints() function looks now:

const plotPoints = (numberOfPoints, rotation) => {
	/* 6 rotations of the spiral divided by number of points */
	const angleStep = (Math.PI * 12) / numberOfPoints 
	
	/* Center the spiral */
	const xPosition = canvas.width / 2
	const yPosition = canvas.height / 2

	const points = []

	for (let i = 1; i <= numberOfPoints; i++) {
		const r = Math.pow(i, 1.3)
		const x = xPosition + Math.cos(i * angleStep + rotation) * r
		const y = yPosition + Math.sin(i * angleStep + rotation) * r

		points.push({ x, y, r })
	}
	
	return points
}

See the Pen Canvas spiral by Michelle Barker (@michellebarker) on CodePen.dark

Wrapping up

I hope this series of articles has given you a few ideas for how to get creative with trigonometry and code. I’ll leave you with one more creative example to delve into, using the spiral method detailed above. Instead of plotting points from an array, I’m drawing circles at a new position on each iteration (using requestAnimationFrame).

See the Pen Canvas spiral IIII by Michelle Barker (@michellebarker) on CodePen.dark

Special thanks to George Francis and Liam Egan, whose wonderful creative work inspired me to delve deeper into this topic!

The post Trigonometry in CSS and JavaScript: Beyond Triangles appeared first on Codrops.

Trigonometry in CSS and JavaScript: Getting Creative with Trigonometric Functions

In part 1 we got an overview of trigonometry and learnt how we can use trigonometric functions in Sass. But for dynamic variables, we would be wise to move our calculations into JavaScript. Let’s take a look at an example that’s slightly more complex than clipping a simple triangle.

This article is the 2nd part in a series on “Trigonometry in CSS and JavaScript”:

  1. Introduction to Trigonometry
  2. Getting Creative with Trigonometric Functions (this article)
  3. Beyond Triangles

In the following demo we have a square-based pyramid, built with CSS 3D transforms. Using the slider, we can change the length of the sides of the pyramid, which results in changes to the overall height, and the angle of the sloping sides.

See the Pen Pyramids by Michelle Barker (@michellebarker) on CodePen.dark

To recalculate the angle at which the sides are rotated every time the input value changes, we need trigonometry. In order to do that, we can take a cross-section of the pyramid from the side, and visualize it as a triangle.

We can see that, just like our equilateral triangle in the previous article, the cross-section of our pyramid can be broken up into two right-angled triangles. (This time the shape of the cross-section is an isosceles triangle — a triangle that has two sides of equal length.)

To create the shapes for the base and sides of the pyramid, we can set the width and initial height, and use clip-path to clip the triangular shape of the sides.

.shape__base {
	--w: 10rem;
	
	width: var(--w);
	height: var(--w);
}

.shape__side {
	width: var(--side);
	height: var(--h, 20rem);
	clip-path: polygon(50% 0, 100% 100%, 0 100%);
}

I’m using custom properties here because they allow us to easily reuse identical values. I’m setting a default value for the --h custom property for the height value of the shape side, as we’ll change this value later on with JavaScript. (This is the value we’ll get from the slider.)

Going back to our cross-section diagram, we can see that our known values are the opposite side (which will be half of our --w variable) and the hypotenuse (the --h variable). What is unknown is the angle at which we need to rotate the sides so that they meet in the middle.

If we imagine the side of the pyramid originates from a starting position in the center, the angle we need to calculate is the one at the top of the triangle. We can think of it as being a bit like leaning a ladder against a wall. The angle between the ladder and the wall is the one we need to calculate.

Again, we can use custom properties in our CSS to set some transform values. Each side will have the same rotateX() value (the angle we’re going to calculate), but different rotateY() values, as they’ll be rotated around the pyramid (represented by the --ry custom property here):

.shape__side {
	transform-origin: top center;
	transform: 	
		rotateY(var(--ry, 0)) 
		rotateX(var(--angle, 15deg));	
}

.shape__side:nth-child(2) {
	--ry: 90deg;
}
	
.shape__side:nth-child(3) {
	--ry: -90deg;
}

.shape__side:nth-child(4) {
	--ry: 180deg;
}

Calculating angles

In the previous article we saw how we can calculate the length of any side of a right-angled triangle if we know the angle, but how about calculating the angle itself? For that, we need to rearrange our equations.

We know the opposite side and the hypotenuse, which indicates we need to use the Sine function. Dividing the opposite by the hypotenuse gives us sin(ϴ):

sin(angle) = o / h
Thee trigonometric equations, abbreviated to SOHCAHTOA

Therefore the angle is calculated by the inverse Sine (or Arcsine) of the opposite divided by the hypotenuse:

Math functions

We can use JavaScript math functions for this. Let’s create a function to call whenever the input changes, and update the --h (for the hypotenuse) and --angle custom properties. To get the Arcsine value we use Math.asin():

const shape = document.querySelector('.shape')
const input = document.querySelector('[data-slider]')

const setAngles = () => {
	const o = shape.clientWidth / 2
	const h = input.value
	const angle = Math.asin(o / h)
	
	shape.style.setProperty('--h', `${h}px`)
	shape.style.setProperty('--angle', `${angle}rad`)
}

input.addEventListener('input', setAngles)

Radians versus degrees

You might notice that we’re setting the --angle custom property value in radians, not degrees. Unless you’re a mathematician, there’s a good chance you usually think of angles in terms of degrees, rather than radians. A radian can be visualized as the length of the radius of a circle wrapped around the circumference. There are 2pi radians in a circle.

Diagram illustrating 2pi radians in a circle

The Math.asin() function gives us the angle in radians, and radians are perfectly legitimate units in CSS, so this will work just fine. But if you prefer to set the value in degrees, we can convert them with a simple function:

const radToDeg = (radians) => {
	return radians * (180 / Math.PI)
}

In the demo I’m also rounding the resulting value to two decimal places with toFixed():

const setAngles = () => {
	const o = shape.clientWidth / 2
	const h = input.value
	const radians = Math.asin(o / h)
	const angle = radToDeg(radians).toFixed(2)
	
	shape.style.setProperty('--h', `${h}px`)
	shape.style.setProperty('--angle', `${angle}deg`)
}

Now the angles of the sides of our pyramid will be recalculated every time we move the slider to change the length of the sides.

Get creative

Using the same method, we could even create a bunch of pyramids of random heights, by changing a single custom property:

See the Pen Pyramids by Michelle Barker (@michellebarker) on CodePen.dark

Here’s another creative example of trigonometry in action: A paper snowflake maker, where the user can drag the handles to clip out segments of a triangle to generate the snowflake pattern. The clip path coordinates were calculated using trigonometric functions.

See the Pen Snowflakes with clip-path trigonometry by Michelle Barker (@michellebarker) on CodePen.dark

In the next article we’ll see how trigonometry affords us even more creative possibilities when combined with JS, by enabling us to plot polygons and more complex shapes.

The post Trigonometry in CSS and JavaScript: Getting Creative with Trigonometric Functions appeared first on Codrops.

Trigonometry in CSS and JavaScript: Introduction to Trigonometry

Understanding trigonometry can give us super powers when it comes to creative coding. But to the uninitiated, it can seem a little intimidating. In this 3-part series of articles we’ll get an overview of trigonometry, understand how it can be useful, and delve into some creative applications in CSS and JavaScript.

  1. Introduction to Trigonometry (this article)
  2. Getting Creative with Trigonometric Functions
  3. Beyond Triangles

Trigonometry basics

If, like me, you’ve rarely used trigonometry outside of the classroom, let’s take a trip back to school and get ourselves reacquainted.

Trigonometric functions allow us to calculate unknown values of a right-angled triangle from known parameters. Imagine you’re standing on the ground, looking up at a tall tree. It would be very difficult to measure the height of the tree from the ground. But if we know the angle at which we look up at the top of the tree, and we know the distance from ourselves to the tree, we can infer the height of the tree itself.

Diagram showing a person nearby a tree. The space between them forms a right-angled triangle.

If we imagine this scene as a triangle, the known length (from us to the tree) is known as the adjacent side, the tree is the opposite side (it’s opposite the angle), and the longest side – from us to the top of the tree – is called the hypotenuse.

Diagram of a right-angled triangle, with the names of the sides.

Sine, Cosine and Tangent

There are three main functions to remember in trigonometry: Sine, Cosine and Tangent (abbreviated to sin, cos and tan). They are expressed as the following formulae:

sin(angle) = opposite / hypotenuse
cos(angle) = adjacent / hypotenuse
tan(angle) = opposite / adjacent

The angle is usually written as the Greek theta (θ) symbol.

The three equations, shown as the acronym SOHCAHTOA
The acronym SOHCAHTOA can help us remember the formulae

We can use these equations to calculate the unknown values of our triangle from the known ones. To measure the height of the tree in the example, we know the angle (θ) and the adjacent side.

Showing the adjacent side of the triangle, from the person to the tree

To calculate the opposite side we would need the tangent function. We would need to switch around the formula:

opposite = tan(angle) * adjacent
Triangle with question mark next to opposite side – the unknown side

How do we get tan(θ)? We could use a scientific calculator (type tan and then the angle), or we could use code! Sass and JavaScript both include trigonometric functions, and we’ll look at some ways to use these in this article and the following ones.

Sass functions

If we’re working with predetermined values, we could use the trigonometric functions built into Sass (the CSS preprocessor).

To include the Math module we need the following line in our Sass file:

@use "sass:math";

We can use variables to calculate the opposite side from the angle and adjacent side values.

$angle: 45deg;
$adjacent: 100%;
$opposite: math.tan($angle) * $adjacent;

The tan function in Sass can use radians or degrees — if using degrees, the units must be specified. Without units, radians will be used by default (more on these later).

In the following demo we’re using these in the clip-path property to determine the coordinates of the polygon points, similar to calculating the height of a tree.

See the Pen Using Sass trigonometry for clip-path values by Michelle Barker (@michellebarker) on CodePen.dark

We need to subtract the $opposite variable from the height of the element in order to get the y coordinate — as clip-path coordinates are plotted along the y axis increasing from top to bottom.

.element {
	clip-path: polygon(0 100%, $adjacent (100% - $opposite), $adjacent 100%);
}
Showing the clipped triangle within the square box of the element.

Clipping an equilateral triangle

A right-angled triangle is the simplest use of trigonometry. But we can work out the coordinates of more complex shapes by splitting them up into right-angled triangles.

An equilateral triangle is a triangle with three sides of the same length. Perhaps you remember from school that the angles in a triangle add up to 180º? That means each angle in an equilateral triangle is 60º.

An equilateral triangle. Each angle is 60 degrees

If we draw a line down the middle of an equilateral triangle, we split it into (you guessed it) two right-angled triangles. So, for a triangle with sides of a given length, we know the angle (60º), the length of the hypotenuse, and the length of the adjacent side (half the length of the hypotenuse).

An equilateral triangle split into two right-angled triangles.

What we don’t know is the height of the triangle — once again, the opposite side of the right-angled triangle. To plot the clip-path coordinates, this is what we need to work out. This time, as we know the angle and the length of the hypotenuse, we can use the sine function:

$hypotenuse: 60%; // side length
$angle: 60deg;
$opposite: math.sin($angle) * $hypotenuse;

(It would also be possible for us to use the tangent function instead, as we know that the length of the adjacent side is half of the hypotenuse.) Then we can use those values for our clip-path polygon points:

.element {
	clip-path: polygon(
		0 $opposite,
		($hypotenuse / 2) 0,
		$hypotenuse $opposite
	);
}

See the Pen Clip-path simple equilateral triangles with Sass by Michelle Barker (@michellebarker) on CodePen.dark

As you can see in the demo, the element is clipped from the top left corner. This might not be completely satisfactory: it’s more likely we’d want to clip from the center, especially if we’re clipping an image. We can adjust our clip-path coordinates accordingly. To make this more readable, we can assign some additional variables for the adjacent side length (half the hypotenuse), and the start and end position of the triangle:

$hypotenuse: 60%; //side length
$angle: 60deg;
$opposite: math.sin($angle) * $hypotenuse;
$adjacent: $hypotenuse / 2;
$startPosX: (50% - $adjacent);
$startPosY: (50% - $opposite / 2);
$endPosX: (50% + $adjacent);
$endPosY: (50% + $opposite / 2);

.element {
	clip-path: polygon(
		$startPosX $endPosY,
		50% $startPosY,
		$endPosX $endPosY
	);
}
Triangle centrally positioned

Creating a mixin for reuse

This is quite a bit of complex code to write for a single triangle. Let’s create a Sass mixin, allowing us to clip a triangle of any size on any element we like. As clip-path still needs a prefix in some browsers, our mixin covers that too:

@mixin triangle($sideLength) {
	$hypotenuse: $sideLength;
	
	$angle: 60deg;
	$opposite: math.sin($angle) * $hypotenuse;
	$adjacent: $hypotenuse / 2;
	$startPosX: (50% - $adjacent);
	$startPosY: (50% - $opposite / 2);
	$endPosX: (50% + $adjacent);
	$endPosY: (50% + $opposite / 2);
	
	$clip: polygon(
				$startPosX $endPosY,
				50% $startPosY,
				$endPosX $endPosY
			);
	
	-webkit-clip-path: $clip;
	clip-path: $clip;
}

To clip a centred equilateral triangle from any element, we can simply include the mixin, passing in the length of the triangle’s sides:

.triangle {
	@include triangle(60%);
}

See the Pen Clip-path equilateral triangles with Sass trigonometric functions by Michelle Barker (@michellebarker) on CodePen.dark

Limitations of Sass functions

Our use of Sass functions has some limitations:

  1. It assumes the $sideLength variable is known at compile time, and doesn’t allow for dynamic values.
  2. Sass doesn’t handle mixing units all that well for our needs. In the last demo, if you switch out the percentage-based side length to a fixed length (such as rems or pixels), the code breaks.

The latter is because our calculations for the $startPos and $endPos variables (to position the clip-path centrally) depend on subtracting the side length from a percentage. Unlike in regular CSS (using calc()), Sass doesn’t allow for that. In the final demo, I’ve adjusted the mixin so that it works for any valid length unit, by passing in the size of the clipped element as a parameter. We’d just need to ensure that the values for the two parameters passed in have identical units.

See the Pen Clip-path equilateral triangles with Sass trigonometric functions by Michelle Barker (@michellebarker) on CodePen.dark

CSS trigonometric functions

CSS has a proposal for trigonometric functions as part of the CSS Values and Units Module Level 4 (currently in working draft). These could be extremely useful, especially when used alongside custom properties. Here’s how we could rewrite our CSS to use native CSS trigonometric functions. Changing the size of the clip path is as simple as updating a single custom property:

.triangle {
	--hypotenuse: 8rem;
	--opposite: calc(sin(60deg) * var(--hypotenuse));
	--adjacent: calc(var(--hypotenuse) / 2);
	--startPosX: calc(var(--size) / 2 - var(--adjacent));
	--startPosY: calc(var(--size) / 2 - var(--opposite) / 2);
	--endPosX: calc(var(--size) / 2 + var(--adjacent));
	--endPosY: calc(var(--size) / 2 + var(--opposite) / 2);
	
	--clip: polygon(
				var(--startPosX) var(--endPosX),
				50% var(--startPosY),
				var(--endPosX) var(--endPosY)
			);
			
	-webkit-clip-path: var(--clip);
	clip-path: var(--clip);
}

.triangle:nth-child(2) {
	--hypotenuse: 3rem;
}

.triangle:nth-child(2) {
	--hypotenuse: 50%;
}

Dynamic variables

Custom properties can be dynamic too. We can change them with JS and the values dependant on them will be automatically recalculated.

triangle.style.setProperty('--hypotenuse', '5rem')

CSS trigonometric functions have a lot of potential when they finally land, but sadly they’re not yet supported in any browsers. To use trigonometry with dynamic variables right now, we need JavaScript.

We’ll take a look at some of the possibilities in the next article.

The post Trigonometry in CSS and JavaScript: Introduction to Trigonometry appeared first on Codrops.