Umrechungen eingebaut
This commit is contained in:
@@ -0,0 +1,752 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
ini_set('display_errors', '1');
|
||||
error_reporting(E_ALL);
|
||||
session_start();
|
||||
|
||||
$loggedIn = isset($_SESSION['user_id']);
|
||||
$pageTitle = 'Astronomische Umrechnungen';
|
||||
$headerIntroPre = 'Astronomie-Werkzeuge';
|
||||
$headerIntroTitle = 'Astronomische Umrechnungen';
|
||||
$headerIntroSub = 'Entfernungen zwischen haeufigen astronomischen Einheiten umrechnen.';
|
||||
|
||||
function h(?string $value): string
|
||||
{
|
||||
return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
?>
|
||||
<?php require __DIR__ . '/header.php'; ?>
|
||||
|
||||
<style>
|
||||
.astro-conv-layout {
|
||||
display: grid;
|
||||
gap: 1.25rem;
|
||||
}
|
||||
|
||||
.astro-conv-tabs {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.astro-conv-tab {
|
||||
padding: 0.75rem 1rem;
|
||||
border-radius: 999px;
|
||||
border: 1px solid rgba(130, 170, 255, 0.18);
|
||||
background: rgba(255,255,255,0.04);
|
||||
color: #dce8ff;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.astro-conv-tab.is-active {
|
||||
background: linear-gradient(180deg, rgba(82, 153, 255, 0.28), rgba(49, 112, 255, 0.18));
|
||||
border-color: rgba(130, 170, 255, 0.4);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.astro-conv-panel {
|
||||
padding: 1.2rem;
|
||||
border-radius: 1rem;
|
||||
background:
|
||||
radial-gradient(circle at top left, rgba(82, 153, 255, 0.12), transparent 36%),
|
||||
linear-gradient(180deg, rgba(13, 19, 33, 0.96), rgba(8, 11, 20, 0.98));
|
||||
border: 1px solid rgba(130, 170, 255, 0.16);
|
||||
}
|
||||
|
||||
.astro-conv-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 0.85rem;
|
||||
}
|
||||
|
||||
.astro-conv-field {
|
||||
display: grid;
|
||||
gap: 0.45rem;
|
||||
}
|
||||
|
||||
.astro-conv-field label {
|
||||
color: #c7d6f4;
|
||||
font-size: 0.94rem;
|
||||
}
|
||||
|
||||
.astro-conv-label-help {
|
||||
border-bottom: 1px dotted rgba(199, 214, 244, 0.45);
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
.astro-conv-input {
|
||||
width: 100%;
|
||||
padding: 0.72rem 0.8rem;
|
||||
border-radius: 0.8rem;
|
||||
border: 1px solid rgba(255,255,255,0.12);
|
||||
background: rgba(255,255,255,0.05);
|
||||
color: #f8fbff;
|
||||
font-size: 0.96rem;
|
||||
}
|
||||
|
||||
.astro-conv-input:focus {
|
||||
outline: none;
|
||||
border-color: rgba(130, 170, 255, 0.6);
|
||||
box-shadow: 0 0 0 3px rgba(82, 153, 255, 0.16);
|
||||
}
|
||||
|
||||
.astro-conv-field {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.astro-conv-tooltip {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: calc(100% + 0.45rem);
|
||||
z-index: 20;
|
||||
min-width: 14rem;
|
||||
max-width: 22rem;
|
||||
padding: 0.7rem 0.8rem;
|
||||
border-radius: 0.8rem;
|
||||
background: rgba(10, 15, 27, 0.96);
|
||||
border: 1px solid rgba(130, 170, 255, 0.2);
|
||||
color: #eef4ff;
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.45;
|
||||
white-space: pre-line;
|
||||
box-shadow: 0 12px 30px rgba(0,0,0,0.35);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transform: translateY(-0.25rem);
|
||||
transition: opacity 140ms ease, transform 140ms ease;
|
||||
}
|
||||
|
||||
.astro-conv-field.is-tooltip-open .astro-conv-tooltip {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.astro-conv-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.8rem;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.astro-conv-tab-panel {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.astro-conv-tab-panel.is-active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@media (max-width: 960px) {
|
||||
.astro-conv-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="astro-conv-layout">
|
||||
<div class="astro-conv-tabs" role="tablist" aria-label="Umrechnungsbereiche">
|
||||
<button type="button" class="astro-conv-tab is-active" data-tab-target="distanceTab" role="tab" aria-selected="true">Entfernung</button>
|
||||
<button type="button" class="astro-conv-tab" data-tab-target="redshiftTab" role="tab" aria-selected="false">Rotverschiebung</button>
|
||||
<button type="button" class="astro-conv-tab" data-tab-target="timeTab" role="tab" aria-selected="false">Zeit</button>
|
||||
</div>
|
||||
|
||||
<section class="card astro-conv-panel astro-conv-tab-panel is-active" id="distanceTab" role="tabpanel">
|
||||
<h2>Entfernungs-Umrechner</h2>
|
||||
|
||||
<div class="astro-conv-grid" id="distanceConverter">
|
||||
<div class="astro-conv-field">
|
||||
<label for="distanceKm">Kilometer (km)</label>
|
||||
<input class="astro-conv-input" id="distanceKm" type="text" inputmode="decimal" value="384400">
|
||||
</div>
|
||||
|
||||
<div class="astro-conv-field">
|
||||
<label for="distanceAu">Astronomische Einheiten (AU)</label>
|
||||
<input class="astro-conv-input" id="distanceAu" type="text" inputmode="decimal">
|
||||
</div>
|
||||
|
||||
<div class="astro-conv-field">
|
||||
<label for="distanceLightMinute">Lichtminuten (lm)</label>
|
||||
<input class="astro-conv-input" id="distanceLightMinute" type="text" inputmode="decimal">
|
||||
</div>
|
||||
|
||||
<div class="astro-conv-field">
|
||||
<label for="distanceLightHour">Lichtstunden (lh)</label>
|
||||
<input class="astro-conv-input" id="distanceLightHour" type="text" inputmode="decimal">
|
||||
</div>
|
||||
|
||||
<div class="astro-conv-field">
|
||||
<label for="distanceLy">Lichtjahre (ly)</label>
|
||||
<input class="astro-conv-input" id="distanceLy" type="text" inputmode="decimal">
|
||||
</div>
|
||||
|
||||
<div class="astro-conv-field">
|
||||
<label for="distancePc">Parsec (pc)</label>
|
||||
<input class="astro-conv-input" id="distancePc" type="text" inputmode="decimal">
|
||||
</div>
|
||||
|
||||
<div class="astro-conv-field">
|
||||
<label for="distanceMpc">Megaparsec (Mpc)</label>
|
||||
<input class="astro-conv-input" id="distanceMpc" type="text" inputmode="decimal">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="astro-conv-actions">
|
||||
<button type="button" class="btn btn-secondary" id="distanceClear">Leeren</button>
|
||||
<button type="button" class="btn btn-primary" id="distanceMoon">Mondentfernung</button>
|
||||
<button type="button" class="btn btn-primary" id="distanceSun">1 AU</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="card astro-conv-panel astro-conv-tab-panel" id="redshiftTab" role="tabpanel">
|
||||
<h2>Rotverschiebung (z)</h2>
|
||||
|
||||
<div class="astro-conv-grid" id="redshiftConverter">
|
||||
<div class="astro-conv-field">
|
||||
<label for="redshiftZ">Rotverschiebung z</label>
|
||||
<input class="astro-conv-input" id="redshiftZ" type="text" inputmode="decimal" value="0,1">
|
||||
</div>
|
||||
|
||||
<div class="astro-conv-field">
|
||||
<label for="redshiftFactor"><span class="astro-conv-label-help" title="Der Faktor, um den sich Wellenlaengen durch die Expansion des Universums verlaengern.">Faktor (1 + z)</span></label>
|
||||
<input class="astro-conv-input" id="redshiftFactor" type="text" inputmode="decimal" readonly>
|
||||
</div>
|
||||
|
||||
<div class="astro-conv-field">
|
||||
<label for="redshiftScaleFactor"><span class="astro-conv-label-help" title="Der kosmologische Skalenfaktor a = 1 / (1 + z). Er beschreibt, wie gross das Universum zum Zeitpunkt der Aussendung relativ zu heute war.">Skalenfaktor a</span></label>
|
||||
<input class="astro-conv-input" id="redshiftScaleFactor" type="text" inputmode="decimal" readonly>
|
||||
</div>
|
||||
|
||||
<div class="astro-conv-field">
|
||||
<label for="redshiftVelocityApprox"><span class="astro-conv-label-help" title="Einfache Naeherung fuer kleine Rotverschiebungen: v ungefaehr gleich z mal Lichtgeschwindigkeit.">Geschwindigkeit naeherungsweise (km/s)</span></label>
|
||||
<input class="astro-conv-input" id="redshiftVelocityApprox" type="text" inputmode="decimal" readonly>
|
||||
</div>
|
||||
|
||||
<div class="astro-conv-field">
|
||||
<label for="redshiftVelocityRel"><span class="astro-conv-label-help" title="Relativistisch korrigierte Geschwindigkeit aus der Doppler-Formel. Sinnvoller als die lineare Naeherung bei groesserem z.">Geschwindigkeit relativistisch (km/s)</span></label>
|
||||
<input class="astro-conv-input" id="redshiftVelocityRel" type="text" inputmode="decimal" readonly>
|
||||
</div>
|
||||
|
||||
<div class="astro-conv-field">
|
||||
<label for="redshiftVelocityC"><span class="astro-conv-label-help" title="Dieselbe relativistische Geschwindigkeit, aber als Anteil der Lichtgeschwindigkeit in Prozent.">Geschwindigkeit relativistisch (% c)</span></label>
|
||||
<input class="astro-conv-input" id="redshiftVelocityC" type="text" inputmode="decimal" readonly>
|
||||
</div>
|
||||
|
||||
<div class="astro-conv-field">
|
||||
<label for="redshiftRestNm">Ruhewellenlaenge (nm)</label>
|
||||
<input class="astro-conv-input" id="redshiftRestNm" type="text" inputmode="decimal" value="656,3">
|
||||
</div>
|
||||
|
||||
<div class="astro-conv-field">
|
||||
<label for="redshiftObservedNm">Beobachtete Wellenlaenge (nm)</label>
|
||||
<input class="astro-conv-input" id="redshiftObservedNm" type="text" inputmode="decimal" readonly>
|
||||
</div>
|
||||
|
||||
<div class="astro-conv-field">
|
||||
<label for="redshiftFrequencyFactor"><span class="astro-conv-label-help" title="Die beobachtete Frequenz ist um diesen Faktor kleiner als die urspruengliche Frequenz.">Frequenzfaktor 1 / (1 + z)</span></label>
|
||||
<input class="astro-conv-input" id="redshiftFrequencyFactor" type="text" inputmode="decimal" readonly>
|
||||
</div>
|
||||
|
||||
<div class="astro-conv-field">
|
||||
<label for="redshiftLookbackGyr"><span class="astro-conv-label-help" title="Zeit, die das Licht seit seiner Aussendung bis heute unterwegs war. Gyr steht fuer Milliarden Jahre.">Rueckblickzeit (Gyr)</span></label>
|
||||
<input class="astro-conv-input" id="redshiftLookbackGyr" type="text" inputmode="decimal" readonly>
|
||||
</div>
|
||||
|
||||
<div class="astro-conv-field">
|
||||
<label for="redshiftComovingMpc"><span class="astro-conv-label-help" title="Kosmologische Entfernung im mitbewegten Koordinatensystem. Sie bleibt fuer mit der Expansion mitbewegte Objekte zeitlich konstant.">Mitbewegte Entfernung (Mpc)</span></label>
|
||||
<input class="astro-conv-input" id="redshiftComovingMpc" type="text" inputmode="decimal" readonly>
|
||||
</div>
|
||||
|
||||
<div class="astro-conv-field">
|
||||
<label for="redshiftLuminosityMpc"><span class="astro-conv-label-help" title="Entfernung, die man bei der beobachteten Helligkeit eines Objekts in einem expandierenden Universum verwendet. Wichtig fuer Standardkerzen.">Leuchtkraftentfernung (Mpc)</span></label>
|
||||
<input class="astro-conv-input" id="redshiftLuminosityMpc" type="text" inputmode="decimal" readonly>
|
||||
</div>
|
||||
|
||||
<div class="astro-conv-field">
|
||||
<label for="redshiftAngularDiameterMpc"><span class="astro-conv-label-help" title="Entfernung, die den beobachteten Winkel mit der echten Groesse eines Objekts verknuepft. Wichtig fuer scheinbare Groessen am Himmel.">Winkeldurchmesser-Entfernung (Mpc)</span></label>
|
||||
<input class="astro-conv-input" id="redshiftAngularDiameterMpc" type="text" inputmode="decimal" readonly>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="astro-conv-actions">
|
||||
<button type="button" class="btn btn-secondary" id="redshiftClear">Leeren</button>
|
||||
<button type="button" class="btn btn-primary" id="redshiftGalaxy">z = 0,1</button>
|
||||
<button type="button" class="btn btn-primary" id="redshiftQuasar">z = 6</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="card astro-conv-panel astro-conv-tab-panel" id="timeTab" role="tabpanel">
|
||||
<h2>Zeit-Umrechner</h2>
|
||||
|
||||
<div class="astro-conv-grid" id="timeConverter">
|
||||
<div class="astro-conv-field">
|
||||
<label for="timeUtc">UTC</label>
|
||||
<input class="astro-conv-input" id="timeUtc" type="text" value="2026-04-06 12:00:00">
|
||||
</div>
|
||||
|
||||
<div class="astro-conv-field">
|
||||
<label for="timeJd">Julianisches Datum (JD)</label>
|
||||
<input class="astro-conv-input" id="timeJd" type="text" inputmode="decimal">
|
||||
</div>
|
||||
|
||||
<div class="astro-conv-field">
|
||||
<label for="timeMjd">Modifiziertes Julianisches Datum (MJD)</label>
|
||||
<input class="astro-conv-input" id="timeMjd" type="text" inputmode="decimal">
|
||||
</div>
|
||||
|
||||
<div class="astro-conv-field">
|
||||
<label for="timeUnix">Unix-Zeit</label>
|
||||
<input class="astro-conv-input" id="timeUnix" type="text" inputmode="decimal">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="astro-conv-actions">
|
||||
<button type="button" class="btn btn-secondary" id="timeClear">Leeren</button>
|
||||
<button type="button" class="btn btn-primary" id="timeNow">Jetzt</button>
|
||||
<button type="button" class="btn btn-primary" id="timeJ2000">J2000</button>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<script src="js/number_to_german_words.js"></script>
|
||||
<script>
|
||||
(function () {
|
||||
const SPEED_OF_LIGHT_KM_S = 299792.458;
|
||||
const H0 = 70;
|
||||
const OMEGA_M = 0.3;
|
||||
const OMEGA_LAMBDA = 0.7;
|
||||
const MPC_IN_KM = 3.0856775814913673e19;
|
||||
const SECONDS_PER_GYR = 365.25 * 24 * 3600 * 1e9;
|
||||
const KM_PER_AU = 149597870.7;
|
||||
const KM_PER_LIGHT_MINUTE = 17987547.48;
|
||||
const KM_PER_LIGHT_HOUR = 1079252848.8;
|
||||
const KM_PER_LY = 9460730472580.8;
|
||||
const KM_PER_PC = 30856775814913.67;
|
||||
const KM_PER_MPC = KM_PER_PC * 1000000;
|
||||
|
||||
const distanceFields = {
|
||||
km: document.getElementById('distanceKm'),
|
||||
au: document.getElementById('distanceAu'),
|
||||
lm: document.getElementById('distanceLightMinute'),
|
||||
lh: document.getElementById('distanceLightHour'),
|
||||
ly: document.getElementById('distanceLy'),
|
||||
pc: document.getElementById('distancePc'),
|
||||
mpc: document.getElementById('distanceMpc')
|
||||
};
|
||||
|
||||
const redshiftFields = {
|
||||
z: document.getElementById('redshiftZ'),
|
||||
factor: document.getElementById('redshiftFactor'),
|
||||
scaleFactor: document.getElementById('redshiftScaleFactor'),
|
||||
velocityApprox: document.getElementById('redshiftVelocityApprox'),
|
||||
velocityRel: document.getElementById('redshiftVelocityRel'),
|
||||
velocityC: document.getElementById('redshiftVelocityC'),
|
||||
restNm: document.getElementById('redshiftRestNm'),
|
||||
observedNm: document.getElementById('redshiftObservedNm'),
|
||||
frequencyFactor: document.getElementById('redshiftFrequencyFactor'),
|
||||
lookbackGyr: document.getElementById('redshiftLookbackGyr'),
|
||||
comovingMpc: document.getElementById('redshiftComovingMpc'),
|
||||
luminosityMpc: document.getElementById('redshiftLuminosityMpc'),
|
||||
angularDiameterMpc: document.getElementById('redshiftAngularDiameterMpc')
|
||||
};
|
||||
|
||||
const timeFields = {
|
||||
utc: document.getElementById('timeUtc'),
|
||||
jd: document.getElementById('timeJd'),
|
||||
mjd: document.getElementById('timeMjd'),
|
||||
unix: document.getElementById('timeUnix')
|
||||
};
|
||||
|
||||
const unitToKm = {
|
||||
km: 1,
|
||||
au: KM_PER_AU,
|
||||
lm: KM_PER_LIGHT_MINUTE,
|
||||
lh: KM_PER_LIGHT_HOUR,
|
||||
ly: KM_PER_LY,
|
||||
pc: KM_PER_PC,
|
||||
mpc: KM_PER_MPC
|
||||
};
|
||||
|
||||
const germanNumberFormatter = new Intl.NumberFormat('de-DE', {
|
||||
maximumFractionDigits: 10
|
||||
});
|
||||
|
||||
const parseGermanNumber = function (value) {
|
||||
if (typeof value !== 'string') {
|
||||
return Number.NaN;
|
||||
}
|
||||
|
||||
const normalized = value
|
||||
.trim()
|
||||
.replace(/\s+/g, '')
|
||||
.replace(/\./g, '')
|
||||
.replace(',', '.');
|
||||
|
||||
if (normalized === '') {
|
||||
return Number.NaN;
|
||||
}
|
||||
|
||||
return Number(normalized);
|
||||
};
|
||||
|
||||
const formatValue = function (value) {
|
||||
if (!Number.isFinite(value)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (value === 0) {
|
||||
return '0';
|
||||
}
|
||||
|
||||
return germanNumberFormatter.format(value);
|
||||
};
|
||||
|
||||
const cosmologyE = function (z) {
|
||||
return Math.sqrt(OMEGA_M * Math.pow(1 + z, 3) + OMEGA_LAMBDA);
|
||||
};
|
||||
|
||||
const integrateSimpson = function (fn, start, end, steps) {
|
||||
if (steps % 2 !== 0) {
|
||||
steps += 1;
|
||||
}
|
||||
|
||||
const h = (end - start) / steps;
|
||||
let sum = fn(start) + fn(end);
|
||||
|
||||
for (let i = 1; i < steps; i += 1) {
|
||||
const x = start + i * h;
|
||||
sum += fn(x) * (i % 2 === 0 ? 2 : 4);
|
||||
}
|
||||
|
||||
return (h / 3) * sum;
|
||||
};
|
||||
|
||||
const updateTooltip = function (field) {
|
||||
const wrapper = field.closest('.astro-conv-field');
|
||||
const tooltipId = field.getAttribute('data-tooltip-id');
|
||||
const tooltip = tooltipId ? document.getElementById(tooltipId) : null;
|
||||
const numericValue = parseGermanNumber(field.value);
|
||||
|
||||
if (!wrapper || !tooltip || !Number.isFinite(numericValue)) {
|
||||
if (wrapper) {
|
||||
wrapper.classList.remove('is-tooltip-open');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof window.numberToGermanText !== 'function') {
|
||||
return;
|
||||
}
|
||||
|
||||
tooltip.textContent = window.numberToGermanText(numericValue);
|
||||
};
|
||||
|
||||
const attachTooltip = function (field, key) {
|
||||
const wrapper = field.closest('.astro-conv-field');
|
||||
if (!wrapper) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tooltip = document.createElement('div');
|
||||
tooltip.className = 'astro-conv-tooltip';
|
||||
tooltip.id = 'tooltip-' + key;
|
||||
wrapper.appendChild(tooltip);
|
||||
field.setAttribute('data-tooltip-id', tooltip.id);
|
||||
};
|
||||
|
||||
const wireTooltipHover = function (field) {
|
||||
field.addEventListener('mouseenter', function () {
|
||||
updateTooltip(field);
|
||||
if (field.value.trim() === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
const wrapper = field.closest('.astro-conv-field');
|
||||
if (wrapper) {
|
||||
wrapper.classList.add('is-tooltip-open');
|
||||
}
|
||||
});
|
||||
|
||||
field.addEventListener('mouseleave', function () {
|
||||
const wrapper = field.closest('.astro-conv-field');
|
||||
if (wrapper) {
|
||||
wrapper.classList.remove('is-tooltip-open');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const distanceFieldEntries = Object.entries(distanceFields);
|
||||
distanceFieldEntries.forEach(function ([unit, field]) {
|
||||
attachTooltip(field, 'distance-' + unit);
|
||||
wireTooltipHover(field);
|
||||
});
|
||||
|
||||
const redshiftFieldEntries = Object.entries(redshiftFields);
|
||||
redshiftFieldEntries.forEach(function ([unit, field]) {
|
||||
attachTooltip(field, 'redshift-' + unit);
|
||||
wireTooltipHover(field);
|
||||
});
|
||||
|
||||
const timeFieldEntries = Object.entries(timeFields);
|
||||
timeFieldEntries.forEach(function ([unit, field]) {
|
||||
attachTooltip(field, 'time-' + unit);
|
||||
wireTooltipHover(field);
|
||||
});
|
||||
|
||||
const updateDistanceFrom = function (sourceUnit) {
|
||||
const rawValue = distanceFields[sourceUnit].value.trim();
|
||||
if (rawValue === '') {
|
||||
Object.values(distanceFields).forEach(function (field, index) {
|
||||
if (Object.keys(distanceFields)[index] !== sourceUnit) {
|
||||
field.value = '';
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const numericValue = parseGermanNumber(rawValue);
|
||||
if (!Number.isFinite(numericValue)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const valueInKm = numericValue * unitToKm[sourceUnit];
|
||||
distanceFields[sourceUnit].value = formatValue(numericValue);
|
||||
updateTooltip(distanceFields[sourceUnit]);
|
||||
|
||||
Object.entries(distanceFields).forEach(function ([unit, field]) {
|
||||
if (unit === sourceUnit) {
|
||||
return;
|
||||
}
|
||||
|
||||
field.value = formatValue(valueInKm / unitToKm[unit]);
|
||||
updateTooltip(field);
|
||||
});
|
||||
};
|
||||
|
||||
distanceFieldEntries.forEach(function ([unit, field]) {
|
||||
field.addEventListener('input', function () {
|
||||
updateDistanceFrom(unit);
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById('distanceClear').addEventListener('click', function () {
|
||||
Object.values(distanceFields).forEach(function (field) {
|
||||
field.value = '';
|
||||
});
|
||||
distanceFields.km.focus();
|
||||
});
|
||||
|
||||
document.getElementById('distanceMoon').addEventListener('click', function () {
|
||||
distanceFields.km.value = '384400';
|
||||
updateDistanceFrom('km');
|
||||
});
|
||||
|
||||
document.getElementById('distanceSun').addEventListener('click', function () {
|
||||
distanceFields.au.value = '1';
|
||||
updateDistanceFrom('au');
|
||||
});
|
||||
|
||||
const updateRedshift = function () {
|
||||
const z = parseGermanNumber(redshiftFields.z.value.trim());
|
||||
const restNm = parseGermanNumber(redshiftFields.restNm.value.trim());
|
||||
|
||||
if (!Number.isFinite(z) || !Number.isFinite(restNm) || z <= -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const factor = 1 + z;
|
||||
const scaleFactor = 1 / factor;
|
||||
const observedNm = restNm * factor;
|
||||
const frequencyFactor = 1 / factor;
|
||||
const velocityApprox = z * SPEED_OF_LIGHT_KM_S;
|
||||
const betaRel = ((factor * factor) - 1) / ((factor * factor) + 1);
|
||||
const velocityRel = betaRel * SPEED_OF_LIGHT_KM_S;
|
||||
const velocityC = betaRel * 100;
|
||||
const integrationSteps = Math.max(200, Math.ceil(z * 200));
|
||||
const comovingIntegral = integrateSimpson(function (currentZ) {
|
||||
return 1 / cosmologyE(currentZ);
|
||||
}, 0, z, integrationSteps);
|
||||
const lookbackIntegral = integrateSimpson(function (currentZ) {
|
||||
return 1 / ((1 + currentZ) * cosmologyE(currentZ));
|
||||
}, 0, z, integrationSteps);
|
||||
const hubbleTimeSeconds = MPC_IN_KM / H0;
|
||||
const comovingMpc = (SPEED_OF_LIGHT_KM_S / H0) * comovingIntegral;
|
||||
const luminosityMpc = comovingMpc * factor;
|
||||
const angularDiameterMpc = comovingMpc / factor;
|
||||
const lookbackGyr = (hubbleTimeSeconds * lookbackIntegral) / SECONDS_PER_GYR;
|
||||
|
||||
redshiftFields.z.value = formatValue(z);
|
||||
redshiftFields.restNm.value = formatValue(restNm);
|
||||
redshiftFields.factor.value = formatValue(factor);
|
||||
redshiftFields.scaleFactor.value = formatValue(scaleFactor);
|
||||
redshiftFields.observedNm.value = formatValue(observedNm);
|
||||
redshiftFields.frequencyFactor.value = formatValue(frequencyFactor);
|
||||
redshiftFields.velocityApprox.value = formatValue(velocityApprox);
|
||||
redshiftFields.velocityRel.value = formatValue(velocityRel);
|
||||
redshiftFields.velocityC.value = formatValue(velocityC);
|
||||
redshiftFields.lookbackGyr.value = formatValue(lookbackGyr);
|
||||
redshiftFields.comovingMpc.value = formatValue(comovingMpc);
|
||||
redshiftFields.luminosityMpc.value = formatValue(luminosityMpc);
|
||||
redshiftFields.angularDiameterMpc.value = formatValue(angularDiameterMpc);
|
||||
|
||||
Object.values(redshiftFields).forEach(function (field) {
|
||||
updateTooltip(field);
|
||||
});
|
||||
};
|
||||
|
||||
['z', 'restNm'].forEach(function (key) {
|
||||
redshiftFields[key].addEventListener('input', updateRedshift);
|
||||
});
|
||||
|
||||
document.getElementById('redshiftClear').addEventListener('click', function () {
|
||||
Object.values(redshiftFields).forEach(function (field) {
|
||||
field.value = '';
|
||||
});
|
||||
redshiftFields.z.focus();
|
||||
});
|
||||
|
||||
document.getElementById('redshiftGalaxy').addEventListener('click', function () {
|
||||
redshiftFields.z.value = '0,1';
|
||||
redshiftFields.restNm.value = '656,3';
|
||||
updateRedshift();
|
||||
});
|
||||
|
||||
document.getElementById('redshiftQuasar').addEventListener('click', function () {
|
||||
redshiftFields.z.value = '6';
|
||||
redshiftFields.restNm.value = '121,567';
|
||||
updateRedshift();
|
||||
});
|
||||
|
||||
const parseUtcDateTime = function (value) {
|
||||
const match = String(value).trim().match(/^(\d{4})-(\d{2})-(\d{2})(?:[ T](\d{2}):(\d{2})(?::(\d{2}))?)?$/);
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const year = Number(match[1]);
|
||||
const month = Number(match[2]);
|
||||
const day = Number(match[3]);
|
||||
const hour = Number(match[4] || '0');
|
||||
const minute = Number(match[5] || '0');
|
||||
const second = Number(match[6] || '0');
|
||||
const date = new Date(Date.UTC(year, month - 1, day, hour, minute, second));
|
||||
|
||||
return Number.isNaN(date.getTime()) ? null : date;
|
||||
};
|
||||
|
||||
const formatUtcDateTime = function (date) {
|
||||
if (!(date instanceof Date) || Number.isNaN(date.getTime())) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const parts = [
|
||||
date.getUTCFullYear().toString().padStart(4, '0'),
|
||||
(date.getUTCMonth() + 1).toString().padStart(2, '0'),
|
||||
date.getUTCDate().toString().padStart(2, '0')
|
||||
];
|
||||
|
||||
const timeParts = [
|
||||
date.getUTCHours().toString().padStart(2, '0'),
|
||||
date.getUTCMinutes().toString().padStart(2, '0'),
|
||||
date.getUTCSeconds().toString().padStart(2, '0')
|
||||
];
|
||||
|
||||
return parts.join('-') + ' ' + timeParts.join(':');
|
||||
};
|
||||
|
||||
const dateToJulianDate = function (date) {
|
||||
return (date.getTime() / 86400000) + 2440587.5;
|
||||
};
|
||||
|
||||
const julianDateToDate = function (jd) {
|
||||
return new Date((jd - 2440587.5) * 86400000);
|
||||
};
|
||||
|
||||
const updateTimeFrom = function (sourceUnit) {
|
||||
let date = null;
|
||||
|
||||
if (sourceUnit === 'utc') {
|
||||
date = parseUtcDateTime(timeFields.utc.value);
|
||||
} else if (sourceUnit === 'jd') {
|
||||
const jd = parseGermanNumber(timeFields.jd.value.trim());
|
||||
date = Number.isFinite(jd) ? julianDateToDate(jd) : null;
|
||||
} else if (sourceUnit === 'mjd') {
|
||||
const mjd = parseGermanNumber(timeFields.mjd.value.trim());
|
||||
date = Number.isFinite(mjd) ? julianDateToDate(mjd + 2400000.5) : null;
|
||||
} else if (sourceUnit === 'unix') {
|
||||
const unixSeconds = parseGermanNumber(timeFields.unix.value.trim());
|
||||
date = Number.isFinite(unixSeconds) ? new Date(unixSeconds * 1000) : null;
|
||||
}
|
||||
|
||||
if (!(date instanceof Date) || Number.isNaN(date.getTime())) {
|
||||
return;
|
||||
}
|
||||
|
||||
const jd = dateToJulianDate(date);
|
||||
const mjd = jd - 2400000.5;
|
||||
const unixSeconds = Math.floor(date.getTime() / 1000);
|
||||
|
||||
timeFields.utc.value = formatUtcDateTime(date);
|
||||
timeFields.jd.value = formatValue(jd);
|
||||
timeFields.mjd.value = formatValue(mjd);
|
||||
timeFields.unix.value = formatValue(unixSeconds);
|
||||
|
||||
Object.values(timeFields).forEach(function (field) {
|
||||
updateTooltip(field);
|
||||
});
|
||||
};
|
||||
|
||||
timeFields.utc.addEventListener('input', function () {
|
||||
updateTimeFrom('utc');
|
||||
});
|
||||
['jd', 'mjd', 'unix'].forEach(function (key) {
|
||||
timeFields[key].addEventListener('input', function () {
|
||||
updateTimeFrom(key);
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById('timeClear').addEventListener('click', function () {
|
||||
Object.values(timeFields).forEach(function (field) {
|
||||
field.value = '';
|
||||
});
|
||||
timeFields.utc.focus();
|
||||
});
|
||||
|
||||
document.getElementById('timeNow').addEventListener('click', function () {
|
||||
timeFields.utc.value = formatUtcDateTime(new Date());
|
||||
updateTimeFrom('utc');
|
||||
});
|
||||
|
||||
document.getElementById('timeJ2000').addEventListener('click', function () {
|
||||
timeFields.utc.value = '2000-01-01 12:00:00';
|
||||
updateTimeFrom('utc');
|
||||
});
|
||||
|
||||
const tabs = Array.from(document.querySelectorAll('.astro-conv-tab'));
|
||||
const tabPanels = Array.from(document.querySelectorAll('.astro-conv-tab-panel'));
|
||||
|
||||
const activateTab = function (targetId) {
|
||||
tabs.forEach(function (tab) {
|
||||
const isActive = tab.getAttribute('data-tab-target') === targetId;
|
||||
tab.classList.toggle('is-active', isActive);
|
||||
tab.setAttribute('aria-selected', isActive ? 'true' : 'false');
|
||||
});
|
||||
|
||||
tabPanels.forEach(function (panel) {
|
||||
panel.classList.toggle('is-active', panel.id === targetId);
|
||||
});
|
||||
};
|
||||
|
||||
tabs.forEach(function (tab) {
|
||||
tab.addEventListener('click', function () {
|
||||
activateTab(tab.getAttribute('data-tab-target'));
|
||||
});
|
||||
});
|
||||
|
||||
updateDistanceFrom('km');
|
||||
updateRedshift();
|
||||
updateTimeFrom('utc');
|
||||
})();
|
||||
</script>
|
||||
|
||||
<?php require __DIR__ . '/footer.php'; ?>
|
||||
Reference in New Issue
Block a user