feat(phys9 ch2): добавлены 10 виджетов Wave B — Глава 2 «Динамика»

Новый модуль frontend/js/phys9_ch2_widgets.js — экспортирует
window.PHYS9_CH2_WIDGETS = { p15..p24: fn }. Архитектура аналогична
ch1_widgets (хелперы дублируются для self-sufficient загрузки).

Виджеты:
- §15 CALC: F=Gm₁m₂/r² с slider'ами в показателях 10^a, бытовые
  аналоги (Земля-Луна, Земля-человек)
- §16 DnD: 6 планет → группы по периоду (T<1, 1≤T<5, T≥5 лет)
- §17 CALC: связь T, ν, ω с переключателем «известная величина»
- §18 CALC+VIS: a_n=v²/R + анимированная точка по окружности
  с векторами v (касательно) и a_n (к центру), пересчёт в g
- §19 CALC: F=kx закона Гука + перевод в массу подвешенного тела
- §20 DnD: 8 пар материалов → 3 группы по μ
- §21 DnD: 8 ситуаций → инерц/неинерц СО
- §22 CALC: F=ma + что будет за 1 с
- §23 CALC: g(h) для разных высот (МКС, геостационар, поверхность)
- §24 CALC: вес P=m(g+a) в лифте с классификатором режима
  (норма/перегрузка/разгон/невесомость)

