Projections of vector in different frames of reference demo

Demo by Mikołaj Kamiński https://becomeapro.pl/

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.0/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<div class="row">
  <div id="slider"></div>
  <br>
  <span style="color: green">|V| = &radic;<span style="border-top: 1px solid green; font-size: 14px;"> <span id="x1"></span><sup>2</sup> + <span id="y1"></span><sup>2</sup> </span> = <span class="vector"></span></span>
  <br>
  <span style="color: red">|V| = &radic;<span style="border-top: 1px solid red; font-size: 14px;"> <span id="x2"></span><sup>2</sup> + <span id="y2"></span><sup>2</sup> </span> = <span class="vector"></span></span>
</div>

<div class="row">
  <canvas id="canvas" width="280" height="440"></canvas>
</div>
<div class="row">
  <span style="color: black">◼ - Base frame of reference</span>
  <span style="color: gray">◼ - Rotated frame of reference</span>
  <br>
  <span style="color: blue">◼ - Vector</span>
  <span style="color: green">◼ - Vector projection on base frame of reference</span>
  <span style="color: red">◼ - Vector projection on rotated frame of reference</span>
</div>

CSS

div.row {
  width: 80vw;
  margin: auto;
  padding: 10px;
  text-align: center;
}

canvas {
  border: solid 1px;
}

JavaScript

var AXIS_LENGTH = 200;
var MARGIN_TOP = 50;
var MARGIN_LEFT = 220;

var VECTOR_LENGTH = 170;
var VECTOR_ANGLE = 30;

var angle = 0;
var c;
var ctx;

function rad(a) {
  return a * Math.PI / 180;
}

function Draw() {

  ctx.save();

  ctx.setTransform(1, 0, 0, 1, 0, 0);
  ctx.clearRect(0, 0, c.width, c.height);

  ctx.restore();

  var y1 = VECTOR_LENGTH * Math.cos(rad(VECTOR_ANGLE));
  var x1 = VECTOR_LENGTH * Math.sin(rad(VECTOR_ANGLE));
  var y2 = VECTOR_LENGTH * Math.cos(rad(VECTOR_ANGLE - angle));
  var x2 = VECTOR_LENGTH * Math.sin(rad(VECTOR_ANGLE - angle));

  ctx.lineBy(AXIS_LENGTH, 0);
  ctx.lineBy(AXIS_LENGTH, 90);
  ctx.lineBy(VECTOR_LENGTH, VECTOR_ANGLE, "blue");
  ctx.lineBy(y1, 0, "green");
  ctx.lineBy(x1, 90, "green");

  ctx.lineBy(AXIS_LENGTH, angle, "gray");
  ctx.lineBy(AXIS_LENGTH, angle + 90, "gray");

  ctx.lineBy(y2, angle, "red");
  ctx.lineBy(x2, angle + 90, "red");

  $("#x1").html(x1.toFixed(4));
  $("#y1").html(y1.toFixed(4));
  $("#x2").html(x2.toFixed(4));
  $("#y2").html(y2.toFixed(4));

  $(".vector").html(VECTOR_LENGTH);

}

$(document).ready(function() {

  c = document.getElementById("canvas");
  ctx = c.getContext("2d");
  ctx.lineBy = function(length, an, color = "black") {

    var a = an * Math.PI / 180;

    this.rotate(a);

    this.beginPath();

    this.strokeStyle = color;
    this.moveTo(0, 0);
    this.lineTo(0, -length);
    this.stroke();

    this.font = "25px Georgia";
    this.fillStyle = color;
    this.fillText(length > 0 ? "▲" : "▼", -12, -length + (length > 0 ? 16 : 0));

    this.closePath();
    this.rotate(-a);

  }
  ctx.translate(MARGIN_TOP, MARGIN_LEFT);

  Draw();

  $('#slider').slider(

    {

      min: 0,
      max: 90,
      step: 1,

      change: function(event, ui) {
        angle = $('#slider').slider('value');
        Draw();
        console.log("Rotation angle: " + angle);
      }
    }
  );

});