Files
skyview.astronomiemuseum.de/public/geocron/plugin-markers.js
T
2026-04-02 15:53:32 +02:00

588 lines
25 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* plugin-markers.js – Ortsmarker auf der Weltkarte
* ====================================================
* Abhängigkeit: earth-core.js
*
* Erstellt: #markersCanvas (z-index 8)
*
* Jeden Marker in der MARKERS-Liste eintragen.
* Unterstützt: Icon-PNG, Fallback-Punkt, Label, Klick-Popup.
*/
(function () {
const userLocation = window.GeocronUserLocation;
const userLocationMarker = userLocation
&& Number.isFinite(Number(userLocation.latitude))
&& Number.isFinite(Number(userLocation.longitude))
? {
name: userLocation.name || "Dein Standort",
lat: Number(userLocation.latitude),
lon: Number(userLocation.longitude),
color: "rgba(255, 215, 90, 0.98)",
glow: "rgba(255, 215, 90, 0.75)",
radius: 6,
showLabel: true,
popup: `${userLocation.name || "Dein Standort"}\n${Number(userLocation.latitude).toFixed(4)}° / ${Number(userLocation.longitude).toFixed(4)}°`
+ (userLocation.elevation !== null && userLocation.elevation !== undefined
? `\n${Number(userLocation.elevation).toFixed(0)} m`
: ""),
}
: null;
// ═══════════════════════════════════════════════════════════════
// MARKER-LISTE – hier eintragen
// ═══════════════════════════════════════════════════════════════
const MARKERS = [
...(userLocationMarker ? [userLocationMarker] : []),
// ═══════════════════════════════════════════════════════════
// EIGENE STANDORTE
// ═══════════════════════════════════════════════════════════
{
name: "Astronomiemuseum",
lat: 50.377222,
lon: 11.189722,
icon: "../images/logoAM.png",
iconW: 67,
iconH: 45,
showLabel: false,
popup: "Astronomiemuseum\nSternwarte Sonneberg",
},
{
name: "Antipode Astronomiemuseum",
lat: -50.377222,
lon: -168.810278,
color: "rgba(255, 100, 180, 0.95)",
radius: 5,
showLabel: true,
popup: "Antipode des Astronomiemuseums\nGenau gegenüber auf der Erde\n50.38°S / 168.81°W\nSüdpazifik – ca. 800 km südöstlich von Neuseeland",
},
// ═══════════════════════════════════════════════════════════
// GEOGRAFISCHE BESONDERHEITEN
// ═══════════════════════════════════════════════════════════
{
name: "Null Island",
lat: 0,
lon: 0,
color: "rgba(255, 255, 100, 0.95)",
radius: 5,
showLabel: true,
popup: "Null Island (0°/0°)\nSchnittpunkt Äquator & Nullmeridian\nHier liegt eine echte GPS-Referenzboje",
},
{
name: "Nullmeridian – Greenwich",
lat: 51.4769,
lon: -0.0005,
color: "rgba(100, 200, 255, 0.95)",
radius: 5,
showLabel: true,
popup: "Royal Observatory Greenwich\nDefiniert seit 1884 den Nullmeridian (0° Länge)\nLondon, England",
},
{
name: "Pol der Unzugänglichkeit",
lat: -48.873,
lon: -123.393,
color: "rgba(200, 100, 255, 0.95)",
radius: 5,
showLabel: true,
popup: "Pol der Unzugänglichkeit (Pazifik)\nAm weitesten von jeder Küste entfernt\n2.688 km bis zur nächsten Landmasse",
},
{
name: "Erdmittelpunkt der Landmasse",
lat: 39.0,
lon: 34.0,
color: "rgba(255, 160, 60, 0.95)",
radius: 5,
showLabel: true,
popup: "Erdmittelpunkt der Landmasse\nGeografisches Zentrum aller Kontinente\nTürkei",
},
{
name: "Magnetischer Nordpol",
lat: 86.5,
lon: -150.0,
color: "rgba(100, 255, 200, 0.95)",
radius: 5,
showLabel: true,
popup: "Magnetischer Nordpol (ca. 2024)\nWandert jährlich ~50 km Richtung Sibirien\nPosition ändert sich kontinuierlich",
},
{
name: "Magnetischer Südpol",
lat: -64.1,
lon: 136.0,
color: "rgba(100, 255, 200, 0.95)",
radius: 5,
showLabel: true,
popup: "Magnetischer Südpol (ca. 2024)\nDerzeit nahe der Küste der Antarktis\nPosition ändert sich kontinuierlich",
},
// ═══════════════════════════════════════════════════════════
// HISTORISCHE OBSERVATORIEN
// ═══════════════════════════════════════════════════════════
{
name: "Sternwarte Paris",
lat: 48.8365,
lon: 2.3363,
color: "rgba(180, 220, 255, 0.95)",
radius: 5,
showLabel: true,
popup: "Observatoire de Paris\nDefinierte bis 1884 den Nullmeridian\nGegründet 1667 – älteste Staatssternwarte",
},
{
name: "Uraniborg",
lat: 55.9,
lon: 12.7,
color: "rgba(180, 220, 255, 0.95)",
radius: 5,
showLabel: true,
popup: "Uraniborg – Tycho Brahes Observatorium\nVen, Dänemark (heute Schweden)\nErbaut 1576 – präziseste vorteleskopische Messungen",
},
{
name: "Jantar Mantar Jaipur",
lat: 26.9245,
lon: 75.8236,
color: "rgba(255, 200, 100, 0.95)",
radius: 5,
showLabel: true,
popup: "Jantar Mantar – Jaipur, Indien\nGrößte steinerne Sonnenuhren der Welt\nErbaut 1724 – UNESCO Weltkulturerbe",
},
{
name: "Göbekli Tepe",
lat: 37.2232,
lon: 38.9224,
color: "rgba(255, 200, 100, 0.95)",
radius: 5,
showLabel: true,
popup: "Göbekli Tepe – Türkei\nÄlteste bekannte astronomische Anlage\nCa. 10.000 v. Chr. – vor Stonehenge & den Pyramiden",
},
// ═══════════════════════════════════════════════════════════
// MODERNE TELESKOPE & OBSERVATORIEN
// ═══════════════════════════════════════════════════════════
{
name: "VLT – Very Large Telescope",
lat: -24.6275,
lon: -70.4044,
color: "rgba(120, 200, 255, 0.95)",
radius: 6,
showLabel: true,
popup: "VLT – Very Large Telescope (ESO)\nCerro Paranal, Atacama-Wüste, Chile\n4 Teleskope à 8,2 m Spiegel\nEins der leistungsfähigsten optischen Observatorien der Welt",
},
{
name: "Mauna Kea",
lat: 19.8228,
lon: -155.4683,
color: "rgba(120, 200, 255, 0.95)",
radius: 6,
showLabel: true,
popup: "Mauna Kea Observatory – Hawaii, USA\nGrößte Teleskopkonzentration der Welt\n4.205 m Höhe – ideale Beobachtungsbedingungen\nHeimat von Keck, Subaru, UKIRT u.v.m.",
},
{
name: "Atacama (ALMA)",
lat: -23.0229,
lon: -67.7540,
color: "rgba(120, 200, 255, 0.95)",
radius: 5,
showLabel: true,
popup: "ALMA – Atacama Large Millimeter Array\nChile, 5.058 m Höhe\n66 Radioteleskop-Antennen\nBeobachtet die kühlsten Objekte des Universums",
},
{
name: "Arecibo (Standort)",
lat: 18.3463,
lon: -66.7528,
color: "rgba(180, 180, 180, 0.85)",
radius: 5,
showLabel: true,
popup: "Arecibo Observatory – Puerto Rico\n305 m Radioteleskop (1963–2020)\nKollabiert im Dez. 2020\nWar 53 Jahre lang das größte Radioteleskop der Welt",
},
{
name: "FAST Radioteleskop",
lat: 25.6531,
lon: 106.8566,
color: "rgba(120, 200, 255, 0.95)",
radius: 5,
showLabel: true,
popup: "FAST – Five-hundred-meter Aperture\nSpherical Telescope, Guizhou, China\n500 m Durchmesser – größtes Radioteleskop der Welt\nIn Betrieb seit 2016",
},
// ═══════════════════════════════════════════════════════════
// METEORITEN & EINSCHLAGKRATER
// ═══════════════════════════════════════════════════════════
{
name: "Chicxulub-Krater",
lat: 21.4,
lon: -89.5,
color: "rgba(255, 80, 50, 0.95)",
radius: 8,
showLabel: true,
popup: "Chicxulub-Krater – Yucatán, Mexiko\n~180 km Durchmesser\nEinschlag vor 66 Mio. Jahren\nAuslöser des Massen­aussterbens der Dinosaurier\nGrößter bekannter Einschlag der Erdgeschichte",
},
{
name: "Vredefort-Krater",
lat: -27.0,
lon: 27.5,
color: "rgba(255, 80, 50, 0.95)",
radius: 7,
showLabel: true,
popup: "Vredefort-Krater – Südafrika\n~300 km Durchmesser (ursprünglich)\nÄltester bekannter Einschlagkrater: vor 2,02 Mrd. Jahren\nUNESCO Weltkulturerbe",
},
{
name: "Sudbury-Krater",
lat: 46.6,
lon: -81.2,
color: "rgba(255, 80, 50, 0.95)",
radius: 7,
showLabel: true,
popup: "Sudbury Basin – Ontario, Kanada\n~130 km Durchmesser\nEinschlag vor 1,85 Mrd. Jahren\nEiner der größten und ältesten Krater\nHeute bedeutende Nickel- und Kupfermine",
},
{
name: "Popigai-Krater",
lat: 71.65,
lon: 111.0,
color: "rgba(255, 80, 50, 0.95)",
radius: 6,
showLabel: true,
popup: "Popigai-Krater – Sibirien, Russland\n~100 km Durchmesser\nEinschlag vor 35,7 Mio. Jahren\nEnthält Billionen Karat Impact-Diamanten\nViertgrößter bekannter Krater",
},
{
name: "Manicouagan-Krater",
lat: 51.37,
lon: -68.7,
color: "rgba(255, 80, 50, 0.95)",
radius: 6,
showLabel: true,
popup: "Manicouagan-Krater – Québec, Kanada\n~100 km Durchmesser\nEinschlag vor 215 Mio. Jahren\nRing-See gut sichtbar auf Satellitenbildern\n'Auge Quebecs'",
},
{
name: "Acraman-Krater",
lat: -32.0,
lon: 135.45,
color: "rgba(255, 80, 50, 0.95)",
radius: 6,
showLabel: true,
popup: "Acraman-Krater – Südaustralien\n~90 km Durchmesser\nEinschlag vor 580 Mio. Jahren\nHeute ein ausgetrockneter Salzsee",
},
{
name: "Tunguska",
lat: 60.917,
lon: 101.95,
color: "rgba(255, 160, 50, 0.95)",
radius: 5,
showLabel: true,
popup: "Tunguska-Ereignis – Sibirien, Russland\n30. Juni 1908\nLuftexplosion eines ~50 m Asteroiden\nStärke ~1.000 Hiroshima-Bomben\n2.000 km² Wald niedergewalzt\nKein Krater – Objekt verglühte in der Atmosphäre",
},
{
name: "Meteor Crater (Barringer)",
lat: 35.0272,
lon: -111.0225,
color: "rgba(255, 80, 50, 0.95)",
radius: 5,
showLabel: true,
popup: "Barringer Meteor Crater – Arizona, USA\n1,2 km Durchmesser, 170 m tief\nEinschlag vor ~50.000 Jahren\nBester erhaltener Einschlagkrater der Erde\nEisenmeteorit, ca. 50 m groß",
},
{
name: "Hoba-Meteorit",
lat: -19.5936,
lon: 17.9347,
color: "rgba(200, 180, 140, 0.95)",
radius: 5,
showLabel: true,
popup: "Hoba-Meteorit – Namibia\nGrößter bekannter Meteorit der Erde\n60 Tonnen, 2,7 × 2,7 m\nEntdeckt 1920 – liegt noch am Fundort\nEisenmeteorit, vor ~80.000 Jahren gefallen",
},
{
name: "Tscheljabinsk",
lat: 55.1644,
lon: 61.4168,
color: "rgba(255, 160, 50, 0.95)",
radius: 5,
showLabel: true,
popup: "Tscheljabinsk-Meteorit – Russland\n15. Februar 2013\n~20 m großer Asteroid\nLuftexplosion in 30 km Höhe\n~1.500 Verletzte durch Druckwelle\nHellster Meteor seit Tunguska",
},
{
name: "Nördlingen (Ries-Krater)",
lat: 48.8566,
lon: 10.6167,
color: "rgba(255, 80, 50, 0.95)",
radius: 5,
showLabel: true,
popup: "Nördlinger Ries – Bayern, Deutschland\n~24 km Durchmesser\nEinschlag vor 14,6 Mio. Jahren\nStadtmauer Nördlingen besteht aus Suevit (Impaktgestein)\nKirche St. Georg enthält ~5.000 Karat Mikro-Diamanten",
},
{
name: "Sikhote-Alin",
lat: 46.1,
lon: 134.7,
color: "rgba(200, 180, 140, 0.95)",
radius: 5,
showLabel: true,
popup: "Sikhote-Alin-Meteorit – Russland\n12. Februar 1947\nEisenmeteorit, ~23 Tonnen (gefundene Fragmente)\nZerbrach in der Atmosphäre in tausende Stücke\nHinterließ ~100 kleine Krater im Primorsky Krai\nGrößter beobachteter Eisenmeteorit-Einschlag",
},
{
name: "Campo del Cielo",
lat: -27.5,
lon: -61.7,
color: "rgba(200, 180, 140, 0.95)",
radius: 5,
showLabel: true,
popup: "Campo del Cielo – Argentinien\nEinschlag vor ca. 4.000–5.000 Jahren\nGruppe von ~26 Kratern auf 60 km²\nBisher ~100 Tonnen Eisenmeteoriten gefunden\nGróncio: 30,8 Tonnen – zweitgrößter Meteorit der Erde",
},
{
name: "Siljan-Krater",
lat: 61.0,
lon: 14.9,
color: "rgba(255, 80, 50, 0.95)",
radius: 5,
showLabel: true,
popup: "Siljan-Krater – Schweden\n~52 km Durchmesser\nEinschlag vor 376 Mio. Jahren\nGrößter Einschlagkrater Europas\nHeute malerische Seenlandschaft",
},
// ═══════════════════════════════════════════════════════════
{
name: "Baikonur",
lat: 45.9200,
lon: 63.3420,
color: "rgba(255, 120, 120, 0.95)",
radius: 5,
showLabel: true,
popup: "Baikonur Kosmodrom – Kasachstan\nÄltester und größter Raumfahrtbahnhof\nErster Satellit (Sputnik 1957)\nErster Mensch im All (Gagarin 1961)",
},
{
name: "Cape Canaveral",
lat: 28.3922,
lon: -80.6077,
color: "rgba(255, 120, 120, 0.95)",
radius: 5,
showLabel: true,
popup: "Kennedy Space Center – Florida, USA\nNASA-Hauptstartplatz seit 1958\nMond-Missionen Apollo, Space Shuttle\nHeute auch SpaceX Falcon & Starship",
},
{
name: "Kourou (ESA)",
lat: 5.2390,
lon: -52.7684,
color: "rgba(255, 120, 120, 0.95)",
radius: 5,
showLabel: true,
popup: "Centre Spatial Guyanais – Kourou\nFranzösisch-Guyana, ESA-Startplatz\nIdeal: nur 5° vom Äquator → Erdrotation spart Treibstoff\nHeimstart von Ariane-Raketen",
},
{
name: "Jiuquan (CNSA)",
lat: 40.9605,
lon: 100.2913,
color: "rgba(255, 120, 120, 0.95)",
radius: 5,
showLabel: true,
popup: "Jiuquan Satellite Launch Center\nGobi-Wüste, China\nErster chinesischer Taikonaut ins All (2003)\nStart der Shenzhou-Missionen",
},
// ═══════════════════════════════════════════════════════════
// POLARLICHT-HOTSPOTS
// ═══════════════════════════════════════════════════════════
{
name: "Tromsø",
lat: 69.6496,
lon: 18.9560,
color: "rgba(80, 255, 160, 0.95)",
radius: 5,
showLabel: true,
popup: "Tromsø – Norwegen\n69°N – mitten im Aurora-Oval\nPolarlicht-Hauptstadt Europas\nBeste Sichtbarkeit: Oktober–März",
},
];
// ═══════════════════════════════════════════════════════════════
// KONFIGURATION – globale Darstellungsoptionen
// ═══════════════════════════════════════════════════════════════
const CFG = {
// ── Fallback-Punkt (wenn kein Icon angegeben) ──────────────
DOT_RADIUS_PX: 5,
DOT_COLOR: "rgba(255, 200, 80, 0.95)",
DOT_BORDER: "rgba(255, 255, 255, 0.6)",
DOT_BORDER_W: 1.2,
DOT_GLOW: "rgba(255, 200, 80, 0.6)",
DOT_GLOW_BLUR: 6,
// ── Label ──────────────────────────────────────────────────
LABEL_FONT: "13px system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif",
LABEL_OFFSET_X: 10,
LABEL_OFFSET_Y: -10,
LABEL_TEXT: "rgba(255, 255, 255, 0.95)",
LABEL_BG: "rgba(0, 0, 0, 0.55)",
LABEL_PAD_X: 6,
LABEL_PAD_Y: 3,
LABEL_RADIUS: 5,
// ── Popup ──────────────────────────────────────────────────
POPUP_BG: "rgba(10, 15, 30, 0.92)",
POPUP_BORDER: "rgba(180, 160, 255, 0.6)",
POPUP_TEXT: "#e8f0ff",
POPUP_FONT: "13px system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif",
};
// ═══════════════════════════════════════════════════════════════
// INTERNER STATE
// ═══════════════════════════════════════════════════════════════
const { toX, toY, createCanvas, syncCanvas, roundRectPath } = EarthCore;
const markersCanvas = createCanvas("markersCanvas", 8, false); // pointerEvents: auto
const ctx = markersCanvas.getContext("2d");
let popup = null; // { x, y, text } oder null
// ── Icons vorladen ────────────────────────────────────────────
const iconCache = new Map(); // marker-index → HTMLImageElement | null
MARKERS.forEach((m, i) => {
if (!m.icon) { iconCache.set(i, null); return; }
const img = new Image();
img.onload = () => { iconCache.set(i, img); draw(EarthCore.size); };
img.onerror = () => { iconCache.set(i, null); };
img.src = m.icon;
});
// ═══════════════════════════════════════════════════════════════
// ZEICHNEN
// ═══════════════════════════════════════════════════════════════
function drawMarker(m, i, w, h) {
const x = toX(m.lon, w);
const y = toY(m.lat, h);
const img = iconCache.get(i);
if (img && img.complete && img.naturalWidth > 0) {
// ── Icon ─────────────────────────────────────────────────
const hw = (m.iconW || 32) / 2;
const hh = (m.iconH || 32) / 2;
ctx.drawImage(img, x - hw, y - hh, m.iconW || 32, m.iconH || 32);
// Wrap an Datumsgrenze
if (x - hw < 0) ctx.drawImage(img, x - hw + w, y - hh, m.iconW || 32, m.iconH || 32);
if (x + hw > w) ctx.drawImage(img, x - hw - w, y - hh, m.iconW || 32, m.iconH || 32);
} else {
// ── Fallback: farbiger Leuchtpunkt ────────────────────────
const r = m.radius ?? CFG.DOT_RADIUS_PX;
const fc = m.color ?? CFG.DOT_COLOR;
ctx.save();
ctx.beginPath();
ctx.arc(x, y, r, 0, Math.PI * 2);
ctx.fillStyle = fc;
ctx.shadowColor = m.glow ?? CFG.DOT_GLOW;
ctx.shadowBlur = CFG.DOT_GLOW_BLUR;
ctx.fill();
ctx.strokeStyle = CFG.DOT_BORDER;
ctx.lineWidth = CFG.DOT_BORDER_W;
ctx.stroke();
ctx.restore();
}
// ── Label ─────────────────────────────────────────────────
if (m.showLabel && m.name) drawLabel(x, y, m.name);
}
function drawLabel(x, y, text) {
ctx.save();
ctx.font = CFG.LABEL_FONT;
ctx.textBaseline = "middle";
ctx.textAlign = "left";
const tx = x + CFG.LABEL_OFFSET_X;
const ty = y + CFG.LABEL_OFFSET_Y;
const boxW = ctx.measureText(text).width + CFG.LABEL_PAD_X * 2;
const boxH = 13 + CFG.LABEL_PAD_Y * 2;
ctx.fillStyle = CFG.LABEL_BG;
roundRectPath(ctx, tx, ty - boxH / 2, boxW, boxH, CFG.LABEL_RADIUS);
ctx.fill();
ctx.fillStyle = CFG.LABEL_TEXT;
ctx.fillText(text, tx + CFG.LABEL_PAD_X, ty);
ctx.restore();
}
function drawPopup({ x, y, text }) {
const lines = text.split("\n");
ctx.save();
ctx.font = CFG.POPUP_FONT;
ctx.textBaseline = "top";
const lh = 18, padX = 10, padY = 8;
const bw = Math.max(...lines.map(l => ctx.measureText(l).width)) + padX * 2;
const bh = lines.length * lh + padY * 2;
const w = markersCanvas.width, h = markersCanvas.height;
let px = x + 12, py = y - bh / 2;
if (px + bw > w - 5) px = x - bw - 12;
if (py < 5) py = 5;
if (py + bh > h - 5) py = h - bh - 5;
roundRectPath(ctx, px, py, bw, bh, 7);
ctx.fillStyle = CFG.POPUP_BG;
ctx.fill();
ctx.strokeStyle = CFG.POPUP_BORDER;
ctx.lineWidth = 1;
ctx.stroke();
ctx.fillStyle = CFG.POPUP_TEXT;
lines.forEach((line, i) => {
if (i === 0) ctx.font = "bold " + CFG.POPUP_FONT;
else ctx.font = CFG.POPUP_FONT;
ctx.fillText(line, px + padX, py + padY + i * lh);
});
ctx.restore();
}
function draw({ w, h }) {
if (!w || !h) return;
syncCanvas(markersCanvas, w, h);
ctx.clearRect(0, 0, w, h);
MARKERS.forEach((m, i) => drawMarker(m, i, w, h));
if (popup) drawPopup(popup);
}
// ═══════════════════════════════════════════════════════════════
// INTERAKTION – Klick öffnet Popup
// ═══════════════════════════════════════════════════════════════
function hitTest(cx, cy) {
const w = markersCanvas.width, h = markersCanvas.height;
for (const m of MARKERS) {
if (!m.popup) continue;
const x = toX(m.lon, w);
const y = toY(m.lat, h);
const hw = (m.iconW ?? CFG.DOT_RADIUS_PX * 2) / 2 + 4;
const hh = (m.iconH ?? CFG.DOT_RADIUS_PX * 2) / 2 + 4;
if (Math.abs(cx - x) <= hw && Math.abs(cy - y) <= hh) return { m, x, y };
}
return null;
}
markersCanvas.addEventListener("click", e => {
const rect = markersCanvas.getBoundingClientRect();
const scaleX = markersCanvas.width / rect.width;
const scaleY = markersCanvas.height / rect.height;
const mx = (e.clientX - rect.left) * scaleX;
const my = (e.clientY - rect.top) * scaleY;
const hit = hitTest(mx, my);
popup = hit ? { x: mx, y: my, text: hit.m.popup } : null;
draw(EarthCore.size);
});
markersCanvas.addEventListener("mousemove", e => {
const rect = markersCanvas.getBoundingClientRect();
const scaleX = markersCanvas.width / rect.width;
const scaleY = markersCanvas.height / rect.height;
const mx = (e.clientX - rect.left) * scaleX;
const my = (e.clientY - rect.top) * scaleY;
markersCanvas.style.cursor = hitTest(mx, my) ? "pointer" : "default";
});
// ═══════════════════════════════════════════════════════════════
// EVENTS
// ═══════════════════════════════════════════════════════════════
window.addEventListener("earth:slow", e => draw(e.detail));
window.addEventListener("earth:resize", e => draw(e.detail));
}());