Compare commits
3
Commits
2bf2848905
...
027651c67e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
027651c67e | ||
|
|
bee9bd1ef4 | ||
|
|
2bf6c504b5 |
@@ -4848,6 +4848,13 @@ body.solarsystem-page:not(.jupitersystem-page) .solarsystem-stage-wrap {
|
|||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.eclipse-info-scale-note {
|
||||||
|
margin-top: 0.8rem;
|
||||||
|
font-size: 0.74rem;
|
||||||
|
line-height: 1.45;
|
||||||
|
color: var(--text-dim);
|
||||||
|
}
|
||||||
|
|
||||||
/* Info panel: ein-/ausklappbar */
|
/* Info panel: ein-/ausklappbar */
|
||||||
.eclipse-info-panel {
|
.eclipse-info-panel {
|
||||||
padding-top: 2.4rem;
|
padding-top: 2.4rem;
|
||||||
@@ -4892,6 +4899,41 @@ body.solarsystem-page:not(.jupitersystem-page) .solarsystem-stage-wrap {
|
|||||||
padding: 0.55rem 0.6rem;
|
padding: 0.55rem 0.6rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sr-only {
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
padding: 0;
|
||||||
|
margin: -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
clip: rect(0, 0, 0, 0);
|
||||||
|
white-space: nowrap;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eclipse-stage-time {
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
bottom: calc(5.4rem + 15px);
|
||||||
|
transform: translateX(-50%);
|
||||||
|
z-index: 9;
|
||||||
|
padding: 0.45rem 0.8rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
border: 1px solid rgba(201, 168, 76, 0.18);
|
||||||
|
background: rgba(5, 9, 18, 0.82);
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
|
color: var(--gold-pale);
|
||||||
|
font-size: 0.88rem;
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
box-shadow: 0 10px 24px rgba(0, 0, 0, 0.28);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eclipse-stage-time-solar {
|
||||||
|
bottom: calc(5.4rem - 5px);
|
||||||
|
}
|
||||||
|
|
||||||
/* View toggle */
|
/* View toggle */
|
||||||
.eclipse-view-toggle {
|
.eclipse-view-toggle {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -5003,6 +5045,23 @@ body.solarsystem-page:not(.jupitersystem-page) .solarsystem-stage-wrap {
|
|||||||
.eclipse-tl-max .eclipse-tl-label { color: var(--gold); }
|
.eclipse-tl-max .eclipse-tl-label { color: var(--gold); }
|
||||||
.eclipse-tl-tot .eclipse-tl-label { color: #f05530; }
|
.eclipse-tl-tot .eclipse-tl-label { color: #f05530; }
|
||||||
|
|
||||||
|
.eclipse-sidebar-controls {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.7rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eclipse-sidebar-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eclipse-speed-label-sidebar {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.3rem;
|
||||||
|
justify-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
.eclipse-timeline-controls {
|
.eclipse-timeline-controls {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
+135
-22
@@ -42,8 +42,42 @@ $userLon = isset($currentLocation['longitude']) ? (float)$currentLocation['longi
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="solarsystem-sidebar-block">
|
||||||
|
<div class="solarsystem-label">Steuerung</div>
|
||||||
|
<div class="eclipse-sidebar-controls">
|
||||||
|
<div class="eclipse-sidebar-buttons">
|
||||||
|
<button class="btn btn-sm btn-secondary" id="eclipseBtnRewind" title="Zum Anfang">⏮</button>
|
||||||
|
<button class="btn btn-sm btn-primary" id="eclipseBtnPlay" title="Play/Pause">▶ Play</button>
|
||||||
|
<button class="btn btn-sm btn-secondary" id="eclipseBtnEnd" title="Zum Ende">⏭</button>
|
||||||
|
</div>
|
||||||
|
<div class="eclipse-time-display" id="eclipseTimeDisplay">– – : – – UTC</div>
|
||||||
|
<label class="eclipse-speed-label eclipse-speed-label-sidebar">
|
||||||
|
<span class="solarsystem-label">Geschw.</span>
|
||||||
|
<select id="eclipseSpeedSel" class="eclipse-speed-sel">
|
||||||
|
<option value="1">×1</option>
|
||||||
|
<option value="3">×3</option>
|
||||||
|
<option value="10" selected>×10</option>
|
||||||
|
<option value="30">×30</option>
|
||||||
|
<option value="60">×60</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="solarsystem-sidebar-block">
|
||||||
|
<div class="solarsystem-label">Zeitformat</div>
|
||||||
|
<label class="form-checkbox" for="eclipseUseLocalTime">
|
||||||
|
<input type="checkbox" id="eclipseUseLocalTime">
|
||||||
|
<span>Lokale Zeit statt UTC anzeigen</span>
|
||||||
|
</label>
|
||||||
|
<label class="form-checkbox" for="eclipseShowStageTime">
|
||||||
|
<input type="checkbox" id="eclipseShowStageTime">
|
||||||
|
<span>Uhrzeit mittig in der Grafik anzeigen</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="solarsystem-sidebar-block is-hidden" id="eclipseDataBlock">
|
<div class="solarsystem-sidebar-block is-hidden" id="eclipseDataBlock">
|
||||||
<div class="solarsystem-label">Kontaktzeiten (UTC)</div>
|
<div class="solarsystem-label">Kontaktzeiten (<span id="eclipseTimeZoneLabel">UTC</span>)</div>
|
||||||
<table class="data-table" id="eclipseContactTable"></table>
|
<table class="data-table" id="eclipseContactTable"></table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -64,30 +98,40 @@ $userLon = isset($currentLocation['longitude']) ? (float)$currentLocation['longi
|
|||||||
<!-- 2D Moon canvas -->
|
<!-- 2D Moon canvas -->
|
||||||
<canvas id="eclipseMoonCanvas" class="eclipse-canvas is-hidden"></canvas>
|
<canvas id="eclipseMoonCanvas" class="eclipse-canvas is-hidden"></canvas>
|
||||||
|
|
||||||
|
|
||||||
<!-- Scale notice -->
|
|
||||||
<div id="eclipseScaleNote" class="eclipse-scale-note">
|
|
||||||
Abstände nicht maßstabsgetreu<br>(Mond real ~60× weiter entfernt)
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Info overlay -->
|
<!-- Info overlay -->
|
||||||
<div class="solarsystem-info-panel" id="eclipseInfoPanel">
|
<div class="solarsystem-info-panel eclipse-info-panel" id="eclipseInfoPanel">
|
||||||
<div class="eclipse-info-empty">Wähle eine Finsternis aus der Liste</div>
|
<button
|
||||||
|
type="button"
|
||||||
|
class="eclipse-info-toggle"
|
||||||
|
id="eclipseInfoToggle"
|
||||||
|
aria-expanded="true"
|
||||||
|
aria-controls="eclipseInfoBody"
|
||||||
|
title="Infokasten ein- oder ausklappen"
|
||||||
|
>
|
||||||
|
<span class="eclipse-info-toggle-icon" aria-hidden="true">▾</span>
|
||||||
|
<span class="sr-only">Infokasten ein- oder ausklappen</span>
|
||||||
|
</button>
|
||||||
|
<div class="eclipse-info-body" id="eclipseInfoBody">
|
||||||
|
<div class="eclipse-info-empty">Wähle eine Finsternis aus der Liste</div>
|
||||||
|
<div class="eclipse-info-scale-note">Abstände nicht maßstabsgetreu, Mond real etwa 60× weiter entfernt</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="eclipse-stage-time is-hidden" id="eclipseStageTime">– – : – – UTC</div>
|
||||||
|
|
||||||
<!-- Timeline -->
|
<!-- Timeline -->
|
||||||
<div class="eclipse-timeline" id="eclipseTimeline">
|
<div class="eclipse-timeline" id="eclipseTimeline">
|
||||||
<div class="eclipse-timeline-bar" id="eclipseTimelineBar">
|
<div class="eclipse-timeline-bar" id="eclipseTimelineBar">
|
||||||
<div class="eclipse-tl-cursor" id="eclipseTimelineCursor"></div>
|
<div class="eclipse-tl-cursor" id="eclipseTimelineCursor"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="eclipse-timeline-controls">
|
<div class="eclipse-timeline-controls is-hidden" aria-hidden="true">
|
||||||
<button class="btn btn-sm btn-secondary" id="eclipseBtnRewind" title="Zum Anfang">⏮</button>
|
<button class="btn btn-sm btn-secondary" id="eclipseBtnRewindLegacy" title="Zum Anfang">⏮</button>
|
||||||
<button class="btn btn-sm btn-primary" id="eclipseBtnPlay" title="Play/Pause">▶ Play</button>
|
<button class="btn btn-sm btn-primary" id="eclipseBtnPlayLegacy" title="Play/Pause">▶ Play</button>
|
||||||
<button class="btn btn-sm btn-secondary" id="eclipseBtnEnd" title="Zum Ende">⏭</button>
|
<button class="btn btn-sm btn-secondary" id="eclipseBtnEndLegacy" title="Zum Ende">⏭</button>
|
||||||
<span class="eclipse-time-display" id="eclipseTimeDisplay">– – : – – UTC</span>
|
<span class="eclipse-time-display" id="eclipseTimeDisplayLegacy">– – : – – UTC</span>
|
||||||
<label class="eclipse-speed-label">
|
<label class="eclipse-speed-label">
|
||||||
<span class="solarsystem-label">Geschw.</span>
|
<span class="solarsystem-label">Geschw.</span>
|
||||||
<select id="eclipseSpeedSel" class="eclipse-speed-sel">
|
<select id="eclipseSpeedSelLegacy" class="eclipse-speed-sel">
|
||||||
<option value="1">×1</option>
|
<option value="1">×1</option>
|
||||||
<option value="3">×3</option>
|
<option value="3">×3</option>
|
||||||
<option value="10" selected>×10</option>
|
<option value="10" selected>×10</option>
|
||||||
@@ -140,9 +184,14 @@ const canvas3d = document.getElementById('eclipseCanvas');
|
|||||||
const canvas2d = document.getElementById('eclipseMoonCanvas');
|
const canvas2d = document.getElementById('eclipseMoonCanvas');
|
||||||
const stageWrap = document.getElementById('eclipseStageWrap');
|
const stageWrap = document.getElementById('eclipseStageWrap');
|
||||||
const infoPanel = document.getElementById('eclipseInfoPanel');
|
const infoPanel = document.getElementById('eclipseInfoPanel');
|
||||||
|
const infoToggle = document.getElementById('eclipseInfoToggle');
|
||||||
const timelineBar = document.getElementById('eclipseTimelineBar');
|
const timelineBar = document.getElementById('eclipseTimelineBar');
|
||||||
const tlCursor = document.getElementById('eclipseTimelineCursor');
|
const tlCursor = document.getElementById('eclipseTimelineCursor');
|
||||||
const tlDisplay = document.getElementById('eclipseTimeDisplay');
|
const tlDisplay = document.getElementById('eclipseTimeDisplay');
|
||||||
|
const useLocalTimeEl = document.getElementById('eclipseUseLocalTime');
|
||||||
|
const showStageTimeEl = document.getElementById('eclipseShowStageTime');
|
||||||
|
const timeZoneLabelEl = document.getElementById('eclipseTimeZoneLabel');
|
||||||
|
const stageTimeEl = document.getElementById('eclipseStageTime');
|
||||||
const eclipseListEl = document.getElementById('eclipseList');
|
const eclipseListEl = document.getElementById('eclipseList');
|
||||||
const dataBlock = document.getElementById('eclipseDataBlock');
|
const dataBlock = document.getElementById('eclipseDataBlock');
|
||||||
const contactTable = document.getElementById('eclipseContactTable');
|
const contactTable = document.getElementById('eclipseContactTable');
|
||||||
@@ -161,6 +210,9 @@ let playing = false;
|
|||||||
let playSpeed = 10; // minutes / real second
|
let playSpeed = 10; // minutes / real second
|
||||||
let lastRAF = 0;
|
let lastRAF = 0;
|
||||||
let viewMode = 'geo';
|
let viewMode = 'geo';
|
||||||
|
let infoPanelCollapsed = false;
|
||||||
|
let useLocalTime = false;
|
||||||
|
let showStageTime = false;
|
||||||
|
|
||||||
// Eclipse geometry (computed per eclipse)
|
// Eclipse geometry (computed per eclipse)
|
||||||
let eclB = 0; // impact parameter (vis-units)
|
let eclB = 0; // impact parameter (vis-units)
|
||||||
@@ -603,7 +655,7 @@ function updateSim() {
|
|||||||
// ── Time display ────────────────────────────────
|
// ── Time display ────────────────────────────────
|
||||||
const peakMs = currentEclipse.peak.date.getTime();
|
const peakMs = currentEclipse.peak.date.getTime();
|
||||||
const cur = new Date(peakMs + simTime * 60000);
|
const cur = new Date(peakMs + simTime * 60000);
|
||||||
tlDisplay.textContent = cur.toISOString().slice(11, 16) + ' UTC';
|
tlDisplay.textContent = formatTime(cur, { withSeconds: false });
|
||||||
|
|
||||||
// ── 2D moon view ────────────────────────────────
|
// ── 2D moon view ────────────────────────────────
|
||||||
if (viewMode === 'moon') drawMoonView(mp, sdw);
|
if (viewMode === 'moon') drawMoonView(mp, sdw);
|
||||||
@@ -775,15 +827,49 @@ function phaseName(t) {
|
|||||||
return t < 0 ? 'VOR DER FINSTERNIS' : 'NACH DER FINSTERNIS';
|
return t < 0 ? 'VOR DER FINSTERNIS' : 'NACH DER FINSTERNIS';
|
||||||
}
|
}
|
||||||
|
|
||||||
function fmtUTC(peakDate, offsetMin) {
|
function timeZoneSuffix() {
|
||||||
return new Date(peakDate.getTime() + offsetMin * 60000).toISOString().slice(11, 19) + ' UTC';
|
return useLocalTime ? 'Uhr' : 'UTC';
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatDate(date, options) {
|
||||||
|
const settings = useLocalTime ? {} : { timeZone: 'UTC' };
|
||||||
|
return date.toLocaleDateString('de-DE', { ...options, ...settings });
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatTime(date, { withSeconds = true } = {}) {
|
||||||
|
const settings = {
|
||||||
|
hour: '2-digit',
|
||||||
|
minute: '2-digit',
|
||||||
|
...(withSeconds ? { second: '2-digit' } : {}),
|
||||||
|
hour12: false,
|
||||||
|
...(useLocalTime ? {} : { timeZone: 'UTC' }),
|
||||||
|
};
|
||||||
|
return `${date.toLocaleTimeString('de-DE', settings)} ${timeZoneSuffix()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshTimeDisplays() {
|
||||||
|
timeZoneLabelEl.textContent = timeZoneSuffix();
|
||||||
|
if (!currentEclipse) {
|
||||||
|
tlDisplay.textContent = `– – : – – ${timeZoneSuffix()}`;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
renderInfo();
|
||||||
|
renderContactTable();
|
||||||
|
updateSim();
|
||||||
|
}
|
||||||
|
|
||||||
|
function setInfoPanelCollapsed(collapsed) {
|
||||||
|
infoPanelCollapsed = collapsed;
|
||||||
|
infoPanel.classList.toggle('is-collapsed', collapsed);
|
||||||
|
infoToggle.setAttribute('aria-expanded', String(!collapsed));
|
||||||
|
infoToggle.title = collapsed ? 'Infokasten aufklappen' : 'Infokasten zuklappen';
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderInfo() {
|
function renderInfo() {
|
||||||
const ec = currentEclipse;
|
const ec = currentEclipse;
|
||||||
const d = ec.peak.date;
|
const d = ec.peak.date;
|
||||||
const ds = d.toLocaleDateString('de-DE', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' });
|
const ds = formatDate(d, { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' });
|
||||||
const ts = d.toISOString().slice(11, 19) + ' UTC';
|
const ts = formatTime(d);
|
||||||
const tc = { penumbral: 'eclipse-type-pen', partial: 'eclipse-type-par', total: 'eclipse-type-tot' }[ec.kind] || '';
|
const tc = { penumbral: 'eclipse-type-pen', partial: 'eclipse-type-par', total: 'eclipse-type-tot' }[ec.kind] || '';
|
||||||
const tl = { penumbral: 'Halbschatten-Finsternis', partial: 'Partielle Mondfinsternis', total: 'Totale Mondfinsternis' }[ec.kind] || ec.kind;
|
const tl = { penumbral: 'Halbschatten-Finsternis', partial: 'Partielle Mondfinsternis', total: 'Totale Mondfinsternis' }[ec.kind] || ec.kind;
|
||||||
|
|
||||||
@@ -791,7 +877,7 @@ function renderInfo() {
|
|||||||
? ec.umbral_magnitude.toFixed(3)
|
? ec.umbral_magnitude.toFixed(3)
|
||||||
: (ec.penumbral_magnitude !== undefined ? ec.penumbral_magnitude.toFixed(3) + ' (Hb)' : '—');
|
: (ec.penumbral_magnitude !== undefined ? ec.penumbral_magnitude.toFixed(3) + ' (Hb)' : '—');
|
||||||
|
|
||||||
infoPanel.innerHTML = `
|
document.getElementById('eclipseInfoBody').innerHTML = `
|
||||||
<div class="eclipse-info-type ${tc}">${tl}</div>
|
<div class="eclipse-info-type ${tc}">${tl}</div>
|
||||||
<div class="eclipse-info-date">${ds}</div>
|
<div class="eclipse-info-date">${ds}</div>
|
||||||
<div class="eclipse-info-time">${ts}</div>
|
<div class="eclipse-info-time">${ts}</div>
|
||||||
@@ -802,6 +888,7 @@ function renderInfo() {
|
|||||||
<tr><td>Magnitude</td><td>${mag}</td></tr>
|
<tr><td>Magnitude</td><td>${mag}</td></tr>
|
||||||
</table>
|
</table>
|
||||||
<div class="eclipse-info-phase" id="eclipsePhaseLabel">—</div>
|
<div class="eclipse-info-phase" id="eclipsePhaseLabel">—</div>
|
||||||
|
<div class="eclipse-info-scale-note">Abstände nicht maßstabsgetreu, Mond real etwa 60× weiter entfernt</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -832,7 +919,7 @@ function renderContactTable() {
|
|||||||
contactTable.innerHTML = rows.map(([lbl, off, desc]) =>
|
contactTable.innerHTML = rows.map(([lbl, off, desc]) =>
|
||||||
`<tr>
|
`<tr>
|
||||||
<td class="eclipse-contact-label">${lbl}</td>
|
<td class="eclipse-contact-label">${lbl}</td>
|
||||||
<td class="eclipse-contact-time">${fmtUTC(pk, off)}</td>
|
<td class="eclipse-contact-time">${formatTime(new Date(pk.getTime() + off * 60000))}</td>
|
||||||
<td class="eclipse-contact-desc">${desc}</td>
|
<td class="eclipse-contact-desc">${desc}</td>
|
||||||
</tr>`
|
</tr>`
|
||||||
).join('');
|
).join('');
|
||||||
@@ -886,9 +973,25 @@ function renderTimeline() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
infoToggle.addEventListener('click', () => {
|
||||||
|
setInfoPanelCollapsed(!infoPanelCollapsed);
|
||||||
|
});
|
||||||
|
|
||||||
// ════════════════════════════════════════════════════════════
|
// ════════════════════════════════════════════════════════════
|
||||||
// Interaction
|
// Interaction
|
||||||
// ════════════════════════════════════════════════════════════
|
// ════════════════════════════════════════════════════════════
|
||||||
|
const originalUpdateSim = updateSim;
|
||||||
|
updateSim = function() {
|
||||||
|
originalUpdateSim();
|
||||||
|
stageTimeEl.textContent = tlDisplay.textContent;
|
||||||
|
};
|
||||||
|
|
||||||
|
const originalRefreshTimeDisplays = refreshTimeDisplays;
|
||||||
|
refreshTimeDisplays = function() {
|
||||||
|
originalRefreshTimeDisplays();
|
||||||
|
stageTimeEl.textContent = tlDisplay.textContent;
|
||||||
|
};
|
||||||
|
|
||||||
function setupInteraction() {
|
function setupInteraction() {
|
||||||
// Camera orbit
|
// Camera orbit
|
||||||
canvas3d.addEventListener('mousedown', e => { isDragging = true; dragX = e.clientX; dragY = e.clientY; });
|
canvas3d.addEventListener('mousedown', e => { isDragging = true; dragX = e.clientX; dragY = e.clientY; });
|
||||||
@@ -949,6 +1052,16 @@ function setupInteraction() {
|
|||||||
// Speed
|
// Speed
|
||||||
speedSel.addEventListener('change', () => { playSpeed = parseInt(speedSel.value); });
|
speedSel.addEventListener('change', () => { playSpeed = parseInt(speedSel.value); });
|
||||||
|
|
||||||
|
useLocalTimeEl.addEventListener('change', () => {
|
||||||
|
useLocalTime = useLocalTimeEl.checked;
|
||||||
|
refreshTimeDisplays();
|
||||||
|
});
|
||||||
|
|
||||||
|
showStageTimeEl.addEventListener('change', () => {
|
||||||
|
showStageTime = showStageTimeEl.checked;
|
||||||
|
stageTimeEl.classList.toggle('is-hidden', !showStageTime);
|
||||||
|
});
|
||||||
|
|
||||||
// View toggle
|
// View toggle
|
||||||
btnGeoView.addEventListener('click', () => setView('geo'));
|
btnGeoView.addEventListener('click', () => setView('geo'));
|
||||||
btnMoonView.addEventListener('click', () => setView('moon'));
|
btnMoonView.addEventListener('click', () => setView('moon'));
|
||||||
|
|||||||
+121
-22
@@ -57,6 +57,40 @@ $userAlt = isset($currentLocation['elevation']) ? (float)$currentLocation['eleva
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="solarsystem-sidebar-block">
|
||||||
|
<div class="solarsystem-label">Steuerung</div>
|
||||||
|
<div class="eclipse-sidebar-controls">
|
||||||
|
<div class="eclipse-sidebar-buttons">
|
||||||
|
<button class="btn btn-sm btn-secondary" id="eclipseBtnRewind" title="Zum Anfang">⏮</button>
|
||||||
|
<button class="btn btn-sm btn-primary" id="eclipseBtnPlay" title="Play/Pause">▶ Play</button>
|
||||||
|
<button class="btn btn-sm btn-secondary" id="eclipseBtnEnd" title="Zum Ende">⏭</button>
|
||||||
|
</div>
|
||||||
|
<div class="eclipse-time-display" id="eclipseTimeDisplay">– – : – – UTC</div>
|
||||||
|
<label class="eclipse-speed-label eclipse-speed-label-sidebar">
|
||||||
|
<span class="solarsystem-label">Geschw.</span>
|
||||||
|
<select id="eclipseSpeedSel" class="eclipse-speed-sel">
|
||||||
|
<option value="1">×1</option>
|
||||||
|
<option value="3">×3</option>
|
||||||
|
<option value="10" selected>×10</option>
|
||||||
|
<option value="30">×30</option>
|
||||||
|
<option value="60">×60</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="solarsystem-sidebar-block">
|
||||||
|
<div class="solarsystem-label">Zeitformat</div>
|
||||||
|
<label class="form-checkbox" for="eclipseUseLocalTime">
|
||||||
|
<input type="checkbox" id="eclipseUseLocalTime">
|
||||||
|
<span>Lokale Zeit statt UTC anzeigen</span>
|
||||||
|
</label>
|
||||||
|
<label class="form-checkbox" for="eclipseShowStageTime">
|
||||||
|
<input type="checkbox" id="eclipseShowStageTime">
|
||||||
|
<span>Uhrzeit mittig in der Grafik anzeigen</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="solarsystem-sidebar-block">
|
<div class="solarsystem-sidebar-block">
|
||||||
<div class="solarsystem-label">Schatten-Skalierung</div>
|
<div class="solarsystem-label">Schatten-Skalierung</div>
|
||||||
<label class="solarsystem-label eclipse-control-label" for="umbraScaleRange">
|
<label class="solarsystem-label eclipse-control-label" for="umbraScaleRange">
|
||||||
@@ -70,7 +104,7 @@ $userAlt = isset($currentLocation['elevation']) ? (float)$currentLocation['eleva
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="solarsystem-sidebar-block is-hidden" id="eclipseDataBlock">
|
<div class="solarsystem-sidebar-block is-hidden" id="eclipseDataBlock">
|
||||||
<div class="solarsystem-label">Kontaktzeiten (UTC)</div>
|
<div class="solarsystem-label">Kontaktzeiten (<span id="eclipseTimeZoneLabel">UTC</span>)</div>
|
||||||
<table class="data-table" id="eclipseContactTable"></table>
|
<table class="data-table" id="eclipseContactTable"></table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -100,31 +134,31 @@ $userAlt = isset($currentLocation['elevation']) ? (float)$currentLocation['eleva
|
|||||||
|
|
||||||
<div id="eclipseLocalHint" class="eclipse-local-hint"></div>
|
<div id="eclipseLocalHint" class="eclipse-local-hint"></div>
|
||||||
|
|
||||||
<div id="eclipseScaleNote" class="eclipse-scale-note">
|
|
||||||
Distanzen stark komprimiert<br>Größenverhältnisse für die Anschauung angepasst
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="solarsystem-info-panel eclipse-info-panel" id="eclipseInfoPanel">
|
<div class="solarsystem-info-panel eclipse-info-panel" id="eclipseInfoPanel">
|
||||||
<button type="button" class="eclipse-info-toggle" id="eclipseInfoToggle" aria-expanded="true" aria-controls="eclipseInfoBody" title="Ein-/Ausklappen">
|
<button type="button" class="eclipse-info-toggle" id="eclipseInfoToggle" aria-expanded="true" aria-controls="eclipseInfoBody" title="Ein-/Ausklappen">
|
||||||
<span class="eclipse-info-toggle-icon">▾</span>
|
<span class="eclipse-info-toggle-icon">▾</span>
|
||||||
|
<span class="sr-only">Infokasten ein- oder ausklappen</span>
|
||||||
</button>
|
</button>
|
||||||
<div class="eclipse-info-body" id="eclipseInfoBody">
|
<div class="eclipse-info-body" id="eclipseInfoBody">
|
||||||
<div class="eclipse-info-empty">Wähle eine Finsternis aus der Liste</div>
|
<div class="eclipse-info-empty">Wähle eine Finsternis aus der Liste</div>
|
||||||
|
<div class="eclipse-info-scale-note">Distanzen stark komprimiert, Größenverhältnisse für die Anschauung angepasst</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="eclipse-stage-time eclipse-stage-time-solar is-hidden" id="eclipseStageTime">– – : – – UTC</div>
|
||||||
|
|
||||||
<div class="eclipse-timeline" id="eclipseTimeline">
|
<div class="eclipse-timeline" id="eclipseTimeline">
|
||||||
<div class="eclipse-timeline-bar" id="eclipseTimelineBar">
|
<div class="eclipse-timeline-bar" id="eclipseTimelineBar">
|
||||||
<div class="eclipse-tl-cursor" id="eclipseTimelineCursor"></div>
|
<div class="eclipse-tl-cursor" id="eclipseTimelineCursor"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="eclipse-timeline-controls">
|
<div class="eclipse-timeline-controls is-hidden" aria-hidden="true">
|
||||||
<button class="btn btn-sm btn-secondary" id="eclipseBtnRewind" title="Zum Anfang">⏮</button>
|
<button class="btn btn-sm btn-secondary" id="eclipseBtnRewindLegacy" title="Zum Anfang">⏮</button>
|
||||||
<button class="btn btn-sm btn-primary" id="eclipseBtnPlay" title="Play/Pause">▶ Play</button>
|
<button class="btn btn-sm btn-primary" id="eclipseBtnPlayLegacy" title="Play/Pause">▶ Play</button>
|
||||||
<button class="btn btn-sm btn-secondary" id="eclipseBtnEnd" title="Zum Ende">⏭</button>
|
<button class="btn btn-sm btn-secondary" id="eclipseBtnEndLegacy" title="Zum Ende">⏭</button>
|
||||||
<span class="eclipse-time-display" id="eclipseTimeDisplay">– – : – – UTC</span>
|
<span class="eclipse-time-display" id="eclipseTimeDisplayLegacy">– – : – – UTC</span>
|
||||||
<label class="eclipse-speed-label">
|
<label class="eclipse-speed-label">
|
||||||
<span class="solarsystem-label">Geschw.</span>
|
<span class="solarsystem-label">Geschw.</span>
|
||||||
<select id="eclipseSpeedSel" class="eclipse-speed-sel">
|
<select id="eclipseSpeedSelLegacy" class="eclipse-speed-sel">
|
||||||
<option value="1">×1</option>
|
<option value="1">×1</option>
|
||||||
<option value="3">×3</option>
|
<option value="3">×3</option>
|
||||||
<option value="10" selected>×10</option>
|
<option value="10" selected>×10</option>
|
||||||
@@ -183,6 +217,10 @@ const infoToggleBtn = document.getElementById('eclipseInfoToggle');
|
|||||||
const timelineBar = document.getElementById('eclipseTimelineBar');
|
const timelineBar = document.getElementById('eclipseTimelineBar');
|
||||||
const tlCursor = document.getElementById('eclipseTimelineCursor');
|
const tlCursor = document.getElementById('eclipseTimelineCursor');
|
||||||
const tlDisplay = document.getElementById('eclipseTimeDisplay');
|
const tlDisplay = document.getElementById('eclipseTimeDisplay');
|
||||||
|
const useLocalTimeEl = document.getElementById('eclipseUseLocalTime');
|
||||||
|
const showStageTimeEl = document.getElementById('eclipseShowStageTime');
|
||||||
|
const timeZoneLabelEl = document.getElementById('eclipseTimeZoneLabel');
|
||||||
|
const stageTimeEl = document.getElementById('eclipseStageTime');
|
||||||
const eclipseListEl = document.getElementById('eclipseList');
|
const eclipseListEl = document.getElementById('eclipseList');
|
||||||
const dataBlock = document.getElementById('eclipseDataBlock');
|
const dataBlock = document.getElementById('eclipseDataBlock');
|
||||||
const contactTable = document.getElementById('eclipseContactTable');
|
const contactTable = document.getElementById('eclipseContactTable');
|
||||||
@@ -207,6 +245,9 @@ let simTime = 0;
|
|||||||
let playing = false;
|
let playing = false;
|
||||||
let playSpeed = 10;
|
let playSpeed = 10;
|
||||||
let lastRAF = 0;
|
let lastRAF = 0;
|
||||||
|
let infoPanelCollapsed = false;
|
||||||
|
let useLocalTime = false;
|
||||||
|
let showStageTime = false;
|
||||||
let simPartialHalf = 95;
|
let simPartialHalf = 95;
|
||||||
let simCentralHalf = 0;
|
let simCentralHalf = 0;
|
||||||
let simTrackB = 0;
|
let simTrackB = 0;
|
||||||
@@ -649,7 +690,9 @@ function drawLocalView() {
|
|||||||
|
|
||||||
const sunR = R;
|
const sunR = R;
|
||||||
const moonR = geo.moonAngR * sc;
|
const moonR = geo.moonAngR * sc;
|
||||||
const mx = cx + geo.dx * sc;
|
// Sky-view perspective is mirrored horizontally relative to the
|
||||||
|
// east-positive topocentric offset used in the geometry calculation.
|
||||||
|
const mx = cx - geo.dx * sc;
|
||||||
const my = cy + geo.dy * sc;
|
const my = cy + geo.dy * sc;
|
||||||
|
|
||||||
const glow = ctx.createRadialGradient(cx, cy, sunR * 0.9, cx, cy, sunR * 2.2);
|
const glow = ctx.createRadialGradient(cx, cy, sunR * 0.9, cx, cy, sunR * 2.2);
|
||||||
@@ -1396,7 +1439,7 @@ function updateSim() {
|
|||||||
|
|
||||||
const peakDate = eventPeakDate();
|
const peakDate = eventPeakDate();
|
||||||
const cur = new Date(peakDate.getTime() + simTime * 60000);
|
const cur = new Date(peakDate.getTime() + simTime * 60000);
|
||||||
tlDisplay.textContent = cur.toISOString().slice(11, 16) + ' UTC';
|
tlDisplay.textContent = formatTime(cur, { withSeconds: false });
|
||||||
|
|
||||||
updateInfoPhase(cov);
|
updateInfoPhase(cov);
|
||||||
|
|
||||||
@@ -1428,15 +1471,49 @@ function renderLoop(now) {
|
|||||||
if (viewMode === 'space') renderer.render(scene, camera);
|
if (viewMode === 'space') renderer.render(scene, camera);
|
||||||
}
|
}
|
||||||
|
|
||||||
function fmtUTC(date) {
|
function timeZoneSuffix() {
|
||||||
return date.toISOString().slice(11, 19) + ' UTC';
|
return useLocalTime ? 'Uhr' : 'UTC';
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatDate(date, options) {
|
||||||
|
const settings = useLocalTime ? {} : { timeZone: 'UTC' };
|
||||||
|
return date.toLocaleDateString('de-DE', { ...options, ...settings });
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatTime(date, { withSeconds = true } = {}) {
|
||||||
|
const settings = {
|
||||||
|
hour: '2-digit',
|
||||||
|
minute: '2-digit',
|
||||||
|
...(withSeconds ? { second: '2-digit' } : {}),
|
||||||
|
hour12: false,
|
||||||
|
...(useLocalTime ? {} : { timeZone: 'UTC' }),
|
||||||
|
};
|
||||||
|
return `${date.toLocaleTimeString('de-DE', settings)} ${timeZoneSuffix()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshTimeDisplays() {
|
||||||
|
timeZoneLabelEl.textContent = timeZoneSuffix();
|
||||||
|
if (!currentEclipse) {
|
||||||
|
tlDisplay.textContent = `– – : – – ${timeZoneSuffix()}`;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
renderInfo();
|
||||||
|
renderContactTable();
|
||||||
|
updateSim();
|
||||||
|
}
|
||||||
|
|
||||||
|
function setInfoPanelCollapsed(collapsed) {
|
||||||
|
infoPanelCollapsed = collapsed;
|
||||||
|
infoPanel.classList.toggle('is-collapsed', collapsed);
|
||||||
|
infoToggleBtn.setAttribute('aria-expanded', String(!collapsed));
|
||||||
|
infoToggleBtn.title = collapsed ? 'Infokasten aufklappen' : 'Infokasten zuklappen';
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderInfo() {
|
function renderInfo() {
|
||||||
const ec = currentEclipse;
|
const ec = currentEclipse;
|
||||||
const d = ec.peak.date;
|
const d = ec.peak.date;
|
||||||
const ds = d.toLocaleDateString('de-DE', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' });
|
const ds = formatDate(d, { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' });
|
||||||
const ts = fmtUTC(d);
|
const ts = formatTime(d);
|
||||||
const tc = eclipseTypeClass(ec.kind);
|
const tc = eclipseTypeClass(ec.kind);
|
||||||
const tl = eclipseTypeLabel(ec.kind);
|
const tl = eclipseTypeLabel(ec.kind);
|
||||||
const locType = currentLocal ? eclipseTypeLabel(currentLocal.kind) : null;
|
const locType = currentLocal ? eclipseTypeLabel(currentLocal.kind) : null;
|
||||||
@@ -1458,6 +1535,7 @@ function renderInfo() {
|
|||||||
${!currentLocal && localObserver ? `<tr><td>Am Standort</td><td>nicht sichtbar</td></tr>` : ''}
|
${!currentLocal && localObserver ? `<tr><td>Am Standort</td><td>nicht sichtbar</td></tr>` : ''}
|
||||||
</table>
|
</table>
|
||||||
<div class="eclipse-info-phase" id="eclipsePhaseLabel">—</div>
|
<div class="eclipse-info-phase" id="eclipsePhaseLabel">—</div>
|
||||||
|
<div class="eclipse-info-scale-note">Distanzen stark komprimiert, Größenverhältnisse für die Anschauung angepasst</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1490,7 +1568,7 @@ function renderContactTable() {
|
|||||||
contactTable.innerHTML = rows.map(([lbl, date, desc]) => `
|
contactTable.innerHTML = rows.map(([lbl, date, desc]) => `
|
||||||
<tr>
|
<tr>
|
||||||
<td class="eclipse-contact-label">${lbl}</td>
|
<td class="eclipse-contact-label">${lbl}</td>
|
||||||
<td class="eclipse-contact-time">${fmtUTC(date)}</td>
|
<td class="eclipse-contact-time">${formatTime(date)}</td>
|
||||||
<td class="eclipse-contact-desc">${desc}</td>
|
<td class="eclipse-contact-desc">${desc}</td>
|
||||||
</tr>
|
</tr>
|
||||||
`).join('');
|
`).join('');
|
||||||
@@ -1508,7 +1586,7 @@ function renderContactTable() {
|
|||||||
contactTable.innerHTML = rows.map(([lbl, date, desc]) => `
|
contactTable.innerHTML = rows.map(([lbl, date, desc]) => `
|
||||||
<tr>
|
<tr>
|
||||||
<td class="eclipse-contact-label">${lbl}</td>
|
<td class="eclipse-contact-label">${lbl}</td>
|
||||||
<td class="eclipse-contact-time">${fmtUTC(date)}</td>
|
<td class="eclipse-contact-time">${formatTime(date)}</td>
|
||||||
<td class="eclipse-contact-desc">${desc}</td>
|
<td class="eclipse-contact-desc">${desc}</td>
|
||||||
</tr>
|
</tr>
|
||||||
`).join('');
|
`).join('');
|
||||||
@@ -1524,7 +1602,7 @@ function renderContactTable() {
|
|||||||
contactTable.innerHTML = rows.map(([lbl, date, desc]) => `
|
contactTable.innerHTML = rows.map(([lbl, date, desc]) => `
|
||||||
<tr>
|
<tr>
|
||||||
<td class="eclipse-contact-label">${lbl}</td>
|
<td class="eclipse-contact-label">${lbl}</td>
|
||||||
<td class="eclipse-contact-time">${date ? fmtUTC(date) : '—'}</td>
|
<td class="eclipse-contact-time">${date ? formatTime(date) : '—'}</td>
|
||||||
<td class="eclipse-contact-desc">${desc}</td>
|
<td class="eclipse-contact-desc">${desc}</td>
|
||||||
</tr>
|
</tr>
|
||||||
`).join('');
|
`).join('');
|
||||||
@@ -1581,6 +1659,18 @@ function renderTimeline() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const originalUpdateSim = updateSim;
|
||||||
|
updateSim = function() {
|
||||||
|
originalUpdateSim();
|
||||||
|
stageTimeEl.textContent = tlDisplay.textContent;
|
||||||
|
};
|
||||||
|
|
||||||
|
const originalRefreshTimeDisplays = refreshTimeDisplays;
|
||||||
|
refreshTimeDisplays = function() {
|
||||||
|
originalRefreshTimeDisplays();
|
||||||
|
stageTimeEl.textContent = tlDisplay.textContent;
|
||||||
|
};
|
||||||
|
|
||||||
function setupInteraction() {
|
function setupInteraction() {
|
||||||
canvas3d.addEventListener('contextmenu', e => e.preventDefault());
|
canvas3d.addEventListener('contextmenu', e => e.preventDefault());
|
||||||
canvas3d.addEventListener('mousedown', e => {
|
canvas3d.addEventListener('mousedown', e => {
|
||||||
@@ -1672,6 +1762,16 @@ function setupInteraction() {
|
|||||||
playSpeed = parseInt(speedSel.value, 10);
|
playSpeed = parseInt(speedSel.value, 10);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useLocalTimeEl.addEventListener('change', () => {
|
||||||
|
useLocalTime = useLocalTimeEl.checked;
|
||||||
|
refreshTimeDisplays();
|
||||||
|
});
|
||||||
|
|
||||||
|
showStageTimeEl.addEventListener('change', () => {
|
||||||
|
showStageTime = showStageTimeEl.checked;
|
||||||
|
stageTimeEl.classList.toggle('is-hidden', !showStageTime);
|
||||||
|
});
|
||||||
|
|
||||||
if (umbraScaleRange && umbraScaleValue) {
|
if (umbraScaleRange && umbraScaleValue) {
|
||||||
const syncUmbra = () => {
|
const syncUmbra = () => {
|
||||||
umbraProxyScale = parseFloat(umbraScaleRange.value);
|
umbraProxyScale = parseFloat(umbraScaleRange.value);
|
||||||
@@ -1695,8 +1795,7 @@ function setupInteraction() {
|
|||||||
document.getElementById('eclipseSearchBtn').addEventListener('click', searchEclipses);
|
document.getElementById('eclipseSearchBtn').addEventListener('click', searchEclipses);
|
||||||
|
|
||||||
infoToggleBtn.addEventListener('click', () => {
|
infoToggleBtn.addEventListener('click', () => {
|
||||||
const collapsed = infoPanel.classList.toggle('is-collapsed');
|
setInfoPanelCollapsed(!infoPanelCollapsed);
|
||||||
infoToggleBtn.setAttribute('aria-expanded', String(!collapsed));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
btnSpaceView.addEventListener('click', () => setView('space'));
|
btnSpaceView.addEventListener('click', () => setView('space'));
|
||||||
|
|||||||
Reference in New Issue
Block a user