2024-08-10 23:13:20 +02:00
|
|
|
export class Reticle extends HTMLElement {
|
2024-08-15 20:01:23 +02:00
|
|
|
render(_viewport, _windowSize) {
|
|
|
|
throw new Error("Reticle.render must be overridden");
|
|
|
|
}
|
|
|
|
}
|
2024-08-10 23:13:20 +02:00
|
|
|
|
2024-08-15 20:01:23 +02:00
|
|
|
export class ReticleCursor extends Reticle {
|
2024-08-10 23:13:20 +02:00
|
|
|
#container;
|
|
|
|
|
|
|
|
constructor(nickname) {
|
|
|
|
super();
|
|
|
|
this.nickname = nickname;
|
|
|
|
}
|
|
|
|
|
|
|
|
connectedCallback() {
|
|
|
|
this.style.setProperty("--color", this.getColor());
|
|
|
|
|
|
|
|
this.#container = this.appendChild(document.createElement("div"));
|
|
|
|
this.#container.classList.add("container");
|
2024-08-15 20:01:23 +02:00
|
|
|
|
|
|
|
this.classList.add("cursor");
|
|
|
|
|
|
|
|
let arrow = this.#container.appendChild(document.createElement("div"));
|
|
|
|
arrow.classList.add("arrow");
|
|
|
|
|
|
|
|
let nickname = this.#container.appendChild(document.createElement("div"));
|
|
|
|
nickname.classList.add("nickname");
|
|
|
|
nickname.textContent = this.nickname;
|
2024-08-10 23:13:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
getColor() {
|
2024-08-15 20:01:23 +02:00
|
|
|
let hash = 8803;
|
2024-08-10 23:13:20 +02:00
|
|
|
for (let i = 0; i < this.nickname.length; ++i) {
|
2024-08-15 20:01:23 +02:00
|
|
|
hash = (hash << 5) - hash + this.nickname.charCodeAt(i);
|
|
|
|
hash |= 0;
|
2024-08-10 23:13:20 +02:00
|
|
|
}
|
2024-08-15 20:01:23 +02:00
|
|
|
return `oklch(65% 0.2 ${(hash / 0xffff) * 360}deg)`;
|
2024-08-10 23:13:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
setCursor(x, y) {
|
2024-08-15 20:01:23 +02:00
|
|
|
this.x = x;
|
|
|
|
this.y = y;
|
|
|
|
this.dispatchEvent(new Event(".update"));
|
2024-08-10 23:13:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
render(viewport, windowSize) {
|
2024-08-15 20:01:23 +02:00
|
|
|
let [viewportX, viewportY] = viewport.toScreenSpace(this.x, this.y, windowSize);
|
|
|
|
this.style.transform = `translate(${viewportX}px, ${viewportY}px)`;
|
2024-08-10 23:13:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-15 20:01:23 +02:00
|
|
|
customElements.define("rkgk-reticle-cursor", ReticleCursor);
|
2024-08-10 23:13:20 +02:00
|
|
|
|
|
|
|
export class ReticleRenderer extends HTMLElement {
|
2024-08-15 20:01:23 +02:00
|
|
|
#reticles = new Set();
|
2024-08-10 23:13:20 +02:00
|
|
|
#reticlesDiv;
|
|
|
|
|
|
|
|
connectedCallback() {
|
|
|
|
this.#reticlesDiv = this.appendChild(document.createElement("div"));
|
|
|
|
this.#reticlesDiv.classList.add("reticles");
|
|
|
|
|
2024-08-15 20:01:23 +02:00
|
|
|
this.render();
|
|
|
|
let resizeObserver = new ResizeObserver(() => this.render());
|
2024-08-10 23:13:20 +02:00
|
|
|
resizeObserver.observe(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
connectViewport(viewport) {
|
|
|
|
this.viewport = viewport;
|
2024-08-15 20:01:23 +02:00
|
|
|
this.render();
|
2024-08-10 23:13:20 +02:00
|
|
|
}
|
|
|
|
|
2024-08-15 20:01:23 +02:00
|
|
|
addReticle(reticle) {
|
|
|
|
if (!this.#reticles.has(reticle)) {
|
2024-08-10 23:13:20 +02:00
|
|
|
reticle.addEventListener(".update", () => {
|
|
|
|
if (this.viewport != null) {
|
|
|
|
reticle.render(this.viewport, {
|
|
|
|
width: this.clientWidth,
|
|
|
|
height: this.clientHeight,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
2024-08-15 20:01:23 +02:00
|
|
|
this.#reticles.add(reticle);
|
2024-08-10 23:13:20 +02:00
|
|
|
this.#reticlesDiv.appendChild(reticle);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-15 20:01:23 +02:00
|
|
|
removeReticle(reticle) {
|
|
|
|
if (this.#reticles.has(reticle)) {
|
|
|
|
this.#reticles.delete(reticle);
|
2024-08-10 23:13:20 +02:00
|
|
|
this.#reticlesDiv.removeChild(reticle);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-15 20:01:23 +02:00
|
|
|
render() {
|
2024-08-10 23:13:20 +02:00
|
|
|
if (this.viewport == null) {
|
|
|
|
console.debug("viewport is disconnected, skipping transform update");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let windowSize = { width: this.clientWidth, height: this.clientHeight };
|
2024-08-15 20:01:23 +02:00
|
|
|
for (let reticle of this.#reticles.values()) {
|
2024-08-10 23:13:20 +02:00
|
|
|
reticle.render(this.viewport, windowSize);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
customElements.define("rkgk-reticle-renderer", ReticleRenderer);
|