Verbessere Baryzentrum-Darstellung und Tagesauflösung
This commit is contained in:
+102
-41
@@ -4,7 +4,7 @@ session_start();
|
||||
|
||||
require_once __DIR__ . '/python_api.php';
|
||||
|
||||
$result = runPythonApi('barycenter', ['20', '12', '24']);
|
||||
$result = runPythonApi('barycenter', ['20', '365', '24']);
|
||||
|
||||
|
||||
require __DIR__ . '/header.php';
|
||||
@@ -135,6 +135,25 @@ require __DIR__ . '/header.php';
|
||||
color: var(--gold-pale);
|
||||
min-width: 60px;
|
||||
}
|
||||
.bc-toggle-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.65rem 1rem;
|
||||
margin-top: 0.65rem;
|
||||
}
|
||||
.bc-toggle {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.45rem;
|
||||
font-size: 0.82rem;
|
||||
color: var(--text-dim);
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
.bc-toggle input {
|
||||
accent-color: var(--gold);
|
||||
cursor: pointer;
|
||||
}
|
||||
input[type=range].bc-slider {
|
||||
flex: 1;
|
||||
min-width: 120px;
|
||||
@@ -169,29 +188,30 @@ input[type=range].bc-slider {
|
||||
<?php else:
|
||||
$cur = $result['data']['current'];
|
||||
$distSR = $cur['dist_solar_radii'];
|
||||
$projDistSR = $cur['proj_dist_solar_radii'];
|
||||
$inside = $cur['inside_sun'];
|
||||
$contributions = $result['data']['contributions'];
|
||||
?>
|
||||
|
||||
<div class="bc-stats-row">
|
||||
<div class="bc-stat">
|
||||
<span class="bc-stat-label">Abstand vom Sonnenmittelpunkt</span>
|
||||
<span class="bc-stat-label">Räumlicher Abstand vom Sonnenmittelpunkt</span>
|
||||
<span class="bc-stat-value"><?= number_format($distSR, 3, ',', '') ?> R☉</span>
|
||||
<span class="bc-stat-sub"><?= number_format($cur['dist_au'], 5, ',', '') ?> AU</span>
|
||||
<span class="bc-stat-sub">XY-Projektion: <?= number_format($projDistSR, 3, ',', '') ?> R☉ · <?= number_format($cur['dist_au'], 5, ',', '') ?> AU</span>
|
||||
</div>
|
||||
<div class="bc-stat">
|
||||
<span class="bc-stat-label">Position</span>
|
||||
<span class="bc-stat-label">Position in der Grafik</span>
|
||||
<span class="bc-stat-value">
|
||||
<span class="bc-inside-badge <?= $inside ? 'inside' : 'outside' ?>">
|
||||
<?= $inside ? 'Innerhalb der Sonne' : 'Außerhalb der Sonne' ?>
|
||||
</span>
|
||||
</span>
|
||||
<span class="bc-stat-sub">Stand: <?= htmlspecialchars($cur['date_utc'], ENT_QUOTES, 'UTF-8') ?></span>
|
||||
<span class="bc-stat-sub">Bewertet als XY-Projektion · Stand: <?= htmlspecialchars($cur['date_utc'], ENT_QUOTES, 'UTF-8') ?></span>
|
||||
</div>
|
||||
<div class="bc-stat">
|
||||
<span class="bc-stat-label">Maximum (2006–2050)</span>
|
||||
<span class="bc-stat-value"><?= number_format($result['data']['max_dist_solar_radii'], 3, ',', '') ?> R☉</span>
|
||||
<span class="bc-stat-sub">Maximaler Abstand im Zeitraum</span>
|
||||
<span class="bc-stat-label">Maximum der Grafik (2006–2050)</span>
|
||||
<span class="bc-stat-value"><?= number_format($result['data']['max_proj_dist_solar_radii'], 3, ',', '') ?> R☉</span>
|
||||
<span class="bc-stat-sub">Größter projizierter Abstand im Zeitraum</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -205,8 +225,7 @@ input[type=range].bc-slider {
|
||||
<div class="bc-legend">
|
||||
<span class="bc-legend-item"><span class="bc-legend-dot" style="background:#f5c842"></span> Sonne</span>
|
||||
<span class="bc-legend-item"><span class="bc-legend-dot" style="background:rgba(255,255,255,0.25);border:1px dashed #666"></span> Sonnenoberfläche</span>
|
||||
<span class="bc-legend-item"><span class="bc-legend-dot" style="background:#4fc3d8"></span> Baryzentrum (Vergangenheit)</span>
|
||||
<span class="bc-legend-item"><span class="bc-legend-dot" style="background:#c9a84c;opacity:0.7"></span> Baryzentrum (Prognose)</span>
|
||||
<span class="bc-legend-item"><span class="bc-legend-dot" style="background:#4fc3d8"></span> Baryzentrum-Bahn</span>
|
||||
<span class="bc-legend-item"><span class="bc-legend-dot" style="background:#ff6060"></span> Baryzentrum (heute)</span>
|
||||
</div>
|
||||
<div class="bc-anim-controls">
|
||||
@@ -214,6 +233,16 @@ input[type=range].bc-slider {
|
||||
<input type="range" class="bc-slider" id="bc-slider" min="0" max="240" value="240" step="1">
|
||||
<span class="bc-year-label" id="bc-year-label">heute</span>
|
||||
</div>
|
||||
<div class="bc-toggle-row">
|
||||
<label class="bc-toggle">
|
||||
<input type="checkbox" id="bc-toggle-path" checked>
|
||||
<span>Baryzentrum-Linie</span>
|
||||
</label>
|
||||
<label class="bc-toggle">
|
||||
<input type="checkbox" id="bc-toggle-radii" checked>
|
||||
<span>1R- und 2R-Radius</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
@@ -233,6 +262,10 @@ input[type=range].bc-slider {
|
||||
Die Bahn folgt keinem einfachen Kreis –
|
||||
die Überlagerung der Planetenumläufe erzeugt eine komplexe Spirale.
|
||||
</p>
|
||||
<p style="font-size:0.9rem;color:var(--text-dim);line-height:1.6;margin-top:0.75rem">
|
||||
Die Grafik ist eine XY-Projektion. Deshalb wird die Lage relativ zur Sonnenscheibe
|
||||
hier ebenfalls in der Projektion bewertet, nicht mit dem räumlichen 3D-Abstand.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="card" style="margin-top:1.5rem">
|
||||
@@ -279,7 +312,7 @@ input[type=range].bc-slider {
|
||||
const CUR = <?= json_encode($cur, JSON_UNESCAPED_UNICODE) ?>;
|
||||
const NOW_INDEX = <?= (int)$result['data']['now_index'] ?>;
|
||||
const SUN_RADIUS_AU = <?= json_encode($result['data']['sun_radius_au']) ?>;
|
||||
const MAX_DIST_SR = <?= json_encode($result['data']['max_dist_solar_radii']) ?>;
|
||||
const MAX_DIST_SR = <?= json_encode($result['data']['max_proj_dist_solar_radii']) ?>;
|
||||
|
||||
const canvas = document.getElementById('bc-canvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
@@ -292,13 +325,19 @@ input[type=range].bc-slider {
|
||||
const slider = document.getElementById('bc-slider');
|
||||
const playBtn = document.getElementById('bc-play');
|
||||
const yearLabel = document.getElementById('bc-year-label');
|
||||
const pathToggle = document.getElementById('bc-toggle-path');
|
||||
const radiiToggle = document.getElementById('bc-toggle-radii');
|
||||
|
||||
slider.max = SERIES.length - 1;
|
||||
slider.value = NOW_INDEX;
|
||||
|
||||
function formatDate(yearFrac) {
|
||||
const y = Math.floor(yearFrac);
|
||||
const m = Math.round((yearFrac - y) * 12) + 1;
|
||||
function formatDate(dateValue) {
|
||||
if (typeof dateValue === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(dateValue)) {
|
||||
return dateValue;
|
||||
}
|
||||
|
||||
const y = Math.floor(dateValue);
|
||||
const m = Math.round((dateValue - y) * 12) + 1;
|
||||
return y + '-' + String(m).padStart(2, '0');
|
||||
}
|
||||
|
||||
@@ -322,20 +361,22 @@ input[type=range].bc-slider {
|
||||
|
||||
ctx.clearRect(0, 0, W, H);
|
||||
|
||||
// Background grid rings
|
||||
ctx.strokeStyle = 'rgba(255,255,255,0.05)';
|
||||
ctx.lineWidth = 1;
|
||||
for (let r = 1; r <= Math.ceil(MAX_DIST_SR * 1.2); r++) {
|
||||
ctx.beginPath();
|
||||
ctx.arc(cx, cy, r * scale, 0, Math.PI * 2);
|
||||
ctx.stroke();
|
||||
}
|
||||
// Ring labels
|
||||
ctx.font = '10px sans-serif';
|
||||
ctx.fillStyle = 'rgba(255,255,255,0.25)';
|
||||
ctx.textAlign = 'left';
|
||||
for (let r = 1; r <= Math.ceil(MAX_DIST_SR * 1.2); r++) {
|
||||
ctx.fillText(r + ' R☉', cx + r * scale + 3, cy - 3);
|
||||
if (radiiToggle.checked) {
|
||||
const guideRadii = [1, 2];
|
||||
ctx.strokeStyle = 'rgba(255,255,255,0.07)';
|
||||
ctx.lineWidth = 1;
|
||||
ctx.font = '10px sans-serif';
|
||||
ctx.fillStyle = 'rgba(255,255,255,0.25)';
|
||||
ctx.textAlign = 'left';
|
||||
for (const r of guideRadii) {
|
||||
if (r > MAX_DIST_SR * 1.25) {
|
||||
continue;
|
||||
}
|
||||
ctx.beginPath();
|
||||
ctx.arc(cx, cy, r * scale, 0, Math.PI * 2);
|
||||
ctx.stroke();
|
||||
ctx.fillText(r + ' R☉', cx + r * scale + 3, cy - 3);
|
||||
}
|
||||
}
|
||||
|
||||
// Sun glow
|
||||
@@ -354,21 +395,22 @@ input[type=range].bc-slider {
|
||||
ctx.fillStyle = '#f5c842';
|
||||
ctx.fill();
|
||||
|
||||
// Sun surface dashed circle
|
||||
ctx.beginPath();
|
||||
ctx.arc(cx, cy, sunRadiusPx, 0, Math.PI * 2);
|
||||
ctx.setLineDash([4, 4]);
|
||||
ctx.strokeStyle = 'rgba(255,255,255,0.2)';
|
||||
ctx.lineWidth = 1;
|
||||
ctx.stroke();
|
||||
ctx.setLineDash([]);
|
||||
if (radiiToggle.checked) {
|
||||
ctx.beginPath();
|
||||
ctx.arc(cx, cy, sunRadiusPx, 0, Math.PI * 2);
|
||||
ctx.setLineDash([4, 4]);
|
||||
ctx.strokeStyle = 'rgba(255,255,255,0.2)';
|
||||
ctx.lineWidth = 1;
|
||||
ctx.stroke();
|
||||
ctx.setLineDash([]);
|
||||
}
|
||||
|
||||
// Barycenter path up to visibleUpTo
|
||||
const end = Math.min(visibleUpTo, SERIES.length - 1);
|
||||
|
||||
// Vergangener Pfad (bis NOW_INDEX) — cyan
|
||||
const pastEnd = Math.min(end, NOW_INDEX);
|
||||
if (pastEnd >= 1) {
|
||||
if (pathToggle.checked && pastEnd >= 1) {
|
||||
ctx.beginPath();
|
||||
const p0 = SERIES[0];
|
||||
ctx.moveTo(cx + p0.x / SUN_RADIUS_AU * scale, cy - p0.y / SUN_RADIUS_AU * scale);
|
||||
@@ -383,7 +425,7 @@ input[type=range].bc-slider {
|
||||
}
|
||||
|
||||
// Zukünftiger Pfad (ab NOW_INDEX) — gold gedimmt, gestrichelt
|
||||
if (end > NOW_INDEX) {
|
||||
if (pathToggle.checked && end > NOW_INDEX) {
|
||||
ctx.beginPath();
|
||||
const pn = SERIES[NOW_INDEX];
|
||||
ctx.moveTo(cx + pn.x / SUN_RADIUS_AU * scale, cy - pn.y / SUN_RADIUS_AU * scale);
|
||||
@@ -391,9 +433,9 @@ input[type=range].bc-slider {
|
||||
const p = SERIES[i];
|
||||
ctx.lineTo(cx + p.x / SUN_RADIUS_AU * scale, cy - p.y / SUN_RADIUS_AU * scale);
|
||||
}
|
||||
ctx.strokeStyle = 'rgba(201, 168, 76, 0.45)';
|
||||
ctx.strokeStyle = 'rgba(79, 195, 216, 0.55)';
|
||||
ctx.lineWidth = 1.5;
|
||||
ctx.setLineDash([5, 4]);
|
||||
ctx.setLineDash([]);
|
||||
ctx.stroke();
|
||||
ctx.setLineDash([]);
|
||||
}
|
||||
@@ -421,7 +463,7 @@ input[type=range].bc-slider {
|
||||
ctx.font = '11px sans-serif';
|
||||
ctx.fillStyle = 'rgba(255,255,255,0.65)';
|
||||
ctx.textAlign = 'left';
|
||||
ctx.fillText(pCur.d.toFixed(3) + ' R☉', px + 8, py - 6);
|
||||
ctx.fillText(pCur.dp.toFixed(3) + ' R☉', px + 8, py - 6);
|
||||
}
|
||||
|
||||
function updateLabel() {
|
||||
@@ -433,12 +475,31 @@ input[type=range].bc-slider {
|
||||
}
|
||||
}
|
||||
|
||||
function setVisibleIndex(nextIndex) {
|
||||
const clamped = Math.max(0, Math.min(SERIES.length - 1, nextIndex));
|
||||
visibleUpTo = clamped;
|
||||
slider.value = clamped;
|
||||
updateLabel();
|
||||
draw();
|
||||
}
|
||||
|
||||
function handleWheelStep(event) {
|
||||
event.preventDefault();
|
||||
if (animPlaying) stopAnim();
|
||||
const direction = event.deltaY > 0 ? 1 : -1;
|
||||
setVisibleIndex(parseInt(slider.value, 10) + direction);
|
||||
}
|
||||
|
||||
slider.addEventListener('input', () => {
|
||||
visibleUpTo = parseInt(slider.value, 10);
|
||||
updateLabel();
|
||||
draw();
|
||||
if (animPlaying) stopAnim();
|
||||
});
|
||||
slider.addEventListener('wheel', handleWheelStep, { passive: false });
|
||||
canvas.addEventListener('wheel', handleWheelStep, { passive: false });
|
||||
pathToggle.addEventListener('change', draw);
|
||||
radiiToggle.addEventListener('change', draw);
|
||||
|
||||
function stopAnim() {
|
||||
animPlaying = false;
|
||||
|
||||
Reference in New Issue
Block a user