diff --git a/frontend/js/phys-fx.js b/frontend/js/phys-fx.js index b6e012e..8da557c 100644 --- a/frontend/js/phys-fx.js +++ b/frontend/js/phys-fx.js @@ -2026,48 +2026,121 @@ class EnergyLevels { render(){ if (!this.el) return; const W = this.W, H = this.H; - const pad = 40, leftLine = 200, rightLine = W - 100; - let svg = util.svgFrame(W, H, {bg:'#fef3c7'}); - /* Уровни n=1..6 + ионизация */ + const padTop = 36, padBot = 30; + const bandW = 16, bandLeft = 4; + const leftLine = 170, rightLine = W - 80; const nMax = 6; - /* y(n) — нелинейное расположение, E пропорционально -1/n² */ + const nFrom = this.n_from, nTo = this.n_to; + function E(n){ return -13.6 / (n * n); } - function y(En){ - const minE = -13.6, maxE = 0; - return pad + (maxE - En) / (maxE - minE) * (H - 2 * pad); + function yE(En){ + const minE = -14.2, maxE = 0.4; + return padTop + (maxE - En) / (maxE - minE) * (H - padTop - padBot); } - /* Линия ионизации (E=0) */ - const y0 = y(0); - svg += ''; - svg += 'E = 0 (ионизация)'; - /* Уровни */ + + /* SVG открытие: белый фон, рамка */ + let svg = ''; + svg += ''; + + /* Заголовок */ + svg += 'Eₙ = −13,6/n² эВ'; + + /* Серии — цветные полосы между уровнями */ + const seriesBands = [ + { n1: 1, n2: 2, fill: '#ede9fe', textFill: '#6d28d9', label: 'Лайман' }, + { n1: 2, n2: 3, fill: '#dbeafe', textFill: '#1d4ed8', label: 'Бальмер' }, + { n1: 3, n2: 6, fill: '#d1fae5', textFill: '#065f46', label: 'Пашен' }, + ]; + for (const b of seriesBands){ + const yTop = yE(E(b.n2)); + const yBot = yE(E(b.n1)); + const bx = bandLeft; + const bh = yBot - yTop; + svg += ''; + /* Вертикальная метка внутри полосы */ + const ymid = ((yTop + yBot) / 2).toFixed(1); + svg += '' + b.label + ''; + } + + /* Вертикальная ось слева от уровней */ + const axisX = leftLine - 3; + svg += ''; + + /* Линия ионизации E=0 */ + const y0 = yE(0); + svg += ''; + svg += 'E = 0 (ионизация)'; + + /* Уровни n=1..6 */ for (let n = 1; n <= nMax; n++){ const En = E(n); - const yL = y(En); - const active = (n === this.n_from || n === this.n_to); - svg += ''; - svg += 'n=' + n + ''; - svg += '' + En.toFixed(2) + ' эВ'; + const yL = yE(En); + const isFrom = (n === nFrom); + const isTo = (n === nTo); + const active = isFrom || isTo; + const lineColor = isFrom ? '#4f46e5' : isTo ? '#0284c7' : '#94a3b8'; + const sw = active ? 2.4 : 1; + + /* Glow под активными */ + if (active){ + svg += ''; + } + svg += ''; + + /* Метка n= слева от оси */ + const labelX = axisX - 4; + const labelY = yL.toFixed(1); + const labelColor = isFrom ? '#4f46e5' : isTo ? '#0284c7' : '#475569'; + const labelFW = active ? '800' : '500'; + if (active){ + svg += ''; + } + svg += 'n=' + n + ''; + + /* Значения энергии справа */ + const eColor = active ? '#334155' : '#94a3b8'; + const eFW = active ? '600' : '400'; + svg += '' + En.toFixed(2) + 'эВ'; } - /* Переход — стрелка */ - if (this.n_from !== this.n_to){ - const E1 = E(this.n_from), E2 = E(this.n_to); - const y1 = y(E1), y2 = y(E2); - const xT = (leftLine + rightLine) / 2; - const color = E1 > E2 ? '#dc2626' : '#16a34a'; - svg += ''; - const dir = y2 < y1 ? -1 : 1; - svg += ''; - const dE = Math.abs(E1 - E2); - svg += 'hν = ' + dE.toFixed(2) + ' эВ'; + + /* Стрелка перехода */ + if (nFrom !== nTo){ + const Ef = E(nFrom), Et = E(nTo); + const yf = yE(Ef), yt = yE(Et); + const emission = Ef > Et; /* испускание: падаем вниз по энергии */ + const arrowColor = emission ? '#ef4444' : '#16a34a'; + const xT = leftLine + (rightLine - leftLine) * 0.42; + + /* Линия стрелки */ + svg += ''; + + /* Наконечник в точке назначения yt */ + const dir = yt < yf ? -1 : 1; /* направление стрелки */ + const tip = yt.toFixed(1); + const tipBase = (yt + 10 * dir).toFixed(1); + svg += ''; + + /* Info-box */ + const dE = Math.abs(Ef - Et); const lam = 1240 / dE; - svg += 'λ ≈ ' + lam.toFixed(0) + ' нм'; + const boxW = 88, boxH = lam >= 380 && lam <= 700 ? 48 : 40; + const yMid = (yf + yt) / 2; + let bx = xT + 10; + if (bx + boxW > W - 4) bx = xT - boxW - 10; + const boxFill = emission ? '#fff5f5' : '#f0fdf4'; + const boxStroke = emission ? '#fca5a5' : '#86efac'; + svg += ''; + svg += 'hν = ' + dE.toFixed(3) + ' эВ'; + svg += 'λ ≈ ' + lam.toFixed(0) + ' нм'; + /* Цветовая метка для видимого диапазона */ + if (lam >= 380 && lam <= 700){ + const hue = Math.round(270 - (lam - 380) / (700 - 380) * 270); + const cy = yMid - boxH / 2 + 39; + svg += ''; + svg += ''; + } } - /* Серии */ - svg += 'Лайман →'; - svg += 'Бальмер →'; - svg += 'Пашен →'; - svg += 'E_n = -13,6/n² (атом водорода)'; + svg += ''; this.el.innerHTML = svg; }