feat(phys11 ch6): Wave 10 — Глава 6 «Физика атома» (§30-§34 + Финал)
- phys-fx.js: PHYS.BohrAtom (атом водорода с орбитами + переходом + фотон), PHYS.EnergyLevels (диаграмма E_n + переход + λ) - ch6 — зелёная тема (--pri:#16a34a), watermark ⊕/n/ν/ω/L/★ - §30: открытие электрона (Томсон), опыт Резерфорда (1911), состав ядра, изотопы - §31: 2 постулата Бора (1913), E_n=-13,6/n², Боровский радиус - §32: спектры (сплошные/линейчатые/полосатые), формула Ридберга, серии Лаймана/Бальмера/Пашена - §33: спонтанное и индуцированное излучение (Эйнштейн 1916), инверсная населённость - §34: лазеры (Мейман 1960), резонатор, 4 свойства лазерного излучения, применения - 10 квизов + 5 боссов (b1-b5) + buildSingleQuizPara helper для компактности - Финал: 3 интегральных босса (fb1-fb3), +150 XP бонус, ачивка ch6_master
This commit is contained in:
@@ -1915,4 +1915,163 @@ class PlanckLinear {
|
||||
}
|
||||
P.PlanckLinear = PlanckLinear;
|
||||
|
||||
/* ============================================================ */
|
||||
/* BohrAtom — атом водорода с орбитами и переходом */
|
||||
/* ============================================================ */
|
||||
|
||||
class BohrAtom {
|
||||
constructor(container, opts){
|
||||
opts = opts || {};
|
||||
this.el = (typeof container === 'string') ? document.querySelector(container) : container;
|
||||
this.W = opts.width || 540;
|
||||
this.H = opts.height || 380;
|
||||
this.n_from = opts.n_from !== undefined ? opts.n_from : 3;
|
||||
this.n_to = opts.n_to !== undefined ? opts.n_to : 2;
|
||||
this.phase = 0;
|
||||
this.transitioning = false;
|
||||
this.t_trans = 0;
|
||||
this.paused = false;
|
||||
util.subscribe(this);
|
||||
util.observe(this);
|
||||
this._render();
|
||||
}
|
||||
setFrom(n){ this.n_from = n; this.startTransition(); }
|
||||
setTo(n){ this.n_to = n; this.startTransition(); }
|
||||
startTransition(){ this.transitioning = true; this.t_trans = 0; }
|
||||
update(dt){
|
||||
this.phase += dt * 2;
|
||||
if (this.transitioning){
|
||||
this.t_trans += dt;
|
||||
if (this.t_trans > 1.5){ this.transitioning = false; this.t_trans = 0; }
|
||||
}
|
||||
}
|
||||
render(){
|
||||
if (!this.el) return;
|
||||
const W = this.W, H = this.H;
|
||||
const cx = W / 2, cy = H / 2;
|
||||
let svg = util.svgFrame(W, H, {bg:'#0f172a'});
|
||||
/* Ядро */
|
||||
svg += '<circle cx="' + cx + '" cy="' + cy + '" r="14" fill="#dc2626" stroke="#fff" stroke-width="2"/>';
|
||||
svg += '<text x="' + cx + '" y="' + (cy + 5) + '" text-anchor="middle" font-family="JetBrains Mono,monospace" font-size="13" fill="#fff" font-weight="700">+</text>';
|
||||
/* Орбиты n = 1..5 */
|
||||
const radii = [30, 55, 85, 120, 160];
|
||||
for (let n = 0; n < 5; n++){
|
||||
const r = radii[n];
|
||||
const active = (n + 1 === this.n_from || n + 1 === this.n_to);
|
||||
svg += '<circle cx="' + cx + '" cy="' + cy + '" r="' + r + '" fill="none" stroke="' + (active ? '#fcd34d' : '#475569') + '" stroke-width="' + (active ? 1.5 : 0.8) + '" opacity="' + (active ? 0.9 : 0.5) + '"/>';
|
||||
svg += '<text x="' + (cx + r + 4) + '" y="' + (cy + 4) + '" font-family="JetBrains Mono,monospace" font-size="10" fill="#94a3b8">n=' + (n + 1) + '</text>';
|
||||
}
|
||||
/* Электрон на текущей орбите */
|
||||
let curN;
|
||||
if (this.transitioning){
|
||||
const t = Math.min(1, this.t_trans / 0.8);
|
||||
const r1 = radii[this.n_from - 1] || 30;
|
||||
const r2 = radii[this.n_to - 1] || 30;
|
||||
const r = r1 + (r2 - r1) * t;
|
||||
const a = this.phase;
|
||||
const ex = cx + r * Math.cos(a), ey = cy + r * Math.sin(a);
|
||||
svg += '<circle cx="' + ex.toFixed(1) + '" cy="' + ey.toFixed(1) + '" r="6" fill="#06b6d4" stroke="#fff" stroke-width="1.4"/>';
|
||||
curN = this.n_to;
|
||||
/* Фотон при переходе на нижний уровень */
|
||||
if (this.n_from > this.n_to && t > 0.4){
|
||||
const pt = (t - 0.4) / 0.6;
|
||||
const fx = ex + 80 * pt;
|
||||
const fy = ey - 40 * pt;
|
||||
svg += '<g><path d="M ' + ex.toFixed(1) + ' ' + ey.toFixed(1) + ' Q ' + ((ex + fx) / 2).toFixed(1) + ' ' + ((ey + fy) / 2 - 10).toFixed(1) + ' ' + fx.toFixed(1) + ' ' + fy.toFixed(1) + '" stroke="#facc15" stroke-width="2" fill="none" opacity="' + (1 - pt) + '"/>';
|
||||
svg += '<text x="' + (fx + 12).toFixed(1) + '" y="' + fy.toFixed(1) + '" font-family="JetBrains Mono,monospace" font-size="11" fill="#facc15" font-weight="700" opacity="' + (1 - pt) + '">hν</text></g>';
|
||||
}
|
||||
} else {
|
||||
const r = radii[this.n_to - 1] || 30;
|
||||
const a = this.phase;
|
||||
const ex = cx + r * Math.cos(a), ey = cy + r * Math.sin(a);
|
||||
svg += '<circle cx="' + ex.toFixed(1) + '" cy="' + ey.toFixed(1) + '" r="6" fill="#06b6d4" stroke="#fff" stroke-width="1.4"/>';
|
||||
curN = this.n_to;
|
||||
}
|
||||
/* Подписи */
|
||||
const En = -13.6 / (curN * curN);
|
||||
svg += '<text x="14" y="22" font-family="JetBrains Mono,monospace" font-size="11" fill="#cbd5e1" font-weight="700">Боровская модель атома H</text>';
|
||||
svg += '<text x="14" y="38" font-family="JetBrains Mono,monospace" font-size="10" fill="#94a3b8">n = ' + curN + ' · E = -13,6/n² = ' + En.toFixed(2) + ' эВ</text>';
|
||||
if (this.n_from !== this.n_to){
|
||||
const E_f = -13.6 / (this.n_from * this.n_from);
|
||||
const E_t = -13.6 / (this.n_to * this.n_to);
|
||||
const dE = Math.abs(E_t - E_f);
|
||||
svg += '<text x="14" y="' + (H - 26) + '" font-family="JetBrains Mono,monospace" font-size="11" fill="#fcd34d" font-weight="700">переход ' + this.n_from + ' → ' + this.n_to + '</text>';
|
||||
svg += '<text x="14" y="' + (H - 12) + '" font-family="JetBrains Mono,monospace" font-size="10" fill="#cbd5e1">hν = |E' + this.n_from + ' − E' + this.n_to + '| = ' + dE.toFixed(2) + ' эВ</text>';
|
||||
}
|
||||
svg += '</svg>';
|
||||
this.el.innerHTML = svg;
|
||||
}
|
||||
_render(){ this.render(); }
|
||||
}
|
||||
P.BohrAtom = BohrAtom;
|
||||
|
||||
/* ============================================================ */
|
||||
/* EnergyLevels — диаграмма E_n + переход */
|
||||
/* ============================================================ */
|
||||
|
||||
class EnergyLevels {
|
||||
constructor(container, opts){
|
||||
opts = opts || {};
|
||||
this.el = (typeof container === 'string') ? document.querySelector(container) : container;
|
||||
this.W = opts.width || 540;
|
||||
this.H = opts.height || 360;
|
||||
this.n_from = opts.n_from !== undefined ? opts.n_from : 4;
|
||||
this.n_to = opts.n_to !== undefined ? opts.n_to : 2;
|
||||
this.paused = true;
|
||||
this.render();
|
||||
}
|
||||
setFrom(n){ this.n_from = n; this.render(); }
|
||||
setTo(n){ this.n_to = n; this.render(); }
|
||||
update(){}
|
||||
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 nMax = 6;
|
||||
/* y(n) — нелинейное расположение, E пропорционально -1/n² */
|
||||
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);
|
||||
}
|
||||
/* Линия ионизации (E=0) */
|
||||
const y0 = y(0);
|
||||
svg += '<line x1="' + leftLine + '" y1="' + y0 + '" x2="' + rightLine + '" y2="' + y0 + '" stroke="#dc2626" stroke-width="1.6" stroke-dasharray="6 4"/>';
|
||||
svg += '<text x="' + (rightLine + 6) + '" y="' + (y0 + 4) + '" font-family="JetBrains Mono,monospace" font-size="11" fill="#dc2626" font-weight="700">E = 0 (ионизация)</text>';
|
||||
/* Уровни */
|
||||
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 += '<line x1="' + leftLine + '" y1="' + yL.toFixed(1) + '" x2="' + rightLine + '" y2="' + yL.toFixed(1) + '" stroke="' + (active ? '#dc2626' : '#475569') + '" stroke-width="' + (active ? 2 : 1.2) + '"/>';
|
||||
svg += '<text x="' + (leftLine - 8) + '" y="' + (yL + 4).toFixed(1) + '" text-anchor="end" font-family="JetBrains Mono,monospace" font-size="11" fill="' + (active ? '#dc2626' : '#0f172a') + '" font-weight="' + (active ? '700' : '600') + '">n=' + n + '</text>';
|
||||
svg += '<text x="' + (rightLine + 6) + '" y="' + (yL + 4).toFixed(1) + '" font-family="JetBrains Mono,monospace" font-size="10" fill="#475569">' + En.toFixed(2) + ' эВ</text>';
|
||||
}
|
||||
/* Переход — стрелка */
|
||||
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 += '<line x1="' + xT + '" y1="' + y1.toFixed(1) + '" x2="' + xT + '" y2="' + y2.toFixed(1) + '" stroke="' + color + '" stroke-width="2.6"/>';
|
||||
const dir = y2 < y1 ? -1 : 1;
|
||||
svg += '<polygon points="' + xT + ',' + y2.toFixed(1) + ' ' + (xT - 6) + ',' + (y2 + 10 * dir).toFixed(1) + ' ' + (xT + 6) + ',' + (y2 + 10 * dir).toFixed(1) + '" fill="' + color + '"/>';
|
||||
const dE = Math.abs(E1 - E2);
|
||||
svg += '<text x="' + (xT + 12) + '" y="' + ((y1 + y2) / 2).toFixed(1) + '" font-family="JetBrains Mono,monospace" font-size="12" fill="' + color + '" font-weight="700">hν = ' + dE.toFixed(2) + ' эВ</text>';
|
||||
const lam = 1240 / dE;
|
||||
svg += '<text x="' + (xT + 12) + '" y="' + ((y1 + y2) / 2 + 16).toFixed(1) + '" font-family="JetBrains Mono,monospace" font-size="11" fill="' + color + '">λ ≈ ' + lam.toFixed(0) + ' нм</text>';
|
||||
}
|
||||
/* Серии */
|
||||
svg += '<text x="14" y="' + (y(E(1)) + 4) + '" font-family="JetBrains Mono,monospace" font-size="10" fill="#9d174d" font-weight="700">Лайман →</text>';
|
||||
svg += '<text x="14" y="' + (y(E(2)) + 4) + '" font-family="JetBrains Mono,monospace" font-size="10" fill="#9d174d" font-weight="700">Бальмер →</text>';
|
||||
svg += '<text x="14" y="' + (y(E(3)) + 4) + '" font-family="JetBrains Mono,monospace" font-size="10" fill="#9d174d" font-weight="700">Пашен →</text>';
|
||||
svg += '<text x="' + (W/2) + '" y="22" text-anchor="middle" font-family="JetBrains Mono,monospace" font-size="11" fill="#475569" font-weight="700">E_n = -13,6/n² (атом водорода)</text>';
|
||||
svg += '</svg>';
|
||||
this.el.innerHTML = svg;
|
||||
}
|
||||
}
|
||||
P.EnergyLevels = EnergyLevels;
|
||||
|
||||
})();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user