Виджеты подключены в physics_9_ch2.html через тот же hook ensureBuilt.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-05-30 09:47:08 +03:00
parent 09cfaa3bd2
commit 88365a6f26
2 changed files with 378 additions and 1 deletions
+376
View File
@@ -0,0 +1,376 @@
// phys9_ch2_widgets.js — виджеты для Физики 9, Глава 2 (§15-§24): гравитация, окружн., силы.
(function(){
'use strict';
const C = () => window.PHYS9_COLORS || {};
const PI = Math.PI;
const G = 6.674e-11; /* гравитационная постоянная */
/* ====== Хелперы (дублируются с ch1 — small file) ====== */
function arrow(x1, y1, x2, y2, color, w){
const dx=x2-x1, dy=y2-y1, len=Math.hypot(dx,dy);
if(len<1e-6) return '';
const ux=dx/len, uy=dy/len, h=10, hw=6;
const bx=x2-ux*h, by=y2-uy*h;
const lx=bx-uy*hw, ly=by+ux*hw;
const rx=bx+uy*hw, ry=by-ux*hw;
return '<line x1="'+x1.toFixed(1)+'" y1="'+y1.toFixed(1)+'" x2="'+bx.toFixed(1)+'" y2="'+by.toFixed(1)+'" stroke="'+color+'" stroke-width="'+(w||2.5)+'" stroke-linecap="round"/>'
+ '<polygon points="'+x2.toFixed(1)+','+y2.toFixed(1)+' '+lx.toFixed(1)+','+ly.toFixed(1)+' '+rx.toFixed(1)+','+ry.toFixed(1)+'" fill="'+color+'"/>';
}
function dndPool(secId, items, cats){
let pool='<div class="dnd-pool" id="'+secId+'-pool" style="display:flex;flex-wrap:wrap;gap:6px;padding:10px;border:1.5px dashed var(--border);border-radius:10px;margin-bottom:10px">';
items.forEach(it=>{
pool += '<div class="dnd-chip" draggable="true" data-id="'+it.id+'" data-cat="'+it.cat+'" style="padding:6px 11px;border:1.5px solid var(--border);border-radius:9px;background:var(--card);cursor:grab;font-size:.92rem">'+it.html+'</div>';
});
pool += '</div>';
let boxes = '<div style="display:grid;grid-template-columns:repeat('+cats.length+',1fr);gap:10px">';
cats.forEach(c=>{
boxes += '<div class="drop-box" data-cat="'+c.cat+'" style="border:1.5px dashed var(--border);border-radius:10px;padding:10px;min-height:80px"><h5 style="font-size:.78rem;font-weight:800;margin-bottom:6px;color:var(--sec-acc-d,var(--pri-d))">'+c.label+'</h5><div class="drop-items"></div></div>';
});
boxes += '</div>';
return pool + boxes;
}
function wireDnd(scopeId, items){
const scope = document.querySelector('#'+scopeId);
if(!scope) return;
scope.querySelectorAll('.dnd-chip').forEach(chip=>{
chip.addEventListener('dragstart', e=>{ e.dataTransfer.setData('text/plain', chip.dataset.id); chip.style.opacity='0.5'; });
chip.addEventListener('dragend', e=>{ chip.style.opacity='1'; });
});
scope.querySelectorAll('.drop-box').forEach(box=>{
box.addEventListener('dragover', e=>{ e.preventDefault(); box.style.borderColor=C().force||'#10b981'; });
box.addEventListener('dragleave', e=>{ box.style.borderColor=''; });
box.addEventListener('drop', e=>{
e.preventDefault(); box.style.borderColor='';
const id = e.dataTransfer.getData('text/plain');
const chip = scope.querySelector('.dnd-chip[data-id="'+id+'"]');
if(chip) box.querySelector('.drop-items').appendChild(chip);
});
});
const checkBtn = scope.querySelector('.dnd-check');
if(checkBtn) checkBtn.addEventListener('click', ()=>{
let wrong = 0, total = items.length;
scope.querySelectorAll('.drop-box').forEach(box=>{
const cat = box.dataset.cat;
box.querySelectorAll('.dnd-chip').forEach(chip=>{
if(chip.dataset.cat !== cat) wrong++;
});
});
let placed = 0; scope.querySelectorAll('.drop-box .dnd-chip').forEach(()=>placed++);
const fb = scope.querySelector('.dnd-fb');
if(placed < total){ fb.className='feedback fail'; fb.innerHTML='Распредели все чипы — осталось '+(total-placed)+'.'; return; }
if(wrong===0){ fb.className='feedback ok'; fb.innerHTML='&#10003; Идеально!'; }
else { fb.className='feedback fail'; fb.innerHTML='&#10007; Ошибок: '+wrong+'.'; }
});
}
function wgWrapper(secId, badge, title, help, body){
return '<div class="wg" id="'+secId+'">'
+'<div class="wg-header"><span class="wg-badge">'+badge+'</span><div class="wg-title">'+title+'</div></div>'
+'<div class="wg-help">'+help+'</div>'+body+'</div>';
}
function appendTo(secId, html){
const box = document.getElementById(secId+'-body');
if(!box) return false;
if(box.querySelector('.wg-phys9-extra-'+secId)) return false;
const div = document.createElement('div');
div.className = 'wg-phys9-extra-'+secId;
div.innerHTML = html;
box.appendChild(div);
try { if(window.renderMathInElement) window.renderMathInElement(box); } catch(e){}
return true;
}
/* ====== §15 — Гравитация F = G m1 m2 / r² ====== */
function add_p15(){
const body = '<div class="sliders">'
+'<label>$m_1$, кг: <b id="p15w-m1">1e30</b><input type="range" id="p15w-m1-r" min="20" max="32" step="0.5" value="30"></label>'
+'<label>$m_2$, кг: <b id="p15w-m2">1e24</b><input type="range" id="p15w-m2-r" min="18" max="30" step="0.5" value="24"></label>'
+'<label>$r$, м: <b id="p15w-r">1e8</b><input type="range" id="p15w-r-r" min="6" max="12" step="0.5" value="8"></label>'
+'</div>'
+'<div class="score-display" style="flex-direction:column;align-items:flex-start;gap:5px">'
+'<span>$F = G\\dfrac{m_1 m_2}{r^2}$ = <b id="p15w-F">6.67</b> Н</span>'
+'<span style="font-size:.85rem;color:var(--muted)">Аналог: <b id="p15w-cmp">Земля-Луна</b></span>'
+'</div>';
if(appendTo('p15', wgWrapper('p15-extra', 'CALC', 'Закон всемирного тяготения', '$G = 6{,}67 \\cdot 10^{-11}$ Н·м²/кг². Slider'+"'"+'ы в показателях $10^a$.', body))){
const upd = ()=>{
const m1e = +document.getElementById('p15w-m1-r').value;
const m2e = +document.getElementById('p15w-m2-r').value;
const re = +document.getElementById('p15w-r-r').value;
const m1 = Math.pow(10, m1e); const m2 = Math.pow(10, m2e); const r = Math.pow(10, re);
document.getElementById('p15w-m1').textContent = '10^'+m1e.toFixed(1);
document.getElementById('p15w-m2').textContent = '10^'+m2e.toFixed(1);
document.getElementById('p15w-r').textContent = '10^'+re.toFixed(1);
const F = G * m1 * m2 / (r*r);
document.getElementById('p15w-F').textContent = F.toExponential(2);
let cmp = '';
if(m1e >= 29 && m2e >= 23 && re <= 9) cmp = 'Земля-Луна (~2·10²⁰ Н)';
else if(m1e >= 29 && m2e <= 21) cmp = 'Земля-человек (~700 Н)';
else if(m1e >= 30) cmp = 'Солнце-планета';
else cmp = '—';
document.getElementById('p15w-cmp').textContent = cmp;
};
['p15w-m1-r','p15w-m2-r','p15w-r-r'].forEach(id=>document.getElementById(id).addEventListener('input', upd));
upd();
}
}
/* ====== §16 — Кеплер: T² = a³ (в годах и а.е.) ====== */
function add_p16(){
const items = [
{id:'i1', cat:'fast', html:'Меркурий ($T = 0{,}24$ г)'},
{id:'i2', cat:'fast', html:'Венера ($T = 0{,}62$ г)'},
{id:'i3', cat:'med', html:'Земля ($T = 1$ г)'},
{id:'i4', cat:'med', html:'Марс ($T = 1{,}88$ г)'},
{id:'i5', cat:'slow', html:'Юпитер ($T = 11{,}9$ г)'},
{id:'i6', cat:'slow', html:'Сатурн ($T = 29{,}5$ г)'}
];
const body = dndPool('p16ex', items, [
{cat:'fast', label:'$T < 1$ г'},
{cat:'med', label:'$1 \\le T < 5$ г'},
{cat:'slow', label:'$T \\ge 5$ г'}
]) + '<div class="actions"><button class="btn primary dnd-check">Проверить</button></div>'
+ '<div class="feedback dnd-fb"></div>';
if(appendTo('p16', wgWrapper('p16-extra', 'DnD', 'Планеты по периоду', 'III закон Кеплера: чем дальше от Солнца, тем больше период.', body))){
wireDnd('p16-extra', items);
}
}
/* ====== §17 — Период, частота, угловая скорость ====== */
function add_p17(){
const body = '<div class="sliders">'
+'<label>Известно: <select id="p17w-mode" class="tinp" style="width:auto;padding:6px 10px"><option value="T">период T</option><option value="nu">частота ν</option><option value="om">угл. скор. ω</option></select></label>'
+'<label>Значение: <b id="p17w-vv">2.0</b><input type="range" id="p17w-v-r" min="0.05" max="10" step="0.05" value="2"></label>'
+'</div>'
+'<div class="score-display" style="flex-direction:column;align-items:flex-start;gap:5px">'
+'<span>$T$ = <b id="p17w-T">2.0</b> с</span>'
+'<span>$\\nu = 1/T$ = <b id="p17w-nu">0.50</b> Гц</span>'
+'<span>$\\omega = 2\\pi/T$ = <b id="p17w-om">3.14</b> рад/с</span>'
+'</div>';
if(appendTo('p17', wgWrapper('p17-extra', 'CALC', 'Связь $T$, $\\nu$, $\\omega$', '$\\nu = 1/T$, $\\omega = 2\\pi\\nu = 2\\pi/T$.', body))){
const upd = ()=>{
const mode = document.getElementById('p17w-mode').value;
const v = +document.getElementById('p17w-v-r').value;
document.getElementById('p17w-vv').textContent = v.toFixed(2);
let T, nu, om;
if(mode === 'T'){ T = v; nu = 1/T; om = 2*PI/T; }
else if(mode === 'nu'){ nu = v; T = 1/nu; om = 2*PI*nu; }
else { om = v; T = 2*PI/om; nu = 1/T; }
document.getElementById('p17w-T').textContent = T.toFixed(2);
document.getElementById('p17w-nu').textContent = nu.toFixed(2);
document.getElementById('p17w-om').textContent = om.toFixed(2);
};
document.getElementById('p17w-mode').addEventListener('change', upd);
document.getElementById('p17w-v-r').addEventListener('input', upd);
upd();
}
}
/* ====== §18 — Центростремительное ускорение ====== */
function add_p18(){
const body = '<div class="sliders">'
+'<label>$v$, м/с: <b id="p18w-v">10</b><input type="range" id="p18w-v-r" min="1" max="50" step="1" value="10"></label>'
+'<label>$R$, м: <b id="p18w-R">5</b><input type="range" id="p18w-R-r" min="0.5" max="50" step="0.5" value="5"></label>'
+'</div>'
+'<svg id="p18w-svg" viewBox="0 0 360 240" style="width:100%;height:auto;background:var(--bg-subtle,#f8fafc);border:1px solid var(--border);border-radius:9px"></svg>'
+'<div class="score-display"><span>$a_n = v^2/R$ = <b id="p18w-an">20</b> м/с²</span><span>(<b id="p18w-g">2.0</b> g)</span></div>';
if(appendTo('p18', wgWrapper('p18-extra', 'CALC+VIS', '$a_n = v^2/R$', '$\\vec a_n$ всегда направлено к центру окружности.', body))){
const cx = 180, cy = 120, R0 = 60;
const upd = ()=>{
const v = +document.getElementById('p18w-v-r').value;
const R = +document.getElementById('p18w-R-r').value;
document.getElementById('p18w-v').textContent = v;
document.getElementById('p18w-R').textContent = R;
const an = v*v/R;
document.getElementById('p18w-an').textContent = an.toFixed(1);
document.getElementById('p18w-g').textContent = (an/9.8).toFixed(2);
const col = C();
const ang = (Date.now()/1000) % (2*PI);
const tipX = cx + R0*Math.cos(ang);
const tipY = cy + R0*Math.sin(ang);
let s = '';
s += '<circle cx="'+cx+'" cy="'+cy+'" r="'+R0+'" fill="none" stroke="'+(col.grid||'#e2e8f0')+'" stroke-width="1.5" stroke-dasharray="3 3"/>';
s += '<circle cx="'+cx+'" cy="'+cy+'" r="3" fill="'+(col.text||'#0f172a')+'"/>';
s += '<circle cx="'+tipX.toFixed(1)+'" cy="'+tipY.toFixed(1)+'" r="8" fill="'+(col.body||'#475569')+'"/>';
/* v касательно (90° от радиуса) */
const vx = -Math.sin(ang), vy = Math.cos(ang);
s += arrow(tipX, tipY, tipX + vx*40, tipY + vy*40, col.velocity||'#0891b2', 2.5);
/* a_n к центру */
s += arrow(tipX, tipY, cx, cy, col.acceleration||'#ea580c', 2.5);
s += '<text x="'+(tipX+vx*44).toFixed(1)+'" y="'+(tipY+vy*44).toFixed(1)+'" font-size="13" font-weight="800" fill="'+(col.velocity||'#0891b2')+'">v</text>';
s += '<text x="'+((tipX+cx)/2-12)+'" y="'+((tipY+cy)/2-6)+'" font-size="13" font-weight="800" fill="'+(col.acceleration||'#ea580c')+'">a_n</text>';
document.getElementById('p18w-svg').innerHTML = s;
};
document.getElementById('p18w-v-r').addEventListener('input', upd);
document.getElementById('p18w-R-r').addEventListener('input', upd);
upd();
setInterval(upd, 80);
}
}
/* ====== §19 — Закон Гука F = kx ====== */
function add_p19(){
const body = '<div class="sliders">'
+'<label>$k$, Н/м: <b id="p19w-k">200</b><input type="range" id="p19w-k-r" min="20" max="2000" step="20" value="200"></label>'
+'<label>$x$, м: <b id="p19w-x">0.05</b><input type="range" id="p19w-x-r" min="0.005" max="0.5" step="0.005" value="0.05"></label>'
+'</div>'
+'<div class="score-display" style="flex-direction:column;align-items:flex-start;gap:4px">'
+'<span>$F = kx$ = <b id="p19w-F">10</b> Н</span>'
+'<span style="font-size:.85rem;color:var(--muted)">это вес тела массой <b id="p19w-m">1.02</b> кг</span>'
+'</div>';
if(appendTo('p19', wgWrapper('p19-extra', 'CALC', 'Закон Гука', 'Сила упругости пропорциональна растяжению/сжатию.', body))){
const upd = ()=>{
const k = +document.getElementById('p19w-k-r').value;
const x = +document.getElementById('p19w-x-r').value;
document.getElementById('p19w-k').textContent = k;
document.getElementById('p19w-x').textContent = x.toFixed(3);
const F = k*x;
document.getElementById('p19w-F').textContent = F.toFixed(2);
document.getElementById('p19w-m').textContent = (F/9.8).toFixed(2);
};
document.getElementById('p19w-k-r').addEventListener('input', upd);
document.getElementById('p19w-x-r').addEventListener('input', upd);
upd();
}
}
/* ====== §20 — Трение μ ====== */
function add_p20(){
const items = [
{id:'i1', cat:'h', html:'резина по сухому асфальту ($\\mu \\sim 0{,}7$)'},
{id:'i2', cat:'h', html:'дерево по дереву ($\\mu \\sim 0{,}5$)'},
{id:'i3', cat:'h', html:'кирпич по кирпичу'},
{id:'i4', cat:'m', html:'сталь по стали ($\\mu \\sim 0{,}2$)'},
{id:'i5', cat:'m', html:'паркет под обувью'},
{id:'i6', cat:'l', html:'лёд по льду ($\\mu \\sim 0{,}03$)'},
{id:'i7', cat:'l', html:'тефлон по тефлону ($\\mu \\sim 0{,}04$)'},
{id:'i8', cat:'l', html:'шина по льду'}
];
const body = dndPool('p20ex', items, [
{cat:'h', label:'Большое трение'},
{cat:'m', label:'Среднее'},
{cat:'l', label:'Малое'}
]) + '<div class="actions"><button class="btn primary dnd-check">Проверить</button></div>'
+ '<div class="feedback dnd-fb"></div>';
if(appendTo('p20', wgWrapper('p20-extra', 'DnD', 'Коэффициент трения', 'Резина-асфальт ~0,7; сталь-сталь ~0,2; лёд-лёд ~0,03.', body))){
wireDnd('p20-extra', items);
}
}
/* ====== §21 — Инерц / неинерц СО ====== */
function add_p21(){
const items = [
{id:'i1', cat:'i', html:'покоящаяся комната'},
{id:'i2', cat:'i', html:'автомобиль с $v = $ const на прямой'},
{id:'i3', cat:'i', html:'самолёт в горизонтальном полёте'},
{id:'i4', cat:'i', html:'космич. корабль с двигателями off'},
{id:'i5', cat:'n', html:'разгоняющийся автобус'},
{id:'i6', cat:'n', html:'тормозящий поезд'},
{id:'i7', cat:'n', html:'карусель'},
{id:'i8', cat:'n', html:'центрифуга'}
];
const body = dndPool('p21ex', items, [
{cat:'i', label:'Инерц. СО'},
{cat:'n', label:'Неинерц. СО'}
]) + '<div class="actions"><button class="btn primary dnd-check">Проверить</button></div>'
+ '<div class="feedback dnd-fb"></div>';
if(appendTo('p21', wgWrapper('p21-extra', 'DnD', 'Инерциальная или нет?', 'Инерциальная — где $\\vec a = 0$ (тело покоится или движется равномерно прямолинейно).', body))){
wireDnd('p21-extra', items);
}
}
/* ====== §22 — F = ma ====== */
function add_p22(){
const body = '<div class="sliders">'
+'<label>$F$, Н: <b id="p22w-F">50</b><input type="range" id="p22w-F-r" min="5" max="500" step="5" value="50"></label>'
+'<label>$m$, кг: <b id="p22w-m">10</b><input type="range" id="p22w-m-r" min="0.5" max="100" step="0.5" value="10"></label>'
+'</div>'
+'<div class="score-display" style="flex-direction:column;align-items:flex-start;gap:5px">'
+'<span>$a = F/m$ = <b id="p22w-a">5.00</b> м/с²</span>'
+'<span>За 1 с скорость возрастёт на <b id="p22w-dv">5.0</b> м/с</span>'
+'</div>';
if(appendTo('p22', wgWrapper('p22-extra', 'CALC', '2-й закон Ньютона', 'Удвой силу — удвоится ускорение. Удвой массу — ускорение упадёт в 2 раза.', body))){
const upd = ()=>{
const F = +document.getElementById('p22w-F-r').value;
const m = +document.getElementById('p22w-m-r').value;
document.getElementById('p22w-F').textContent = F;
document.getElementById('p22w-m').textContent = m;
const a = F/m;
document.getElementById('p22w-a').textContent = a.toFixed(2);
document.getElementById('p22w-dv').textContent = a.toFixed(2);
};
document.getElementById('p22w-F-r').addEventListener('input', upd);
document.getElementById('p22w-m-r').addEventListener('input', upd);
upd();
}
}
/* ====== §23 — g на разных высотах ====== */
function add_p23(){
const body = '<div class="sliders">'
+'<label>Высота $h$, км: <b id="p23w-h">0</b><input type="range" id="p23w-h-r" min="0" max="50000" step="100" value="0"></label>'
+'</div>'
+'<div class="score-display" style="flex-direction:column;align-items:flex-start;gap:5px">'
+'<span>$g(h) = GM/(R+h)^2$ = <b id="p23w-g">9.80</b> м/с²</span>'
+'<span style="font-size:.85rem;color:var(--muted)">место: <b id="p23w-loc">поверхность Земли</b></span>'
+'</div>';
if(appendTo('p23', wgWrapper('p23-extra', 'CALC', '$g$ на разных высотах', '$g$ уменьшается с высотой как $1/(R+h)^2$.', body))){
const upd = ()=>{
const h_km = +document.getElementById('p23w-h-r').value;
const h = h_km * 1000;
const R = 6.371e6, M = 5.972e24;
const g = G * M / Math.pow(R+h, 2);
document.getElementById('p23w-h').textContent = h_km;
document.getElementById('p23w-g').textContent = g.toFixed(2);
let loc = 'поверхность Земли';
if(h_km > 30000) loc = 'геостационарная орбита (~36000 км)';
else if(h_km > 8000) loc = 'дальняя орбита';
else if(h_km > 1000) loc = 'высокая орбита';
else if(h_km > 400) loc = 'МКС орбита (~408 км)';
else if(h_km > 100) loc = 'низкая орбита';
else if(h_km > 10) loc = 'стратосфера';
else if(h_km > 0) loc = 'тропосфера';
document.getElementById('p23w-loc').textContent = loc;
};
document.getElementById('p23w-h-r').addEventListener('input', upd);
upd();
}
}
/* ====== §24 — Вес в лифте ====== */
function add_p24(){
const body = '<div class="sliders">'
+'<label>$m$, кг: <b id="p24w-m">70</b><input type="range" id="p24w-m-r" min="10" max="150" step="1" value="70"></label>'
+'<label>$a$ лифта, м/с² (вверх+): <b id="p24w-a">0</b><input type="range" id="p24w-a-r" min="-20" max="20" step="0.5" value="0"></label>'
+'</div>'
+'<div class="score-display" style="flex-direction:column;align-items:flex-start;gap:5px">'
+'<span>Вес $P = m(g + a)$ = <b id="p24w-P">686</b> Н</span>'
+'<span style="font-size:.85rem"><b id="p24w-mode">НОРМАЛЬНЫЙ ВЕС</b></span>'
+'</div>';
if(appendTo('p24', wgWrapper('p24-extra', 'CALC', 'Вес в лифте', '$a > 0$ — разгон вверх (перегрузка). $a < 0$ — свободное падение (невесомость при $a = -g$).', body))){
const upd = ()=>{
const m = +document.getElementById('p24w-m-r').value;
const a = +document.getElementById('p24w-a-r').value;
document.getElementById('p24w-m').textContent = m;
document.getElementById('p24w-a').textContent = a;
const g = 9.8;
const P = m*(g+a);
document.getElementById('p24w-P').textContent = P.toFixed(0);
const mode = document.getElementById('p24w-mode');
if(Math.abs(P) < 5){ mode.textContent = 'НЕВЕСОМОСТЬ'; mode.style.color = 'var(--warn,#f59e0b)'; }
else if(P < 0){ mode.textContent = 'ОТРИЦАТЕЛЬНЫЙ ВЕС (пол давит вниз)'; mode.style.color = 'var(--fail,#dc2626)'; }
else if(P > m*g*1.5){ mode.textContent = 'ПЕРЕГРУЗКА '+(P/(m*g)).toFixed(1)+'g'; mode.style.color = 'var(--fail,#dc2626)'; }
else if(P > m*g*1.05){ mode.textContent = 'РАЗГОН ВВЕРХ ('+(P/(m*g)).toFixed(2)+'g)'; mode.style.color = 'var(--warn,#f59e0b)'; }
else if(P < m*g*0.95){ mode.textContent = 'РАЗГОН ВНИЗ ('+(P/(m*g)).toFixed(2)+'g)'; mode.style.color = 'var(--warn,#f59e0b)'; }
else { mode.textContent = 'НОРМАЛЬНЫЙ ВЕС'; mode.style.color = 'var(--ok,#10b981)'; }
};
document.getElementById('p24w-m-r').addEventListener('input', upd);
document.getElementById('p24w-a-r').addEventListener('input', upd);
upd();
}
}
window.PHYS9_CH2_WIDGETS = {
p15:add_p15, p16:add_p16, p17:add_p17, p18:add_p18, p19:add_p19,
p20:add_p20, p21:add_p21, p22:add_p22, p23:add_p23, p24:add_p24
};
})();
+2 -1
View File
@@ -17,6 +17,7 @@
<script src="/js/phys.js" defer></script>
<script src="/js/phys9_palette.js" defer></script>
<script src="/js/phys9_legacy.js" defer></script>
<script src="/js/phys9_ch2_widgets.js" defer></script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Manrope:wght@600;700;800;900&family=Unbounded:wght@700;800;900&family=JetBrains+Mono:wght@500;700&display=swap" rel="stylesheet">
<style>
:root{
@@ -786,7 +787,7 @@ function _injectTasks(id){
var body = document.getElementById(id + '-body');
if(!body || body.querySelector('.legacy-tasks')) return;
body.insertAdjacentHTML('beforeend', _makeTaskBlock(id));
setTimeout(function(){ try { if(window.renderTask) window.renderTask(id); if(window.renderNav) window.renderNav(id); } catch(e){} }, 60);
setTimeout(function(){ try { if(window.renderTask) window.renderTask(id); if(window.renderNav) window.renderNav(id); } catch(e){} try { if(window.PHYS9_CH2_WIDGETS && window.PHYS9_CH2_WIDGETS[id]) window.PHYS9_CH2_WIDGETS[id](); } catch(e){ console.warn('phys9 widget init:', e.message); } }, 60);
}
var _origEnsureBuilt = ensureBuilt;
ensureBuilt = function(id){ _origEnsureBuilt(id); _injectTasks(id); };