Geocron ist drin

This commit is contained in:
Eskimue
2026-04-02 15:40:06 +02:00
parent 4adb5a6065
commit 1156cb66dc
39 changed files with 3195 additions and 0 deletions
+215
View File
@@ -0,0 +1,215 @@
/**
* earth-core.js – Kern-Framework für die Erd-Visualisierung
* =============================================================
* Stellt Hilfsfunktionen, astronomische Berechnungen und ein
* Event-System bereit, auf das alle Plugins lauschen.
*
* Gefeuerte Events (auf window):
* earth:resize → { detail: { w, h } }
* earth:slow → { detail: { sun, w, h, now } } (~1×/min)
* earth:fast → { detail: { sun, w, h, now } } (~30 fps)
*
* Globales Objekt: window.EarthCore
*/
window.EarthCore = (function () {
// ═══════════════════════════════════════════════════════════════
// KONFIGURATION
// ═══════════════════════════════════════════════════════════════
const CFG = {
// ── Bildpfade ──────────────────────────────────────────────
IMG_DAY_DIR: "../images/planets/earth/day/",
IMG_EXT: ".jpg",
// ── Aktualisierungsintervalle ──────────────────────────────
UPDATE_FAST_MS: 1000, // ~30 fps
UPDATE_SLOW_MS: 60_000, // 1× pro Minute
};
// ═══════════════════════════════════════════════════════════════
// HILFSFUNKTIONEN (öffentlich über EarthCore)
// ═══════════════════════════════════════════════════════════════
const toRad = d => d * Math.PI / 180;
const toDeg = r => r * 180 / Math.PI;
const toX = (lon, w) => ((lon + 180) / 360) * w;
const toY = (lat, h) => ((90 - lat) / 180) * h;
/** Maximales 2:1-Rechteck im Earth-Container */
function calcSize() {
const wrapper = document.getElementById("earth-wrapper");
const W = wrapper?.clientWidth || window.innerWidth;
const H = wrapper?.clientHeight || window.innerHeight;
return W / H >= 2
? { w: H * 2, h: H }
: { w: W, h: W / 2 };
}
/**
* Erstellt einen Plugin-Canvas und hängt ihn in #earth-wrapper.
* @param {string} id – canvas.id
* @param {number} zIndex – CSS z-index
* @param {boolean} [noPointer] – pointerEvents: none (Standard: true)
*/
function createCanvas(id, zIndex, noPointer = true) {
const viewport = document.getElementById("earth-viewport");
if (!viewport) throw new Error("earth-core: #earth-viewport nicht gefunden");
const c = document.createElement("canvas");
c.id = id;
Object.assign(c.style, {
position: "absolute",
top: "0",
left: "0",
display: "block",
zIndex: String(zIndex),
pointerEvents: noPointer ? "none" : "auto",
});
viewport.appendChild(c);
return c;
}
/**
* Synchronisiert Größe eines Canvas auf aktuelle Erdgröße.
* Gibt true zurück wenn Größe gesetzt werden konnte.
*/
function syncCanvas(canvas, w, h) {
if (!w || !h) return false;
const rw = Math.round(w), rh = Math.round(h);
canvas.style.width = rw + "px";
canvas.style.height = rh + "px";
canvas.width = rw;
canvas.height = rh;
return true;
}
/**
* Zeichnet eine abgerundete Rechteck-Path (kein fill/stroke).
* Universell für alle Plugins nutzbar.
*/
function roundRectPath(ctx, x, y, w, h, r) {
const rr = Math.min(r, w / 2, h / 2);
ctx.beginPath();
ctx.moveTo(x + rr, y);
ctx.arcTo(x + w, y, x + w, y + h, rr);
ctx.arcTo(x + w, y + h, x, y + h, rr);
ctx.arcTo(x, y + h, x, y, rr);
ctx.arcTo(x, y, x + w, y, rr);
ctx.closePath();
}
// ═══════════════════════════════════════════════════════════════
// ASTRONOMISCHE BERECHNUNGEN
// ═══════════════════════════════════════════════════════════════
/** Subsolar-Punkt: wo steht die Sonne senkrecht? (Astronomy Engine) */
function subsolarPoint(date) {
try {
const vec = Astronomy.GeoVector(Astronomy.Body.Sun, date, true);
const dist = Math.sqrt(vec.x * vec.x + vec.y * vec.y + vec.z * vec.z);
const dec = toDeg(Math.asin(vec.z / dist));
const ra = toDeg(Math.atan2(vec.y, vec.x));
const gmst = Astronomy.SiderealTime(date) * 15; // Stunden → Grad
const lon = ((ra - gmst + 180) % 360 + 360) % 360 - 180;
return { lat: dec, lon: lon };
} catch (e) {
return { lat: 0, lon: 0 };
}
}
// ═══════════════════════════════════════════════════════════════
// ZUSTAND & EVENT-LOOP
// ═══════════════════════════════════════════════════════════════
let _sun = { lat: 0, lon: 0 };
let _size = { w: 0, h: 0 };
let _resizeRaf = 0;
let _resizeObserver = null;
function _buildDetail(now) {
return { sun: _sun, w: _size.w, h: _size.h, now };
}
function _fireSlow() {
const now = new Date();
_sun = subsolarPoint(now);
window.dispatchEvent(new CustomEvent("earth:slow", { detail: _buildDetail(now) }));
}
function _fireFast() {
window.dispatchEvent(new CustomEvent("earth:fast", { detail: _buildDetail(new Date()) }));
}
function _onResize() {
_size = calcSize();
const viewport = document.getElementById("earth-viewport");
if (viewport) {
viewport.style.width = Math.round(_size.w) + "px";
viewport.style.height = Math.round(_size.h) + "px";
}
window.dispatchEvent(new CustomEvent("earth:resize", { detail: { w: _size.w, h: _size.h } }));
_fireSlow();
_fireFast();
}
function _queueResize() {
if (_resizeRaf) cancelAnimationFrame(_resizeRaf);
_resizeRaf = requestAnimationFrame(() => {
_resizeRaf = 0;
_onResize();
});
}
window.addEventListener("resize", _queueResize);
// ── Start ──────────────────────────────────────────────────────
function _start() {
// Tagbild laden
const img = document.getElementById("earthDay");
if (img) {
const month = new Date().getMonth() + 1;
img.src = `${CFG.IMG_DAY_DIR}${month}${CFG.IMG_EXT}`;
}
_size = calcSize();
const viewport = document.getElementById("earth-viewport");
if (viewport) {
viewport.style.width = Math.round(_size.w) + "px";
viewport.style.height = Math.round(_size.h) + "px";
}
const wrapper = document.getElementById("earth-wrapper");
if (wrapper && typeof ResizeObserver !== "undefined") {
_resizeObserver = new ResizeObserver(() => _queueResize());
_resizeObserver.observe(wrapper);
}
_fireSlow();
_fireFast();
setInterval(_fireFast, CFG.UPDATE_FAST_MS);
setInterval(_fireSlow, CFG.UPDATE_SLOW_MS);
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", _start);
} else {
_start();
}
// ═══════════════════════════════════════════════════════════════
// ÖFFENTLICHE API
// ═══════════════════════════════════════════════════════════════
return {
// Koordinaten-Helfer
toRad, toDeg, toX, toY,
// Canvas-Helfer
createCanvas, syncCanvas, roundRectPath,
// Astronomie
subsolarPoint,
// Größe
calcSize,
// Live-Getter
get sun() { return _sun; },
get size() { return _size; },
};
}());