diff --git a/public/barycenter.php b/public/barycenter.php
index 888ce6b..05afcbc 100644
--- a/public/barycenter.php
+++ b/public/barycenter.php
@@ -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 {
- Abstand vom Sonnenmittelpunkt
+ Räumlicher Abstand vom Sonnenmittelpunkt
= number_format($distSR, 3, ',', '') ?> R☉
- = number_format($cur['dist_au'], 5, ',', '') ?> AU
+ XY-Projektion: = number_format($projDistSR, 3, ',', '') ?> R☉ · = number_format($cur['dist_au'], 5, ',', '') ?> AU
- Position
+ Position in der Grafik
= $inside ? 'Innerhalb der Sonne' : 'Außerhalb der Sonne' ?>
- Stand: = htmlspecialchars($cur['date_utc'], ENT_QUOTES, 'UTF-8') ?>
+ Bewertet als XY-Projektion · Stand: = htmlspecialchars($cur['date_utc'], ENT_QUOTES, 'UTF-8') ?>
- Maximum (2006–2050)
- = number_format($result['data']['max_dist_solar_radii'], 3, ',', '') ?> R☉
- Maximaler Abstand im Zeitraum
+ Maximum der Grafik (2006–2050)
+ = number_format($result['data']['max_proj_dist_solar_radii'], 3, ',', '') ?> R☉
+ Größter projizierter Abstand im Zeitraum
@@ -205,8 +225,7 @@ input[type=range].bc-slider {
Sonne
Sonnenoberfläche
- Baryzentrum (Vergangenheit)
- Baryzentrum (Prognose)
+ Baryzentrum-Bahn
Baryzentrum (heute)
@@ -214,6 +233,16 @@ input[type=range].bc-slider {
heute
+
+
+
+ Baryzentrum-Linie
+
+
+
+ 1R- und 2R-Radius
+
+
@@ -233,6 +262,10 @@ input[type=range].bc-slider {
Die Bahn folgt keinem einfachen Kreis –
die Überlagerung der Planetenumläufe erzeugt eine komplexe Spirale.
+
+ 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.
+
@@ -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;
diff --git a/public/py/api.py b/public/py/api.py
index c2ad5e4..f555004 100644
--- a/public/py/api.py
+++ b/public/py/api.py
@@ -5780,7 +5780,7 @@ def action_barycenter(args: list[str]) -> dict:
steps_per_year = int(args[1]) if len(args) > 1 and args[1].isdigit() else 12
years_forward = int(args[2]) if len(args) > 2 and args[2].isdigit() else 0
years_back = max(1, min(years_back, 100))
- steps_per_year = max(4, min(steps_per_year, 52))
+ steps_per_year = max(4, min(steps_per_year, 366))
years_forward = max(0, min(years_forward, 100))
now = datetime.now(timezone.utc)
@@ -5793,6 +5793,8 @@ def action_barycenter(args: list[str]) -> dict:
cur_y = -sun_state.y
cur_dist_au = math.hypot(cur_x, cur_y, -sun_state.z)
cur_dist_sr = cur_dist_au / _SUN_RADIUS_AU
+ cur_proj_dist_au = math.hypot(cur_x, cur_y)
+ cur_proj_dist_sr = cur_proj_dist_au / _SUN_RADIUS_AU
# -- Zeitreihe --
total_steps = (years_back + years_forward) * steps_per_year
@@ -5800,24 +5802,32 @@ def action_barycenter(args: list[str]) -> dict:
start_jd = now_time.tt - years_back * 365.25
series = []
max_dist_au = 0.0
+ max_proj_dist_au = 0.0
for i in range(total_steps + 1):
t = astronomy.Time(start_jd + i * days_per_step)
s = astronomy.BaryState(astronomy.Body.Sun, t)
tx, ty = -s.x, -s.y
d = math.hypot(tx, ty, -s.z)
+ dp = math.hypot(tx, ty)
if d > max_dist_au:
max_dist_au = d
+ if dp > max_proj_dist_au:
+ max_proj_dist_au = dp
dt_utc = datetime(2000, 1, 1, 12, tzinfo=timezone.utc) + timedelta(days=t.tt - 0.0)
# Epoche J2000.0 = 2000-01-01 12:00 TT ≈ UTC (Differenz <1 min hier vernachlässigt)
- series.append({"x": round(tx, 6), "y": round(ty, 6), "d": round(d / _SUN_RADIUS_AU, 3)})
+ series.append({
+ "x": round(tx, 6),
+ "y": round(ty, 6),
+ "d": round(d / _SUN_RADIUS_AU, 3),
+ "dp": round(dp / _SUN_RADIUS_AU, 3),
+ })
- # Zeitstempel für Animationslabel (nur Jahr.Monat reicht)
+ # Zeitstempel für Animationslabel als echte UTC-Kalenderdaten
series_dates = []
for i in range(total_steps + 1):
t_days = start_jd + i * days_per_step
- # Grobe Umrechnung J2000-TT → Jahr
- year_frac = 2000.0 + (t_days / 365.25)
- series_dates.append(round(year_frac, 3))
+ dt_utc = datetime(2000, 1, 1, 12, tzinfo=timezone.utc) + timedelta(days=t_days)
+ series_dates.append(dt_utc.strftime("%Y-%m-%d"))
# -- Planetenmassen (GM relativ zur Sonne = 1) für gewichteten Beitrag --
# Quellen: IAU 2012 / astronomy-engine Konstanten
@@ -5872,13 +5882,16 @@ def action_barycenter(args: list[str]) -> dict:
"y": round(cur_y, 6),
"dist_au": round(cur_dist_au, 6),
"dist_solar_radii": round(cur_dist_sr, 4),
- "inside_sun": cur_dist_sr <= 1.0,
+ "proj_dist_au": round(cur_proj_dist_au, 6),
+ "proj_dist_solar_radii": round(cur_proj_dist_sr, 4),
+ "inside_sun": cur_proj_dist_sr <= 1.0,
"date_utc": now.strftime("%Y-%m-%dT%H:%M:%SZ"),
},
"series": series,
"series_dates": series_dates,
"now_index": now_index,
"max_dist_solar_radii": round(max_dist_au / _SUN_RADIUS_AU, 3),
+ "max_proj_dist_solar_radii": round(max_proj_dist_au / _SUN_RADIUS_AU, 3),
"sun_radius_au": _SUN_RADIUS_AU,
"contributions": contributions,
"years_back": years_back,