610 lines
20 KiB
PHP
610 lines
20 KiB
PHP
<?php
|
||
declare(strict_types=1);
|
||
|
||
ini_set('display_errors', '1');
|
||
error_reporting(E_ALL);
|
||
session_start();
|
||
|
||
$pageTitle = 'Schwarzkörperstrahlung';
|
||
$headerIntroPre = 'Astronomie-Werkzeuge';
|
||
$headerIntroTitle = 'Schwarzkörperstrahlung';
|
||
$headerIntroSub = 'Planck-Kurve für eine frei wählbare Temperatur als interaktives Diagramm.';
|
||
|
||
require __DIR__ . '/header.php';
|
||
?>
|
||
|
||
<style>
|
||
.bb-layout {
|
||
display: grid;
|
||
grid-template-columns: minmax(18rem, 24rem) minmax(0, 1fr);
|
||
gap: 1.5rem;
|
||
align-items: start;
|
||
}
|
||
|
||
.bb-panel,
|
||
.bb-chart-card {
|
||
display: grid;
|
||
gap: 1rem;
|
||
}
|
||
|
||
.bb-field-grid {
|
||
display: grid;
|
||
gap: 1rem;
|
||
}
|
||
|
||
.bb-field {
|
||
display: grid;
|
||
gap: 0.45rem;
|
||
}
|
||
|
||
.bb-field label {
|
||
color: var(--text-dim);
|
||
font-size: 0.92rem;
|
||
}
|
||
|
||
.bb-number-row {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.6rem;
|
||
}
|
||
|
||
.bb-number-row input[type="number"] {
|
||
width: 100%;
|
||
padding: 0.72rem 0.8rem;
|
||
border-radius: var(--radius);
|
||
border: 1px solid var(--border);
|
||
background: rgba(255,255,255,0.04);
|
||
color: var(--text);
|
||
font-size: 0.96rem;
|
||
font-family: inherit;
|
||
}
|
||
|
||
.bb-number-row input[type="number"]:focus,
|
||
.bb-field input[type="range"]:focus {
|
||
outline: none;
|
||
border-color: rgba(201, 168, 76, 0.5);
|
||
box-shadow: 0 0 0 3px rgba(201, 168, 76, 0.1);
|
||
}
|
||
|
||
.bb-unit {
|
||
color: var(--text-dim);
|
||
font-size: 0.88rem;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.bb-field input[type="range"] {
|
||
width: 100%;
|
||
accent-color: var(--gold);
|
||
cursor: pointer;
|
||
}
|
||
|
||
.bb-hint {
|
||
color: var(--text-dim);
|
||
font-size: 0.8rem;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
.bb-presets {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 0.55rem;
|
||
}
|
||
|
||
.bb-toggle {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.55rem;
|
||
color: var(--text-dim);
|
||
font-size: 0.86rem;
|
||
}
|
||
|
||
.bb-toggle input[type="checkbox"] {
|
||
accent-color: var(--gold);
|
||
cursor: pointer;
|
||
}
|
||
|
||
.bb-field.is-disabled {
|
||
opacity: 0.55;
|
||
}
|
||
|
||
.bb-stats {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||
gap: 0.85rem;
|
||
}
|
||
|
||
.bb-stat {
|
||
display: grid;
|
||
gap: 0.2rem;
|
||
padding: 0.9rem 1rem;
|
||
border-radius: var(--radius);
|
||
border: 1px solid var(--border);
|
||
background: var(--bg-card2);
|
||
}
|
||
|
||
.bb-stat-label {
|
||
color: var(--text-dim);
|
||
font-size: 0.78rem;
|
||
letter-spacing: 0.04em;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.bb-stat-value {
|
||
color: var(--gold-pale);
|
||
font-size: 1.18rem;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.bb-stat-sub {
|
||
color: var(--text-dim);
|
||
font-size: 0.8rem;
|
||
}
|
||
|
||
.bb-curve-wrap {
|
||
border-radius: var(--radius);
|
||
border: 1px solid var(--border);
|
||
background:
|
||
radial-gradient(circle at top, rgba(201, 168, 76, 0.12), transparent 40%),
|
||
linear-gradient(180deg, rgba(10, 14, 28, 0.96), rgba(5, 7, 14, 1));
|
||
padding: 0.75rem;
|
||
}
|
||
|
||
#bb-canvas {
|
||
display: block;
|
||
width: 100%;
|
||
height: 28rem;
|
||
border-radius: calc(var(--radius) - 0.2rem);
|
||
}
|
||
|
||
.bb-note-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
gap: 1rem;
|
||
}
|
||
|
||
.bb-note {
|
||
color: var(--text-dim);
|
||
font-size: 0.9rem;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
.bb-note strong {
|
||
color: var(--text);
|
||
}
|
||
|
||
@media (max-width: 980px) {
|
||
.bb-layout {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.bb-stats,
|
||
.bb-note-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
#bb-canvas {
|
||
height: 22rem;
|
||
}
|
||
}
|
||
</style>
|
||
|
||
<div class="bb-layout">
|
||
<section class="card bb-panel">
|
||
<div>
|
||
<h2>Parameter</h2>
|
||
<p class="bb-hint">Die Kurve zeigt die spektrale Strahlungsdichte eines idealen Schwarzkörpers nach dem planckschen Strahlungsgesetz.</p>
|
||
</div>
|
||
|
||
<div class="bb-field-grid">
|
||
<div class="bb-field">
|
||
<label for="bbTemperature">Temperatur</label>
|
||
<div class="bb-number-row">
|
||
<input id="bbTemperature" type="number" min="100" max="40000" step="10" value="5778">
|
||
<span class="bb-unit">K</span>
|
||
</div>
|
||
<input id="bbTemperatureRange" type="range" min="100" max="40000" step="10" value="5778">
|
||
<div class="bb-hint">Typische Bereiche: Glühlampe ~ 2.700 K, Sonne ~ 5.778 K, heißer Stern > 10.000 K.</div>
|
||
</div>
|
||
|
||
<div class="bb-field">
|
||
<label for="bbMaxWavelength">Diagrammbereich</label>
|
||
<div class="bb-number-row">
|
||
<input id="bbMaxWavelength" type="number" min="1000" max="10000" step="100" value="3000">
|
||
<span class="bb-unit">nm</span>
|
||
</div>
|
||
<input id="bbMaxWavelengthRange" type="range" min="1000" max="10000" step="100" value="3000">
|
||
<div class="bb-hint">Das Diagramm beginnt bei 100 nm und endet beim hier gewählten Maximalwert.</div>
|
||
</div>
|
||
|
||
<div class="bb-field is-disabled" id="bbYAxisField">
|
||
<label for="bbYAxisMax">Y-Achse</label>
|
||
<label class="bb-toggle" for="bbYAxisAuto">
|
||
<input id="bbYAxisAuto" type="checkbox" checked>
|
||
<span>Automatisch skalieren</span>
|
||
</label>
|
||
<div class="bb-number-row">
|
||
<input id="bbYAxisMax" type="number" min="1000000" max="400000000000000000" step="1000000" value="10000000000000" disabled>
|
||
<span class="bb-unit">W·sr⁻¹·m⁻³</span>
|
||
</div>
|
||
<input id="bbYAxisMaxRange" type="range" min="1000000" max="400000000000000000" step="1000000" value="10000000000000" disabled>
|
||
<div class="bb-hint">Wenn Auto aus ist, legst du hier den Maximalwert der y-Achse selbst fest.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div>
|
||
<div class="bb-hint" style="margin-bottom:0.5rem;">Beispiele</div>
|
||
<div class="bb-presets">
|
||
<button type="button" class="btn btn-secondary btn-sm" data-temp="300">Erde ~ 300 K</button>
|
||
<button type="button" class="btn btn-secondary btn-sm" data-temp="2700">Glühlampe</button>
|
||
<button type="button" class="btn btn-secondary btn-sm" data-temp="5778">Sonne</button>
|
||
<button type="button" class="btn btn-secondary btn-sm" data-temp="10000">Heißer Stern</button>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="bb-chart-card">
|
||
<div class="bb-stats">
|
||
<div class="bb-stat">
|
||
<span class="bb-stat-label">Wellenlängenmaximum</span>
|
||
<span class="bb-stat-value" id="bbPeakNm">–</span>
|
||
<span class="bb-stat-sub" id="bbPeakRegion">–</span>
|
||
</div>
|
||
<div class="bb-stat">
|
||
<span class="bb-stat-label">Stefan-Boltzmann</span>
|
||
<span class="bb-stat-value" id="bbFlux">–</span>
|
||
<span class="bb-stat-sub">Gesamtleistung pro Fläche</span>
|
||
</div>
|
||
<div class="bb-stat">
|
||
<span class="bb-stat-label">Relative Farbwirkung</span>
|
||
<span class="bb-stat-value" id="bbColorLabel">–</span>
|
||
<span class="bb-stat-sub">grob aus dem Peak-Bereich</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<h2>Planck-Kurve</h2>
|
||
<div class="bb-curve-wrap">
|
||
<canvas id="bb-canvas" aria-label="Diagramm der Schwarzkörperstrahlung"></canvas>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="bb-note-grid">
|
||
<div class="card bb-note">
|
||
<strong>Was zeigt die Kurve?</strong><br>
|
||
Auf der x-Achse steht die Wellenlänge in Nanometern, auf der y-Achse die spektrale Strahlungsdichte. Höhere Temperaturen verschieben das Maximum zu kleineren Wellenlängen.
|
||
</div>
|
||
<div class="card bb-note">
|
||
<strong>Wichtige Gesetze</strong><br>
|
||
Das Wiensche Verschiebungsgesetz liefert die Lage des Maximums, das Stefan-Boltzmann-Gesetz die gesamte abgestrahlte Leistung über alle Wellenlängen.
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</div>
|
||
|
||
<script>
|
||
(function () {
|
||
const PLANCK_H = 6.62607015e-34;
|
||
const LIGHT_C = 2.99792458e8;
|
||
const BOLTZMANN_K = 1.380649e-23;
|
||
const STEFAN_BOLTZMANN = 5.670374419e-8;
|
||
const WIEN_DISPLACEMENT_NM_K = 2.897771955e6;
|
||
const MIN_WAVELENGTH_NM = 100;
|
||
|
||
const temperatureInput = document.getElementById('bbTemperature');
|
||
const temperatureRange = document.getElementById('bbTemperatureRange');
|
||
const maxWavelengthInput = document.getElementById('bbMaxWavelength');
|
||
const maxWavelengthRange = document.getElementById('bbMaxWavelengthRange');
|
||
const yAxisField = document.getElementById('bbYAxisField');
|
||
const yAxisAutoInput = document.getElementById('bbYAxisAuto');
|
||
const yAxisMaxInput = document.getElementById('bbYAxisMax');
|
||
const yAxisMaxRange = document.getElementById('bbYAxisMaxRange');
|
||
const peakNmOutput = document.getElementById('bbPeakNm');
|
||
const peakRegionOutput = document.getElementById('bbPeakRegion');
|
||
const fluxOutput = document.getElementById('bbFlux');
|
||
const colorLabelOutput = document.getElementById('bbColorLabel');
|
||
const canvas = document.getElementById('bb-canvas');
|
||
const ctx = canvas.getContext('2d');
|
||
|
||
function syncPair(primary, secondary, onChange) {
|
||
primary.addEventListener('input', function () {
|
||
secondary.value = primary.value;
|
||
onChange();
|
||
});
|
||
secondary.addEventListener('input', function () {
|
||
primary.value = secondary.value;
|
||
onChange();
|
||
});
|
||
}
|
||
|
||
function clamp(value, min, max) {
|
||
return Math.min(max, Math.max(min, value));
|
||
}
|
||
|
||
function updateYAxisControls() {
|
||
const isAuto = yAxisAutoInput.checked;
|
||
yAxisMaxInput.disabled = isAuto;
|
||
yAxisMaxRange.disabled = isAuto;
|
||
yAxisField.classList.toggle('is-disabled', isAuto);
|
||
}
|
||
|
||
function planckSpectralRadiance(lambdaMeters, temperatureKelvin) {
|
||
const exponent = (PLANCK_H * LIGHT_C) / (lambdaMeters * BOLTZMANN_K * temperatureKelvin);
|
||
if (!Number.isFinite(exponent) || exponent > 700) {
|
||
return 0;
|
||
}
|
||
|
||
const numerator = 2 * PLANCK_H * Math.pow(LIGHT_C, 2);
|
||
const denominator = Math.pow(lambdaMeters, 5) * (Math.exp(exponent) - 1);
|
||
return numerator / denominator;
|
||
}
|
||
|
||
function formatGermanNumber(value, fractionDigits) {
|
||
return new Intl.NumberFormat('de-DE', {
|
||
minimumFractionDigits: fractionDigits,
|
||
maximumFractionDigits: fractionDigits
|
||
}).format(value);
|
||
}
|
||
|
||
function formatScientific(value) {
|
||
if (!Number.isFinite(value) || value <= 0) {
|
||
return '0';
|
||
}
|
||
|
||
const exponent = Math.floor(Math.log10(value));
|
||
const mantissa = value / Math.pow(10, exponent);
|
||
return formatGermanNumber(mantissa, 2) + ' × 10^' + exponent;
|
||
}
|
||
|
||
function describePeakRegion(peakNm) {
|
||
if (peakNm < 380) {
|
||
return 'Maximum im Ultraviolett';
|
||
}
|
||
if (peakNm < 450) {
|
||
return 'Maximum im violett-blauen Bereich';
|
||
}
|
||
if (peakNm < 495) {
|
||
return 'Maximum im blauen Bereich';
|
||
}
|
||
if (peakNm < 570) {
|
||
return 'Maximum im grün-gelben Bereich';
|
||
}
|
||
if (peakNm < 590) {
|
||
return 'Maximum im gelben Bereich';
|
||
}
|
||
if (peakNm < 620) {
|
||
return 'Maximum im orangefarbenen Bereich';
|
||
}
|
||
if (peakNm < 750) {
|
||
return 'Maximum im roten Bereich';
|
||
}
|
||
return 'Maximum im Infrarot';
|
||
}
|
||
|
||
function describeColor(peakNm) {
|
||
if (peakNm < 380) {
|
||
return 'bläulich bis UV-dominiert';
|
||
}
|
||
if (peakNm < 500) {
|
||
return 'bläulich';
|
||
}
|
||
if (peakNm < 570) {
|
||
return 'weißlich';
|
||
}
|
||
if (peakNm < 620) {
|
||
return 'gelblich';
|
||
}
|
||
if (peakNm < 750) {
|
||
return 'orange bis rötlich';
|
||
}
|
||
return 'rot bis infrarotdominiert';
|
||
}
|
||
|
||
function drawVisibleBand(plotLeft, plotTop, plotWidth, plotHeight, xMin, xMax) {
|
||
const visibleStart = Math.max(380, xMin);
|
||
const visibleEnd = Math.min(750, xMax);
|
||
if (visibleEnd <= visibleStart) {
|
||
return;
|
||
}
|
||
|
||
const startX = plotLeft + ((visibleStart - xMin) / (xMax - xMin)) * plotWidth;
|
||
const endX = plotLeft + ((visibleEnd - xMin) / (xMax - xMin)) * plotWidth;
|
||
const gradient = ctx.createLinearGradient(startX, 0, endX, 0);
|
||
gradient.addColorStop(0.00, 'rgba(102, 0, 255, 0.30)');
|
||
gradient.addColorStop(0.17, 'rgba(0, 90, 255, 0.30)');
|
||
gradient.addColorStop(0.34, 'rgba(0, 200, 255, 0.30)');
|
||
gradient.addColorStop(0.50, 'rgba(0, 255, 120, 0.25)');
|
||
gradient.addColorStop(0.67, 'rgba(255, 230, 0, 0.25)');
|
||
gradient.addColorStop(0.83, 'rgba(255, 140, 0, 0.28)');
|
||
gradient.addColorStop(1.00, 'rgba(255, 40, 0, 0.28)');
|
||
|
||
ctx.fillStyle = gradient;
|
||
ctx.fillRect(startX, plotTop, endX - startX, plotHeight);
|
||
}
|
||
|
||
function renderChart() {
|
||
const temperature = clamp(Number(temperatureInput.value) || 0, 100, 40000);
|
||
const maxWavelengthNm = clamp(Number(maxWavelengthInput.value) || 0, 1000, 10000);
|
||
temperatureInput.value = String(temperature);
|
||
temperatureRange.value = String(temperature);
|
||
maxWavelengthInput.value = String(maxWavelengthNm);
|
||
maxWavelengthRange.value = String(maxWavelengthNm);
|
||
|
||
const peakNm = WIEN_DISPLACEMENT_NM_K / temperature;
|
||
const totalFlux = STEFAN_BOLTZMANN * Math.pow(temperature, 4);
|
||
|
||
peakNmOutput.textContent = formatGermanNumber(peakNm, peakNm < 100 ? 1 : 0) + ' nm';
|
||
peakRegionOutput.textContent = describePeakRegion(peakNm);
|
||
fluxOutput.textContent = formatScientific(totalFlux) + ' W/m²';
|
||
colorLabelOutput.textContent = describeColor(peakNm);
|
||
|
||
const ratio = Math.min(window.devicePixelRatio || 1, 2);
|
||
const width = canvas.clientWidth;
|
||
const height = canvas.clientHeight;
|
||
canvas.width = Math.round(width * ratio);
|
||
canvas.height = Math.round(height * ratio);
|
||
ctx.setTransform(ratio, 0, 0, ratio, 0, 0);
|
||
ctx.clearRect(0, 0, width, height);
|
||
|
||
const padding = { top: 20, right: 22, bottom: 48, left: 78 };
|
||
const plotLeft = padding.left;
|
||
const plotTop = padding.top;
|
||
const plotWidth = width - padding.left - padding.right;
|
||
const plotHeight = height - padding.top - padding.bottom;
|
||
const xMin = MIN_WAVELENGTH_NM;
|
||
const xMax = maxWavelengthNm;
|
||
|
||
const samples = Math.max(320, Math.floor(plotWidth));
|
||
const points = [];
|
||
let dataMaxRadiance = 0;
|
||
|
||
for (let index = 0; index <= samples; index += 1) {
|
||
const wavelengthNm = xMin + ((xMax - xMin) * index / samples);
|
||
const radiance = planckSpectralRadiance(wavelengthNm * 1e-9, temperature);
|
||
if (radiance > dataMaxRadiance) {
|
||
dataMaxRadiance = radiance;
|
||
}
|
||
points.push({ wavelengthNm, radiance });
|
||
}
|
||
|
||
let maxRadiance = dataMaxRadiance;
|
||
if (!yAxisAutoInput.checked) {
|
||
const manualMaxRadiance = Number(yAxisMaxInput.value) || 0;
|
||
if (Number.isFinite(manualMaxRadiance) && manualMaxRadiance > 0) {
|
||
maxRadiance = manualMaxRadiance;
|
||
}
|
||
}
|
||
maxRadiance = Math.max(maxRadiance, dataMaxRadiance * 0.05, 1);
|
||
|
||
drawVisibleBand(plotLeft, plotTop, plotWidth, plotHeight, xMin, xMax);
|
||
|
||
ctx.strokeStyle = 'rgba(255,255,255,0.08)';
|
||
ctx.lineWidth = 1;
|
||
ctx.font = '11px Georgia, serif';
|
||
ctx.fillStyle = 'rgba(220, 226, 244, 0.72)';
|
||
|
||
const xTicks = [100, 250, 500, 750, 1000, 1500, 2000, 3000, 5000, 8000, 10000].filter(function (tick) {
|
||
return tick >= xMin && tick <= xMax;
|
||
});
|
||
xTicks.forEach(function (tick) {
|
||
const x = plotLeft + ((tick - xMin) / (xMax - xMin)) * plotWidth;
|
||
ctx.beginPath();
|
||
ctx.moveTo(x, plotTop);
|
||
ctx.lineTo(x, plotTop + plotHeight);
|
||
ctx.stroke();
|
||
ctx.textAlign = 'center';
|
||
ctx.textBaseline = 'top';
|
||
ctx.fillText(String(tick), x, plotTop + plotHeight + 8);
|
||
});
|
||
|
||
const yTicks = 5;
|
||
for (let tick = 0; tick <= yTicks; tick += 1) {
|
||
const value = maxRadiance * tick / yTicks;
|
||
const y = plotTop + plotHeight - (tick / yTicks) * plotHeight;
|
||
ctx.beginPath();
|
||
ctx.moveTo(plotLeft, y);
|
||
ctx.lineTo(plotLeft + plotWidth, y);
|
||
ctx.stroke();
|
||
ctx.textAlign = 'right';
|
||
ctx.textBaseline = 'middle';
|
||
ctx.fillText(formatScientific(value), plotLeft - 10, y);
|
||
}
|
||
|
||
ctx.strokeStyle = 'rgba(255,255,255,0.22)';
|
||
ctx.lineWidth = 1.2;
|
||
ctx.beginPath();
|
||
ctx.moveTo(plotLeft, plotTop);
|
||
ctx.lineTo(plotLeft, plotTop + plotHeight);
|
||
ctx.lineTo(plotLeft + plotWidth, plotTop + plotHeight);
|
||
ctx.stroke();
|
||
|
||
const areaGradient = ctx.createLinearGradient(0, plotTop, 0, plotTop + plotHeight);
|
||
areaGradient.addColorStop(0, 'rgba(201, 168, 76, 0.38)');
|
||
areaGradient.addColorStop(1, 'rgba(201, 168, 76, 0.03)');
|
||
|
||
ctx.beginPath();
|
||
points.forEach(function (point, index) {
|
||
const x = plotLeft + ((point.wavelengthNm - xMin) / (xMax - xMin)) * plotWidth;
|
||
const y = plotTop + plotHeight - ((point.radiance / maxRadiance) * plotHeight);
|
||
if (index === 0) {
|
||
ctx.moveTo(x, y);
|
||
return;
|
||
}
|
||
ctx.lineTo(x, y);
|
||
});
|
||
ctx.lineTo(plotLeft + plotWidth, plotTop + plotHeight);
|
||
ctx.lineTo(plotLeft, plotTop + plotHeight);
|
||
ctx.closePath();
|
||
ctx.fillStyle = areaGradient;
|
||
ctx.fill();
|
||
|
||
ctx.beginPath();
|
||
points.forEach(function (point, index) {
|
||
const x = plotLeft + ((point.wavelengthNm - xMin) / (xMax - xMin)) * plotWidth;
|
||
const y = plotTop + plotHeight - ((point.radiance / maxRadiance) * plotHeight);
|
||
if (index === 0) {
|
||
ctx.moveTo(x, y);
|
||
return;
|
||
}
|
||
ctx.lineTo(x, y);
|
||
});
|
||
ctx.strokeStyle = '#f0d47b';
|
||
ctx.lineWidth = 2.4;
|
||
ctx.stroke();
|
||
|
||
if (peakNm >= xMin && peakNm <= xMax) {
|
||
const peakX = plotLeft + ((peakNm - xMin) / (xMax - xMin)) * plotWidth;
|
||
ctx.beginPath();
|
||
ctx.moveTo(peakX, plotTop);
|
||
ctx.lineTo(peakX, plotTop + plotHeight);
|
||
ctx.strokeStyle = 'rgba(79, 195, 216, 0.95)';
|
||
ctx.lineWidth = 1.4;
|
||
ctx.setLineDash([6, 5]);
|
||
ctx.stroke();
|
||
ctx.setLineDash([]);
|
||
|
||
ctx.fillStyle = '#4fc3d8';
|
||
ctx.textAlign = 'left';
|
||
ctx.textBaseline = 'top';
|
||
ctx.fillText('λmax', Math.min(peakX + 6, plotLeft + plotWidth - 42), plotTop + 6);
|
||
}
|
||
|
||
ctx.fillStyle = 'rgba(240, 244, 255, 0.85)';
|
||
ctx.textAlign = 'center';
|
||
ctx.textBaseline = 'bottom';
|
||
ctx.fillText('Wellenlänge in nm', plotLeft + plotWidth / 2, height - 10);
|
||
|
||
ctx.save();
|
||
ctx.translate(18, plotTop + plotHeight / 2);
|
||
ctx.rotate(-Math.PI / 2);
|
||
ctx.textAlign = 'center';
|
||
ctx.textBaseline = 'top';
|
||
ctx.fillText('Spektrale Strahlungsdichte Bλ', 0, 0);
|
||
ctx.restore();
|
||
}
|
||
|
||
syncPair(temperatureInput, temperatureRange, renderChart);
|
||
syncPair(maxWavelengthInput, maxWavelengthRange, renderChart);
|
||
syncPair(yAxisMaxInput, yAxisMaxRange, renderChart);
|
||
|
||
yAxisAutoInput.addEventListener('change', function () {
|
||
updateYAxisControls();
|
||
renderChart();
|
||
});
|
||
|
||
document.querySelectorAll('[data-temp]').forEach(function (button) {
|
||
button.addEventListener('click', function () {
|
||
const value = button.getAttribute('data-temp') || '5778';
|
||
temperatureInput.value = value;
|
||
temperatureRange.value = value;
|
||
renderChart();
|
||
});
|
||
});
|
||
|
||
window.addEventListener('resize', renderChart);
|
||
updateYAxisControls();
|
||
renderChart();
|
||
})();
|
||
</script>
|
||
|
||
<?php require __DIR__ . '/footer.php'; ?>
|