calculate
Mathematics
Topic: Trigonometry & Functions
Subtopic: Unit Circle & Sine Wave
Level: grade 9 10
Difficulty: intermediate
⏱ 15 mins
Trigonometric Unit Circle & Sine Wave Dynamic Visualizer
Dynamic geometric visualization of trigonometric ratios and sine waves.
Ready / Running
Speed:
sync
Compiling simulation engine...
Unit Circle Foundation
In a circle with radius $r = 1$ centered at $(0,0)$, any point on the circumference has coordinates:
$$(x, y) = (costheta, sintheta)$$
As $theta$ sweeps from $0^circ$ to $360^circ$, the $y$-projection traces the fundamental periodic function $f(theta) = sintheta$.
- Drag the slider to $90^circ$ and verify that $sin(90^circ) = 1$ and $cos(90^circ) = 0$.
- Observe what happens at $180^circ$ and $270^circ$.
- Click Auto Rotate to watch the continuous generation of the waveform.
(function() {
var canvas = document.getElementById('trigCanvas');
if (!canvas) return;
var ctx = canvas.getContext('2d');
var angleDeg = 45;
var isRotating = false;
var slider = document.getElementById('angleSlider');
var autoBtn = document.getElementById('autoRotateBtn');
if (slider) {
slider.oninput = function() {
angleDeg = parseFloat(this.value);
isRotating = false;
if (autoBtn) autoBtn.innerText = '▶ Auto Rotate';
};
}
if (autoBtn) {
autoBtn.onclick = function() {
isRotating = !isRotating;
autoBtn.innerText = isRotating ? '⏸ Pause' : '▶ Auto Rotate';
};
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
var circleX = 140;
var circleY = canvas.height / 2;
var radius = 90;
var rad = (angleDeg * Math.PI) / 180;
var ptX = circleX + radius * Math.cos(rad);
var ptY = circleY - radius * Math.sin(rad);
// Axes
ctx.strokeStyle = '#334155';
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(circleX - 110, circleY); ctx.lineTo(circleX + 110, circleY);
ctx.moveTo(circleX, circleY - 110); ctx.lineTo(circleX, circleY + 110);
ctx.stroke();
// Circle
ctx.beginPath();
ctx.arc(circleX, circleY, radius, 0, 2 * Math.PI);
ctx.strokeStyle = '#475569';
ctx.lineWidth = 2;
ctx.stroke();
// Cosine line (blue, horizontal)
ctx.strokeStyle = '#38bdf8';
ctx.lineWidth = 3;
ctx.beginPath();
ctx.moveTo(circleX, circleY);
ctx.lineTo(ptX, circleY);
ctx.stroke();
// Sine line (rose, vertical)
ctx.strokeStyle = '#f43f5e';
ctx.beginPath();
ctx.moveTo(ptX, circleY);
ctx.lineTo(ptX, ptY);
ctx.stroke();
// Hypotenuse
ctx.strokeStyle = '#e2e8f0';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(circleX, circleY);
ctx.lineTo(ptX, ptY);
ctx.stroke();
// Dot
ctx.fillStyle = '#f43f5e';
ctx.beginPath();
ctx.arc(ptX, ptY, 6, 0, 2 * Math.PI);
ctx.fill();
// Sine wave plot to the right
var waveStartX = 280;
var waveEndX = canvas.width - 20;
// Wave zero-line
ctx.strokeStyle = '#334155';
ctx.beginPath();
ctx.moveTo(waveStartX, circleY); ctx.lineTo(waveEndX, circleY);
ctx.stroke();
// Projection line
ctx.setLineDash([4, 4]);
ctx.strokeStyle = 'rgba(244, 63, 94, 0.4)';
ctx.beginPath();
ctx.moveTo(ptX, ptY);
ctx.lineTo(waveStartX + (angleDeg / 360) * (waveEndX - waveStartX), ptY);
ctx.stroke();
ctx.setLineDash([]);
// Trace wave
ctx.beginPath();
ctx.strokeStyle = '#f43f5e';
ctx.lineWidth = 2.5;
for (var d = 0; d <= 360; d += 2) {
var r = (d * Math.PI) / 180;
var x = waveStartX + (d / 360) * (waveEndX - waveStartX);
var y = circleY - radius * Math.sin(r);
if (d === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y);
}
ctx.stroke();
// Live dot on wave
var waveDotX = waveStartX + (angleDeg / 360) * (waveEndX - waveStartX);
ctx.fillStyle = '#38bdf8';
ctx.beginPath();
ctx.arc(waveDotX, ptY, 5, 0, 2 * Math.PI);
ctx.fill();
// Update Readouts
var s = Math.sin(rad);
var c = Math.cos(rad);
var t = Math.abs(c) < 0.0001 ? 'Undefined' : (s / c).toFixed(3);
document.getElementById('degLabel').innerText = Math.round(angleDeg) + '° (' + rad.toFixed(2) + ' rad)';
document.getElementById('sinVal').innerText = s.toFixed(3);
document.getElementById('cosVal').innerText = c.toFixed(3);
document.getElementById('tanVal').innerText = t;
}
function loop() {
if (isRotating) {
angleDeg = (angleDeg + 1) % 360;
if (slider) slider.value = angleDeg;
}
draw();
requestAnimationFrame(loop);
}
loop();
})();
<div class="trig-sim-wrap">
<div class="trig-canvas-box">
<canvas id="trigCanvas" width="620" height="340"></canvas>
</div>
<div class="trig-controls">
<div class="dial-block">
<label>Angle (θ): <span id="degLabel">45° (0.79 rad)</span></label>
<input type="range" id="angleSlider" min="0" max="360" value="45">
</div>
<div class="trig-readouts">
<div class="val-pill sin"><span>sin(θ)</span> = <strong id="sinVal">0.707</strong></div>
<div class="val-pill cos"><span>cos(θ)</span> = <strong id="cosVal">0.707</strong></div>
<div class="val-pill tan"><span>tan(θ)</span> = <strong id="tanVal">1.000</strong></div>
</div>
<button type="button" id="autoRotateBtn" class="trig-btn">▶ Auto Rotate</button>
</div>
</div>
.trig-sim-wrap { background: #0f172a; padding: 16px; border-radius: 16px; color: #fff; font-family: inherit; display: flex; flex-direction: column; gap: 14px; }
.trig-canvas-box { background: #020617; border-radius: 12px; overflow: hidden; border: 1px solid #1e293b; display: flex; justify-content: center; }
canvas { max-width: 100%; height: auto; }
.trig-controls { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px; background: #1e293b; padding: 12px 18px; border-radius: 12px; }
.dial-block { flex: 1; min-width: 200px; }
.dial-block label { font-size: 11px; font-weight: 800; color: #cbd5e1; display: flex; justify-content: space-between; margin-bottom: 4px; }
.dial-block input { width: 100%; accent-color: #f43f5e; }
.trig-readouts { display: flex; gap: 8px; font-family: monospace; }
.val-pill { background: #0f172a; padding: 6px 10px; border-radius: 6px; font-size: 11px; border: 1px solid #334155; }
.val-pill.sin strong { color: #f43f5e; }
.val-pill.cos strong { color: #38bdf8; }
.val-pill.tan strong { color: #10b981; }
.trig-btn { padding: 8px 14px; border-radius: 6px; background: #f43f5e; color: #fff; border: none; font-weight: 800; font-size: 11px; cursor: pointer; }