import { SCHEMATIC_FLOOR_LINE, SCHEMATIC_HEX_PATH, SCHEMATIC_PANEL_LAYOUT, } from "../portal-layout.js"; import "./portal-panel.js"; const SCHEMATIC_STYLES = ` :host { display: none; width: 100%; height: 100%; align-items: center; justify-content: center; padding: 1rem; box-sizing: border-box; background: radial-gradient(ellipse at 50% 45%, #141820 0%, #0a0c12 70%); } :host([visible]) { display: flex; } .hex-stage { position: relative; width: min(88vw, 420px); aspect-ratio: 100 / 118; } .hex-svg { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; } .hex-fill { fill: rgba(0, 0, 0, 0.35); } .hex-stroke { fill: none; stroke: #3a4458; stroke-width: 1.2; } .hex-floor { fill: none; stroke: #2a3044; stroke-width: 0.8; stroke-dasharray: 3 3; } .floor-label { position: absolute; left: 50%; top: 91%; transform: translate(-50%, -50%); font-size: 0.65rem; letter-spacing: 0.14em; text-transform: uppercase; color: #5a6278; font-family: system-ui, sans-serif; pointer-events: none; } .ground { position: absolute; left: 5%; right: 5%; bottom: -2%; height: 2px; background: #3a4050; } .slot { position: absolute; transform: translate(-50%, -50%); z-index: 1; } .slot portal-panel { display: block; transform-origin: center center; box-shadow: 0 0 12px rgba(255, 60, 40, 0.15); } `; export class PortalSchematic extends HTMLElement { constructor() { super(); /** @type {Map} */ this._panels = new Map(); } connectedCallback() { if (this.shadowRoot) return; const root = this.attachShadow({ mode: "open" }); root.innerHTML = `
floor ยท walk through
`; this._slotsEl = root.querySelector(".slots"); } _ensureSlot(position) { let slot = this._slotsEl.querySelector(`[data-position="${position}"]`); if (slot) return slot; const layout = SCHEMATIC_PANEL_LAYOUT[position]; if (!layout) return null; slot = document.createElement("div"); slot.className = "slot"; slot.dataset.position = position; slot.style.left = `${layout.x}%`; slot.style.top = `${layout.y}%`; slot.style.maxWidth = layout.maxW; this._slotsEl.appendChild(slot); return slot; } /** @param {import('../api.js').PanelConfig[]} panels */ setPanels(panels) { if (!this.shadowRoot) this.connectedCallback(); this._panels.clear(); this._slotsEl.querySelectorAll(".slot").forEach((s) => { s.innerHTML = ""; }); for (const panel of panels) { const slot = this._ensureSlot(panel.position); if (!slot) continue; const layout = SCHEMATIC_PANEL_LAYOUT[panel.position]; const el = document.createElement("portal-panel"); el.setAttribute("index", String(panel.index)); el.setAttribute("position", panel.position); el.setAttribute("width", String(panel.width)); el.setAttribute("height", String(panel.height)); el.style.transform = `rotate(${layout.rot}deg)`; slot.appendChild(el); this._panels.set(panel.index, el); } } /** * @param {number} index * @param {number[] | Uint8Array} rgb * @param {number} width * @param {number} height * @param {boolean} identify */ updatePanel(index, rgb, width, height, identify) { const panel = this._panels.get(index); if (!panel) return; if (identify) panel.showIdentify(); else panel.setFrame(rgb, width, height); } set visible(on) { if (on) this.setAttribute("visible", ""); else this.removeAttribute("visible"); } } customElements.define("portal-schematic", PortalSchematic);