<div id='root' class='my-example'></div>
.my-example {
height: 100vh;
}
.my-example > svg {
display: block;
height: 100%;
width: 100%;
}
const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
class MathUtils {
static clamp(value, min, max) {
return Math.min(Math.max(value, min), max);
}
}
class Example {
#root;
#svg;
#path;
#x;
#y;
#mouseX;
#mouseY;
#frameRequestID;
constructor(root) {
this.#root = root;
this.#init();
this.#initEventListeners();
}
#init() {
this.#svg = document.createElementNS(SVG_NAMESPACE, 'svg');
this.#path = document.createElementNS(SVG_NAMESPACE, 'path');
this.#path.setAttribute('stroke', '#000');
this.#path.setAttribute('fill', 'none');
this.#path.setAttribute('stroke-width', '1');
this.#path.setAttribute('stroke-linejoin', 'round');
this.#path.setAttribute('stroke-linecap', 'round');
this.#svg.appendChild(this.#path);
this.#mouseX = window.innerWidth / 2;
this.#mouseY = window.innerHeight / 2;
this.#x = this.#mouseX;
this.#y = this.#mouseY;
this.#updateSVG();
this.#root.appendChild(this.#svg);
}
#updateSVG() {
const width = window.innerWidth;
const height = window.innerHeight;
const s = Math.min(width, height) / 4;
const dx = this.#x - this.#mouseX;
const dy = this.#y - this.#mouseY;
this.#x -= dx / 100;
this.#y -= dy / 100;
const x = MathUtils.clamp(this.#x, s, width - s);
const y = MathUtils.clamp(this.#y, s, height - s);
this.#svg.setAttribute('viewBox', `0 0 ${width} ${height}`);
this.#path.setAttribute('d', `
M ${x} ${y - s}
L ${x + s} ${y + s}
L ${x - s} ${y + s}
L ${x} ${y - s}
L ${width} 0
L ${x + s / 2} ${y}
L ${width} ${height / 2}
L ${x + s} ${y + s}
L ${width} ${height}
M ${x + s} ${y + s}
L ${width * (2 / 3)} ${height}
L ${x} ${y + s}
L ${width / 3} ${height}
L ${x - s} ${y + s}
M 0 ${height}
L ${x - s} ${y + s}
L 0 ${height / 2}
L ${x - s / 2} ${y}
L 0 0
L ${x} ${y - s}
`);
}
#initEventListeners() {
window.addEventListener('resize', this.#onWindowResize.bind(this));
document.addEventListener('mousemove', this.#onMouseMove.bind(this));
this.#root.addEventListener('mouseleave', this.#onMouseLeave.bind(this));
}
#onWindowResize() {
this.#updateSVG();
}
#onMouseMove(e) {
this.#mouseX = e.clientX;
this.#mouseY = e.clientY;
}
#onMouseLeave() {
this.#mouseX = window.innerWidth / 2;
this.#mouseY = window.innerHeight / 2;
}
start() {
this.#updateSVG();
this.#frameRequestID = requestAnimationFrame(this.start.bind(this));
}
stop() {
cancelAnimationFrame(this.#frameRequestID);
}
}
function main() {
const root = document.getElementById('root');
const example = new Example(root);
example.start();
}
document.addEventListener('DOMContentLoaded', main);
View Compiled
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.