In this tutorial I teach a Ton about Canvas and All of the Trigonometry you need to make games and graphics programs while making a real project. I walk you step-by-step through the design of the app. If you want to get good at designing real applications then this tutorial is for you.
All of the code follows the video below to help you learn.
This nearly 40 minute tutorial contains only one 5 second skippable ad. If you think tutorials like this should remain free, please consider turning off Ad Blockers.
Code from the Video
jstut6.js
// Radius of circle
const RADIUS = 200;
// Circle center points
const X_CIRCLE_CENTER = 300;
const Y_CIRCLE_CENTER = 300;
let canvas;
let ctx;
class MousePosition {
constructor(x, y) {
this.x = x,
this.y = y;
}
}
// Holds changing mouse position
let mousePos = new MousePosition(0,0);
// Call for our function to execute when page is loaded
document.addEventListener('DOMContentLoaded', setupCanvas);
function setupCanvas(){
// Get reference to canvas element
canvas = document.getElementById("my-canvas");
// Get methods for manipulating the canvas
ctx = canvas.getContext("2d");
drawCanvas();
// Execute redrawCanvas when the mouse moves
canvas.addEventListener("mousemove", redrawCanvas);
}
function drawCanvas(){
// Create border
drawRectangle("#839192", 5, 0, 0, 600, 600);
// Create circle
drawCircle("#839192", 1, X_CIRCLE_CENTER, Y_CIRCLE_CENTER, RADIUS, 0, 2 * Math.PI);
// Create guide lines
drawLine("#839192", 1, X_CIRCLE_CENTER, 0, X_CIRCLE_CENTER, 600);
drawLine("#839192", 1, 0, Y_CIRCLE_CENTER, 600, Y_CIRCLE_CENTER);
}
function redrawCanvas(evt){
// Clear canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Redraw canvas
drawCanvas();
// Call for MousePosition object to be updated
getMousePosition(evt);
// Draw x & y coordinates using updated MousePosition settings
drawTextAtPoint(ctx, "X : " + mousePos.x, 15, 25);
drawTextAtPoint(ctx, "Y : " + mousePos.y, 15, 45);
// Get angle in degrees and draw text
let angleOfMouseDegrees = getAngleUsingXAndY(mousePos.x, mousePos.y);
drawTextAtPoint(ctx, "Degrees : " + angleOfMouseDegrees, 15, 65);
// Calculates hypotenuse and opposite sides and draws
// them
drawTriangle(angleOfMouseDegrees);
}
function drawRectangle(strokeColor, lineWidth, startX, startY, endX, endY){
ctx.strokeStyle = strokeColor;
ctx.lineWidth = lineWidth;
ctx.strokeRect(startX, startY, endX, endY);
}
function drawCircle(strokeColor, lineWidth, xCircCenter, yCircCenter, radius, arcStart, arcEnd){
ctx.strokeStyle = strokeColor;
ctx.lineWidth = lineWidth;
ctx.beginPath();
ctx.arc(xCircCenter, yCircCenter, radius, arcStart, arcEnd);
ctx.stroke();
}
function drawLine(strokeColor, lineWidth, xStart, yStart, xEnd, yEnd){
// Move to start of line
ctx.moveTo(xStart, yStart);
// Move to end of line
ctx.lineTo(xEnd, yEnd);
// Draw line
ctx.stroke();
}
function drawTextAtPoint(ctx, text, x, y){
ctx.font = "15px Arial";
ctx.fillText(text,x,y);
}
function getMousePosition(evt){
// Get the canvas size and position relative to the web page
let canvasDimensions = canvas.getBoundingClientRect();
// Get canvas x & y position
mousePos.x = Math.floor(evt.clientX - canvasDimensions.left);
mousePos.y = Math.floor(evt.clientY - canvasDimensions.top);
// Convert to coordinate graph
mousePos.x -= 300;
mousePos.y = -1 * (mousePos.y - 300);
return mousePos;
}
// Returns the angle using x and y
// x = Adjacent Side
// y = Opposite Side
// Tan(Angle) = Opposite / Adjacent
// Angle = ArcTan(Opposite / Adjacent)
function getAngleUsingXAndY(x, y){
let adjacent = x;
let opposite = y;
return radiansToDegrees(Math.atan2(opposite, adjacent));
}
function radiansToDegrees(rad){
if(rad < 0){
// Correct the bottom error by adding the negative
// angle to 360 to get the correct result around
// the whole circle
return (360.0 + (rad * (180 / Math.PI))).toFixed(2);
} else {
return (rad * (180 / Math.PI)).toFixed(2);
}
}
function degreesToRadians(degrees){
return degrees * (Math.PI / 180);
}
function drawTriangle(angleDegrees){
// Draw hypotenuse
ctx.moveTo(X_CIRCLE_CENTER, Y_CIRCLE_CENTER);
// Cosine = Adjacent / Hypotenuse so
// xEndPoint = xStartPoint + radius * cos(angle) [angle in radians]
let xEndPoint = X_CIRCLE_CENTER + RADIUS * Math.cos(degreesToRadians(angleDegrees));
// Sine = Opposite / Hypotenuse so
// yEndPoint = yStartPoint + radius * sin(angle) [angle in radians]
let yEndPoint = Y_CIRCLE_CENTER + RADIUS * -(Math.sin(degreesToRadians(angleDegrees)));
drawTextAtPoint(ctx, "Radians : " + degreesToRadians(angleDegrees).toFixed(2), 15, 85);
ctx.lineTo(xEndPoint, yEndPoint);
ctx.stroke();
// Draw Opposite Line
ctx.moveTo(xEndPoint, yEndPoint);
ctx.lineTo(xEndPoint, 300);
ctx.stroke();
// Draw text for x & y
drawTextAtPoint(ctx, "(" + xEndPoint.toFixed(2) + "," + yEndPoint.toFixed(2) + ")", xEndPoint + 10, yEndPoint - 10);
// Calculate the hypotenuse length (Stays Constant)
let hypotenuseLength = getLineLength(X_CIRCLE_CENTER, Y_CIRCLE_CENTER, xEndPoint, yEndPoint);
drawTextAtPoint(ctx, "Hypot L : " + hypotenuseLength.toFixed(2), 15, 105);
// Calculate the opposite length
let oppositeLength = getLineLength(xEndPoint, yEndPoint, xEndPoint, 300);
drawTextAtPoint(ctx, "Opp L : " + oppositeLength.toFixed(2), 15, 125);
}
// Distance = √((x2 - x1)² + (y2 - y1)²)
function getLineLength(x1, y1, x2, y2){
let xS = x2 - x1;
xS = xS * xS;
let yS = y2 - y1;
yS = yS * yS;
return Math.sqrt(xS + yS);
}
Jstut6.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width = device-width, initial-scale = 1">
<title>JavaScript Canvas Trigonometry</title>
<link rel="stylesheet" type="text/css" href="mainstyle.css">
<script src="jstut6.js"></script>
</head>
<body>
<div class="wrapper">
<canvas id="my-canvas" width="600" height="600"></canvas>
</div>
</body>
</html>
mainstyle.css
.wrapper {
max-width: 500px;
margin: auto;
}