JSFiddle - React, Tailwind, and code Playground

by Jake Cattrall

HTML

<div class="vector"></div>
<div class="edgePoint"></div>
<div class="position"></div>
<canvas id="myCanvas"></canvas>

CSS

html,
body {
  margin: 0;
  padding: 0;
}

#myCanvas {
  position: absolute;
  top: 0;
  left: 0;
}

.vector {
  width: 14px;
  height: 14px;
  position: absolute;
  margin-left: -7px;
  margin-top: -7px;
  left: 50%;
  top: 50px;
  background-color: lightblue;
}

.edgePoint {
  width: 14px;
  height: 14px;
  margin-left: -7px;
  margin-top: -7px;
  background-color: lightgreen;
  position: absolute;
}
.position {
  color: black;
  padding: 20px;
  font-size: 16px;
}

JavaScript

const $ = selector => document.querySelectorAll(selector)[0];

const position = $('.position');
const edgePoint = $('.edgePoint');
const vector = $('.vector').getBoundingClientRect();
const vectorCenter = {
  x: vector.left + (vector.width / 2),
  y: vector.top + (vector.height / 2)
};

const viewport = {
  width: window.innerWidth,
  height: window.innerHeight,
};
var canvas = document.getElementById("myCanvas");
canvas.width = viewport.width;
canvas.height = viewport.height;
var ctx = canvas.getContext("2d");

window.addEventListener('mousemove', (e) => {
  const mouse = {
    x: e.pageX,
    y: e.pageY,
  };

  const angle = Math.atan2(mouse.y - vectorCenter.y, mouse.x - vectorCenter.x);

  const cosAngle = Math.abs(Math.cos(angle));
  const sinAngle = Math.abs(Math.sin(angle));

  const vx = (viewport.width - vectorCenter.x) * sinAngle;
  const vy = (viewport.height - vectorCenter.y) * cosAngle;

  const vpMagnitude = vx <= vy ?
    (viewport.width - vectorCenter.x) / cosAngle :
    (viewport.height - vectorCenter.y) / sinAngle;

  const viewportX = vectorCenter.x + Math.cos(angle) * vpMagnitude;
  const viewportY = vectorCenter.y + Math.sin(angle) * vpMagnitude;

  const viewPortEdge = {
    x: viewportX,
    y: viewportY,
  };
  
  edgePoint.style.left = viewPortEdge.x + 'px';
  edgePoint.style.top = viewPortEdge.y + 'px';
  
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.beginPath();
	ctx.moveTo(vectorCenter.x,vectorCenter.y);
  ctx.lineTo(viewPortEdge.x, viewPortEdge.y);
	ctx.stroke();
  
  position.innerHTML = `X: ${Math.round(viewPortEdge.x)}<br />Y: ${Math.round(viewPortEdge.y)}`;
  position.style.color = viewPortEdge.y >= 0 ? 'black' : 'red';

});