JSFiddle - React, Tailwind, and code Playground
HTML
<div class="container">
<div class="block"></div>
<div class="block-container bc1"></div>
</div>
<div class="chaser"></div>
<div class="mouser"></div>
<div class="edger"></div>
<div id="output">
</div>
</div>
CSS
.container {
width: 100px;
height: 150px;
padding: 20px;
margin: 20px auto;
position: relative;
}
.block-container {
width: 40px;
height: 40px;
border: 1px solid gray;
}
.block {
position: absolute;
top: 20px;
left: 50%;
margin-left: -20px;
width: 40px;
height: 40px;
border: 1px solid black;
background-color: blue;
}
.bc1 {
margin: 0 auto;
}
.chaser {
position: absolute;
width: 4px;
height: 4px;
margin-left: -2px;
margin-top: -2px;
background-color: red;
}
.mouser {
position: absolute;
width: 4px;
height: 4px;
margin-left: -2px;
margin-top: -2px;
background-color: blue;
}
.edger {
position: absolute;
width: 10px;
height: 10px;
margin-left: -5px;
margin-top: -5px;
background-color: green;
}
JavaScript
const $ = selector => document.querySelectorAll(selector)[0];
const chaser = $('.chaser');
const mouser = $('.mouser');
const edger = $('.edger');
const block = $('.block');
window.addEventListener('mousemove', (e) => {
const mouse = {
x: e.pageX *1000,
y: e.pageY * 1000,
};
const target = document.body.getBoundingClientRect();
const targetCenter = {
x: Math.floor(target.left + (target.width / 2)),
y: Math.floor(target.top + (target.height / 2)),
};
const angle = Math.atan2(mouse.y - targetCenter.y, mouse.x - targetCenter.x);
const cosAngle = Math.abs(Math.cos(angle));
const sinAngle = Math.abs(Math.sin(angle));
const magnitude = target.width / 2 * sinAngle <= target.height / 2 * cosAngle ?
target.width / 2 / cosAngle :
target.height / 2 / sinAngle;
const targetEdge = {
x: targetCenter.x + Math.cos(angle) * magnitude,
y: targetCenter.y + Math.sin(angle) * magnitude,
};
const viewport = {
width: window.innerWidth,
height: window.innerHeight,
};
const viewPortEdge = {};
const x0 = targetCenter.x;
const y0 = targetCenter.y;
const x2 = viewport.width;
const y2 = viewport.height;
const vx = mouse.x - x0;
const vy = mouse.y - y0;
const ex = vx > 0 ? x2 : 0;
const ey = vy > 0 ? y2 : 0;
if (!vx) {
viewPortEdge.x = 0;
viewPortEdge.y = ey;
} else if (!vy) {
viewPortEdge.x = ex;
viewPortEdge.y = 0;
} else {
const tx = (ex - x0) / vx;
const ty = (ey - y0) / vy;
viewPortEdge.x = tx <= ty ? ex : x0 + ty * vx;
viewPortEdge.y = tx <= ty ? y0 + tx * vy : ey;
}
chaser.style.left = `${targetEdge.x}px`;
chaser.style.top = `${targetEdge.y}px`;
mouser.style.left = `${mouse.x}px`;
mouser.style.top = `${mouse.y}px`;
edger.style.left = `${viewPortEdge.x}px`;
edger.style.top = `${viewPortEdge.y}px`;
document.getElementById('output').innerHTML = `${viewPortEdge.x}x${viewPortEdge.y}`;
console.log(angle)
});