191 lines
7.0 KiB
JavaScript
191 lines
7.0 KiB
JavaScript
/**
|
||
* plugin-ui.js – Layer-Steuerung (ein-/ausblenden)
|
||
* ====================================================
|
||
* Abhängigkeit: earth-core.js
|
||
*/
|
||
|
||
(function () {
|
||
|
||
const LAYERS = [
|
||
{ name: "Nacht & Dämmerung", canvasIds: ["nightCanvas", "terminatorCanvas"], defaultOn: true },
|
||
{ name: "Wolken", canvasIds: ["cloudCanvas"], defaultOn: false },
|
||
{ name: "Aurora", canvasIds: ["auroraCanvas"], defaultOn: false },
|
||
{ name: "Satelliten", canvasIds: ["orbitCanvas"], defaultOn: true },
|
||
{ name: "Sonne", canvasIds: ["sunCanvas"], defaultOn: true },
|
||
{ name: "Mond", canvasIds: ["moonCanvas"], defaultOn: true },
|
||
{ name: "Erdbeben", canvasIds: ["earthquakeCanvas"], defaultOn: false },
|
||
{ name: "Ortsmarker", canvasIds: ["markersCanvas"], defaultOn: false },
|
||
];
|
||
|
||
const CFG = {
|
||
TITLE: "Layer",
|
||
ACCENT: "#4a9eff",
|
||
ACCENT_OFF: "rgba(50, 60, 90, 0.9)",
|
||
};
|
||
|
||
// ── pendingVisibility und setVisibility VOR dem UI-Aufbau ──────
|
||
const pendingVisibility = new Map();
|
||
|
||
function setVisibility(layer, on) {
|
||
layer.canvasIds.forEach(id => {
|
||
const el = document.getElementById(id);
|
||
if (el) {
|
||
el.style.display = on ? "block" : "none";
|
||
} else {
|
||
pendingVisibility.set(id, on);
|
||
}
|
||
});
|
||
}
|
||
|
||
const observer = new MutationObserver(mutations => {
|
||
for (const mut of mutations) {
|
||
for (const node of mut.addedNodes) {
|
||
if (node.id && pendingVisibility.has(node.id)) {
|
||
node.style.display = pendingVisibility.get(node.id) ? "block" : "none";
|
||
pendingVisibility.delete(node.id);
|
||
}
|
||
}
|
||
}
|
||
if (pendingVisibility.size === 0) observer.disconnect();
|
||
});
|
||
observer.observe(document.getElementById("earth-wrapper") || document.body, {
|
||
childList: true, subtree: true,
|
||
});
|
||
|
||
// ── CSS ────────────────────────────────────────────────────────
|
||
const style = document.createElement("style");
|
||
style.textContent = `
|
||
#earth-ui {
|
||
position: absolute; bottom: 14px; left: 14px; z-index: 9999;
|
||
background: rgba(6, 10, 22, 0.78);
|
||
border: 1px solid rgba(80, 110, 190, 0.28);
|
||
border-radius: 8px; padding: 7px 10px;
|
||
font: 11px/1.4 system-ui, -apple-system, sans-serif;
|
||
color: rgba(190, 210, 255, 0.88);
|
||
user-select: none; min-width: 140px;
|
||
backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
|
||
box-shadow: 0 2px 16px rgba(0,0,0,0.5);
|
||
opacity: 0.75; transition: opacity 0.2s;
|
||
}
|
||
#earth-ui:hover { opacity: 1; }
|
||
|
||
#earth-ui-header {
|
||
display: flex; align-items: center; justify-content: space-between;
|
||
margin-bottom: 6px; cursor: pointer; gap: 8px;
|
||
}
|
||
#earth-ui-title {
|
||
font-weight: 600; font-size: 10px;
|
||
letter-spacing: 0.1em; text-transform: uppercase;
|
||
color: rgba(140, 170, 255, 0.75);
|
||
}
|
||
#earth-ui-chevron {
|
||
font-size: 8px; color: rgba(100, 120, 180, 0.6);
|
||
transition: transform 0.2s;
|
||
}
|
||
#earth-ui-chevron.collapsed { transform: rotate(-90deg); }
|
||
|
||
#earth-ui-rows {
|
||
display: flex; flex-direction: column; gap: 4px;
|
||
overflow: hidden; max-height: 300px; opacity: 1;
|
||
transition: max-height 0.2s ease, opacity 0.15s;
|
||
}
|
||
#earth-ui-rows.collapsed { max-height: 0; opacity: 0; }
|
||
|
||
.earth-ui-row {
|
||
display: flex; align-items: center;
|
||
justify-content: space-between; gap: 8px;
|
||
}
|
||
.earth-ui-label {
|
||
font-size: 11px; color: rgba(190, 210, 255, 0.85);
|
||
transition: color 0.15s; flex: 1; cursor: pointer;
|
||
}
|
||
.earth-ui-label:hover { color: #fff; }
|
||
.earth-ui-label.off { color: rgba(100, 115, 155, 0.65); }
|
||
|
||
/* Schmaler Toggle: 28×15px */
|
||
.earth-ui-toggle { position: relative; width: 28px; height: 15px; flex-shrink: 0; }
|
||
.earth-ui-toggle input { opacity: 0; width: 0; height: 0; position: absolute; }
|
||
.earth-ui-slider {
|
||
position: absolute; inset: 0; border-radius: 15px;
|
||
background: ${CFG.ACCENT_OFF}; transition: background 0.18s; cursor: pointer;
|
||
}
|
||
.earth-ui-slider::before {
|
||
content: ""; position: absolute;
|
||
width: 10px; height: 10px; left: 2.5px; top: 50%;
|
||
transform: translateY(-50%); border-radius: 50%;
|
||
background: rgba(160, 175, 210, 0.8);
|
||
transition: left 0.18s, background 0.18s;
|
||
}
|
||
.earth-ui-toggle input:checked + .earth-ui-slider { background: ${CFG.ACCENT}; }
|
||
.earth-ui-toggle input:checked + .earth-ui-slider::before {
|
||
left: 15.5px; background: #fff;
|
||
}
|
||
`;
|
||
document.head.appendChild(style);
|
||
|
||
// ── Panel ──────────────────────────────────────────────────────
|
||
const panel = document.createElement("div");
|
||
panel.id = "earth-ui";
|
||
|
||
const header = document.createElement("div");
|
||
header.id = "earth-ui-header";
|
||
header.innerHTML = `
|
||
<span id="earth-ui-title">${CFG.TITLE}</span>
|
||
<span id="earth-ui-chevron">▼</span>
|
||
`;
|
||
panel.appendChild(header);
|
||
|
||
const rows = document.createElement("div");
|
||
rows.id = "earth-ui-rows";
|
||
panel.appendChild(rows);
|
||
|
||
let collapsed = false;
|
||
header.addEventListener("click", () => {
|
||
collapsed = !collapsed;
|
||
rows.classList.toggle("collapsed", collapsed);
|
||
document.getElementById("earth-ui-chevron").classList.toggle("collapsed", collapsed);
|
||
});
|
||
|
||
// ── Rows ───────────────────────────────────────────────────────
|
||
LAYERS.forEach(layer => {
|
||
const row = document.createElement("div");
|
||
row.className = "earth-ui-row";
|
||
|
||
const label = document.createElement("span");
|
||
label.className = "earth-ui-label";
|
||
label.textContent = layer.name;
|
||
|
||
const toggleWrap = document.createElement("label");
|
||
toggleWrap.className = "earth-ui-toggle";
|
||
|
||
const checkbox = document.createElement("input");
|
||
checkbox.type = "checkbox";
|
||
checkbox.checked = layer.defaultOn;
|
||
|
||
const slider = document.createElement("span");
|
||
slider.className = "earth-ui-slider";
|
||
|
||
toggleWrap.appendChild(checkbox);
|
||
toggleWrap.appendChild(slider);
|
||
row.appendChild(label);
|
||
row.appendChild(toggleWrap);
|
||
rows.appendChild(row);
|
||
|
||
setVisibility(layer, layer.defaultOn);
|
||
if (!layer.defaultOn) label.classList.add("off");
|
||
|
||
checkbox.addEventListener("change", () => {
|
||
setVisibility(layer, checkbox.checked);
|
||
label.classList.toggle("off", !checkbox.checked);
|
||
});
|
||
|
||
label.addEventListener("click", () => {
|
||
checkbox.checked = !checkbox.checked;
|
||
checkbox.dispatchEvent(new Event("change"));
|
||
});
|
||
});
|
||
|
||
(document.getElementById("earth-wrapper") || document.body).appendChild(panel);
|
||
|
||
}());
|