5b075cde86
Новый модуль frontend/js/phys9_finals.js:
1. РАСШИРЯЕТ window.checkNum чтобы поддерживать сигнатуру
(id, answer, unit, tol) — раньше legacy checkNum принимал только
sec для POOLS, из-за чего кнопки «Проверить» в финалах не работали.
2. ПРОГРЕСС-БАР под заголовком каждого finalN:
- Подсчитывает количество <input id="fin1-q1"...> в финале
- При правильном ответе обновляет % решённых
- +8 XP за каждую решённую задачу
3. АЧИВКИ:
- При 100% решённых задач финала — +50 XP + бэйдж
«★ МАСТЕР ГЛАВЫ» (физика9_chN_master)
- При всех 5 финалах — +150 XP + ачивка «МАГИСТР ФИЗИКИ 9»
(Wave G — финал курса)
Подключение во все 5 ch + хук на ensureBuilt вызывает
PHYS9_FINALS_INIT(id) для id вида final1..final5.
(linter добавил { delimiters, throwOnError:false } в renderMathInElement
вызовы во всех 5 widget-модулях — сохранено).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
430 lines
25 KiB
JavaScript
430 lines
25 KiB
JavaScript
// phys9_ch5_widgets.js — виджеты для Физики 9, Глава 5 (ЛР 1-12).
|
||
(function(){
|
||
'use strict';
|
||
|
||
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, { delimiters: [{left:'$$',right:'$$',display:true},{left:'$',right:'$',display:false}], throwOnError:false }); } catch(e){}
|
||
return true;
|
||
}
|
||
function wireSubmit(id){
|
||
const btn = document.getElementById(id+'-sub'); if(!btn) return;
|
||
btn.addEventListener('click', ()=>{
|
||
const fb = document.getElementById(id+'-fb');
|
||
fb.className='feedback ok';
|
||
fb.innerHTML='✓ Работа сдана! +30 XP. Молодец, лаборант!';
|
||
btn.disabled = true; btn.style.opacity = 0.6;
|
||
try { if(window.addXp) window.addXp(30, id); } catch(e){}
|
||
});
|
||
}
|
||
|
||
/* === ЛР 1. Определение средней скорости === */
|
||
function add_lr1(){
|
||
const body = '<div class="sliders">'
|
||
+'<label>$s_1$ м: <b id="lr1w-s1">1.0</b><input type="range" id="lr1w-s1-r" min="0.2" max="3" step="0.1" value="1"></label>'
|
||
+'<label>$t_1$ с: <b id="lr1w-t1">2.0</b><input type="range" id="lr1w-t1-r" min="0.5" max="5" step="0.1" value="2"></label>'
|
||
+'<label>$s_2$ м: <b id="lr1w-s2">2.0</b><input type="range" id="lr1w-s2-r" min="0.2" max="5" step="0.1" value="2"></label>'
|
||
+'<label>$t_2$ с: <b id="lr1w-t2">3.0</b><input type="range" id="lr1w-t2-r" min="0.5" max="6" step="0.1" value="3"></label>'
|
||
+'</div>'
|
||
+'<div class="score-display" style="flex-direction:column;align-items:flex-start;gap:4px">'
|
||
+'<span>Полный путь $s$ = <b id="lr1w-s">3.0</b> м, время $t$ = <b id="lr1w-t">5.0</b> с</span>'
|
||
+'<span>$\\langle v\\rangle = s/t$ = <b id="lr1w-vv">0.60</b> м/с</span>'
|
||
+'</div>'
|
||
+'<div class="actions"><button class="btn primary" id="lr1-sub">Сдать работу (+30 XP)</button></div>'
|
||
+'<div class="feedback" id="lr1-fb"></div>';
|
||
if(appendTo('lr1', wgWrapper('lr1-extra', 'ЛР 1', 'Определение средней скорости', 'Засеки время на 2 участках, рассчитай среднюю скорость.', body))){
|
||
const upd = ()=>{
|
||
const s1 = +document.getElementById('lr1w-s1-r').value;
|
||
const t1 = +document.getElementById('lr1w-t1-r').value;
|
||
const s2 = +document.getElementById('lr1w-s2-r').value;
|
||
const t2 = +document.getElementById('lr1w-t2-r').value;
|
||
document.getElementById('lr1w-s1').textContent = s1.toFixed(2);
|
||
document.getElementById('lr1w-t1').textContent = t1.toFixed(2);
|
||
document.getElementById('lr1w-s2').textContent = s2.toFixed(2);
|
||
document.getElementById('lr1w-t2').textContent = t2.toFixed(2);
|
||
const s = s1+s2, t = t1+t2;
|
||
document.getElementById('lr1w-s').textContent = s.toFixed(2);
|
||
document.getElementById('lr1w-t').textContent = t.toFixed(2);
|
||
document.getElementById('lr1w-vv').textContent = (s/t).toFixed(2);
|
||
};
|
||
['lr1w-s1-r','lr1w-t1-r','lr1w-s2-r','lr1w-t2-r'].forEach(id=>document.getElementById(id).addEventListener('input', upd));
|
||
upd();
|
||
wireSubmit('lr1');
|
||
}
|
||
}
|
||
|
||
/* === ЛР 2. Изучение равноускоренного движения === */
|
||
function add_lr2(){
|
||
const body = '<div class="sliders">'
|
||
+'<label>Длина 1: $s_1$ м: <b id="lr2w-s1">0.5</b><input type="range" id="lr2w-s1-r" min="0.1" max="2" step="0.05" value="0.5"></label>'
|
||
+'<label>$t_1$ с: <b id="lr2w-t1">1.0</b><input type="range" id="lr2w-t1-r" min="0.2" max="3" step="0.05" value="1"></label>'
|
||
+'<label>Длина 2: $s_2$ м: <b id="lr2w-s2">2.0</b><input type="range" id="lr2w-s2-r" min="0.5" max="5" step="0.1" value="2"></label>'
|
||
+'<label>$t_2$ с: <b id="lr2w-t2">2.0</b><input type="range" id="lr2w-t2-r" min="0.5" max="5" step="0.05" value="2"></label>'
|
||
+'</div>'
|
||
+'<div class="score-display" style="flex-direction:column;align-items:flex-start;gap:4px">'
|
||
+'<span>$a = 2 s_1 / t_1^2$ = <b id="lr2w-a1">1.0</b> м/с² (по 1-му)</span>'
|
||
+'<span>$a = 2 s_2 / t_2^2$ = <b id="lr2w-a2">1.0</b> м/с² (по 2-му)</span>'
|
||
+'<span>Среднее: $a$ = <b id="lr2w-a">1.0</b> м/с²</span>'
|
||
+'</div>'
|
||
+'<div class="actions"><button class="btn primary" id="lr2-sub">Сдать работу (+30 XP)</button></div>'
|
||
+'<div class="feedback" id="lr2-fb"></div>';
|
||
if(appendTo('lr2', wgWrapper('lr2-extra', 'ЛР 2', 'Равноускоренное движение', 'Тележка скатывается с начала и проходит $s_1$ за $t_1$, потом $s_2$ за $t_2$ от старта. $a = 2s/t^2$.', body))){
|
||
const upd = ()=>{
|
||
const s1 = +document.getElementById('lr2w-s1-r').value;
|
||
const t1 = +document.getElementById('lr2w-t1-r').value;
|
||
const s2 = +document.getElementById('lr2w-s2-r').value;
|
||
const t2 = +document.getElementById('lr2w-t2-r').value;
|
||
document.getElementById('lr2w-s1').textContent = s1.toFixed(2);
|
||
document.getElementById('lr2w-t1').textContent = t1.toFixed(2);
|
||
document.getElementById('lr2w-s2').textContent = s2.toFixed(2);
|
||
document.getElementById('lr2w-t2').textContent = t2.toFixed(2);
|
||
const a1 = 2*s1/(t1*t1), a2 = 2*s2/(t2*t2);
|
||
document.getElementById('lr2w-a1').textContent = a1.toFixed(2);
|
||
document.getElementById('lr2w-a2').textContent = a2.toFixed(2);
|
||
document.getElementById('lr2w-a').textContent = ((a1+a2)/2).toFixed(2);
|
||
};
|
||
['lr2w-s1-r','lr2w-t1-r','lr2w-s2-r','lr2w-t2-r'].forEach(id=>document.getElementById(id).addEventListener('input', upd));
|
||
upd();
|
||
wireSubmit('lr2');
|
||
}
|
||
}
|
||
|
||
/* === ЛР 3. Движение по окружности === */
|
||
function add_lr3(){
|
||
const body = '<div class="sliders">'
|
||
+'<label>$R$ м: <b id="lr3w-R">0.3</b><input type="range" id="lr3w-R-r" min="0.05" max="2" step="0.05" value="0.3"></label>'
|
||
+'<label>10 оборотов за $t$ с: <b id="lr3w-t">5</b><input type="range" id="lr3w-t-r" min="1" max="30" step="0.5" value="5"></label>'
|
||
+'</div>'
|
||
+'<div class="score-display" style="flex-direction:column;align-items:flex-start;gap:4px">'
|
||
+'<span>$T$ = $t$/10 = <b id="lr3w-T">0.50</b> с</span>'
|
||
+'<span>$v$ = $2\\pi R/T$ = <b id="lr3w-v">3.77</b> м/с</span>'
|
||
+'<span>$a_n$ = $v^2/R$ = <b id="lr3w-an">47</b> м/с²</span>'
|
||
+'</div>'
|
||
+'<div class="actions"><button class="btn primary" id="lr3-sub">Сдать работу (+30 XP)</button></div>'
|
||
+'<div class="feedback" id="lr3-fb"></div>';
|
||
if(appendTo('lr3', wgWrapper('lr3-extra', 'ЛР 3', 'Движение по окружности', 'Измерь время 10 оборотов шарика на нити длиной $R$.', body))){
|
||
const upd = ()=>{
|
||
const R = +document.getElementById('lr3w-R-r').value;
|
||
const t = +document.getElementById('lr3w-t-r').value;
|
||
document.getElementById('lr3w-R').textContent = R.toFixed(2);
|
||
document.getElementById('lr3w-t').textContent = t.toFixed(2);
|
||
const T = t/10;
|
||
const v = 2*Math.PI*R/T;
|
||
const an = v*v/R;
|
||
document.getElementById('lr3w-T').textContent = T.toFixed(2);
|
||
document.getElementById('lr3w-v').textContent = v.toFixed(2);
|
||
document.getElementById('lr3w-an').textContent = an.toFixed(1);
|
||
};
|
||
document.getElementById('lr3w-R-r').addEventListener('input', upd);
|
||
document.getElementById('lr3w-t-r').addEventListener('input', upd);
|
||
upd();
|
||
wireSubmit('lr3');
|
||
}
|
||
}
|
||
|
||
/* === ЛР 4. Маятник, нахождение g === */
|
||
function add_lr4(){
|
||
const body = '<div class="sliders">'
|
||
+'<label>$l$ нить, м: <b id="lr4w-l">1.0</b><input type="range" id="lr4w-l-r" min="0.1" max="3" step="0.05" value="1"></label>'
|
||
+'<label>10 колебаний за $t$ с: <b id="lr4w-t">20.1</b><input type="range" id="lr4w-t-r" min="5" max="40" step="0.1" value="20.1"></label>'
|
||
+'</div>'
|
||
+'<div class="score-display" style="flex-direction:column;align-items:flex-start;gap:4px">'
|
||
+'<span>$T$ = $t/10$ = <b id="lr4w-T">2.01</b> с</span>'
|
||
+'<span>$g = 4\\pi^2 l / T^2$ = <b id="lr4w-g">9.77</b> м/с²</span>'
|
||
+'<span>Эталон: $9{,}81$ м/с². Погрешность: <b id="lr4w-err">0.4</b>%</span>'
|
||
+'</div>'
|
||
+'<div class="actions"><button class="btn primary" id="lr4-sub">Сдать работу (+30 XP)</button></div>'
|
||
+'<div class="feedback" id="lr4-fb"></div>';
|
||
if(appendTo('lr4', wgWrapper('lr4-extra', 'ЛР 4', 'Определение $g$ маятником', 'Засеки время 10 полных колебаний, рассчитай $g$.', body))){
|
||
const upd = ()=>{
|
||
const l = +document.getElementById('lr4w-l-r').value;
|
||
const t = +document.getElementById('lr4w-t-r').value;
|
||
document.getElementById('lr4w-l').textContent = l.toFixed(2);
|
||
document.getElementById('lr4w-t').textContent = t.toFixed(1);
|
||
const T = t/10;
|
||
const g = 4*Math.PI*Math.PI*l/(T*T);
|
||
const err = Math.abs(g - 9.81)/9.81*100;
|
||
document.getElementById('lr4w-T').textContent = T.toFixed(2);
|
||
document.getElementById('lr4w-g').textContent = g.toFixed(2);
|
||
document.getElementById('lr4w-err').textContent = err.toFixed(1);
|
||
};
|
||
document.getElementById('lr4w-l-r').addEventListener('input', upd);
|
||
document.getElementById('lr4w-t-r').addEventListener('input', upd);
|
||
upd();
|
||
wireSubmit('lr4');
|
||
}
|
||
}
|
||
|
||
/* === ЛР 5. Сила тяги на наклонной === */
|
||
function add_lr5(){
|
||
const body = '<div class="sliders">'
|
||
+'<label>$m$ груза, кг: <b id="lr5w-m">0.2</b><input type="range" id="lr5w-m-r" min="0.05" max="2" step="0.05" value="0.2"></label>'
|
||
+'<label>Угол $\\alpha$, °: <b id="lr5w-a">30</b><input type="range" id="lr5w-a-r" min="10" max="60" step="1" value="30"></label>'
|
||
+'</div>'
|
||
+'<div class="score-display" style="flex-direction:column;align-items:flex-start;gap:4px">'
|
||
+'<span>Сила тяжести $P = mg$ = <b id="lr5w-P">1.96</b> Н</span>'
|
||
+'<span>Проекция вдоль накл.: $F_\\parallel = mg\\sin\\alpha$ = <b id="lr5w-Fp">0.98</b> Н</span>'
|
||
+'<span>Прижим: $F_\\perp = mg\\cos\\alpha$ = <b id="lr5w-Fn">1.70</b> Н</span>'
|
||
+'</div>'
|
||
+'<div class="actions"><button class="btn primary" id="lr5-sub">Сдать работу (+30 XP)</button></div>'
|
||
+'<div class="feedback" id="lr5-fb"></div>';
|
||
if(appendTo('lr5', wgWrapper('lr5-extra', 'ЛР 5', 'Силы на наклонной плоскости', 'Изменяй угол, наблюдай как меняются $F_\\parallel$ и $F_\\perp$.', body))){
|
||
const upd = ()=>{
|
||
const m = +document.getElementById('lr5w-m-r').value;
|
||
const a = +document.getElementById('lr5w-a-r').value;
|
||
document.getElementById('lr5w-m').textContent = m.toFixed(2);
|
||
document.getElementById('lr5w-a').textContent = a;
|
||
const g = 9.8;
|
||
const P = m*g;
|
||
const Fp = P*Math.sin(a*Math.PI/180);
|
||
const Fn = P*Math.cos(a*Math.PI/180);
|
||
document.getElementById('lr5w-P').textContent = P.toFixed(2);
|
||
document.getElementById('lr5w-Fp').textContent = Fp.toFixed(2);
|
||
document.getElementById('lr5w-Fn').textContent = Fn.toFixed(2);
|
||
};
|
||
document.getElementById('lr5w-m-r').addEventListener('input', upd);
|
||
document.getElementById('lr5w-a-r').addEventListener('input', upd);
|
||
upd();
|
||
wireSubmit('lr5');
|
||
}
|
||
}
|
||
|
||
/* === ЛР 6. Свободное падение g = 2h/t² === */
|
||
function add_lr6(){
|
||
const body = '<div class="sliders">'
|
||
+'<label>$h$ высота, м: <b id="lr6w-h">2.0</b><input type="range" id="lr6w-h-r" min="0.5" max="10" step="0.1" value="2"></label>'
|
||
+'<label>$t$ время, с: <b id="lr6w-t">0.64</b><input type="range" id="lr6w-t-r" min="0.2" max="2" step="0.01" value="0.64"></label>'
|
||
+'</div>'
|
||
+'<div class="score-display" style="flex-direction:column;align-items:flex-start;gap:4px">'
|
||
+'<span>$g = 2h/t^2$ = <b id="lr6w-g">9.77</b> м/с²</span>'
|
||
+'<span>Эталон: $9{,}81$. Погрешность: <b id="lr6w-err">0.4</b>%</span>'
|
||
+'</div>'
|
||
+'<div class="actions"><button class="btn primary" id="lr6-sub">Сдать работу (+30 XP)</button></div>'
|
||
+'<div class="feedback" id="lr6-fb"></div>';
|
||
if(appendTo('lr6', wgWrapper('lr6-extra', 'ЛР 6', 'Свободное падение', 'Сбрось предмет, засеки время. $g = 2h/t^2$.', body))){
|
||
const upd = ()=>{
|
||
const h = +document.getElementById('lr6w-h-r').value;
|
||
const t = +document.getElementById('lr6w-t-r').value;
|
||
document.getElementById('lr6w-h').textContent = h.toFixed(2);
|
||
document.getElementById('lr6w-t').textContent = t.toFixed(2);
|
||
const g = 2*h/(t*t);
|
||
const err = Math.abs(g-9.81)/9.81*100;
|
||
document.getElementById('lr6w-g').textContent = g.toFixed(2);
|
||
document.getElementById('lr6w-err').textContent = err.toFixed(1);
|
||
};
|
||
document.getElementById('lr6w-h-r').addEventListener('input', upd);
|
||
document.getElementById('lr6w-t-r').addEventListener('input', upd);
|
||
upd();
|
||
wireSubmit('lr6');
|
||
}
|
||
}
|
||
|
||
/* === ЛР 7. Закон сохранения механической энергии === */
|
||
function add_lr7(){
|
||
const body = '<div class="sliders">'
|
||
+'<label>$m$ кг: <b id="lr7w-m">0.1</b><input type="range" id="lr7w-m-r" min="0.05" max="2" step="0.05" value="0.1"></label>'
|
||
+'<label>$h$ м: <b id="lr7w-h">0.5</b><input type="range" id="lr7w-h-r" min="0.1" max="3" step="0.05" value="0.5"></label>'
|
||
+'<label>Измер. $v_{внизу}$: <b id="lr7w-v">3.0</b><input type="range" id="lr7w-v-r" min="0.5" max="10" step="0.05" value="3"></label>'
|
||
+'</div>'
|
||
+'<div class="score-display" style="flex-direction:column;align-items:flex-start;gap:4px">'
|
||
+'<span>$E_p^{старт} = mgh$ = <b id="lr7w-Ep">0.49</b> Дж</span>'
|
||
+'<span>$E_k^{внизу} = mv^2/2$ = <b id="lr7w-Ek">0.45</b> Дж</span>'
|
||
+'<span>Сохранение: <b id="lr7w-cons">8%</b> потерь</span>'
|
||
+'</div>'
|
||
+'<div class="actions"><button class="btn primary" id="lr7-sub">Сдать работу (+30 XP)</button></div>'
|
||
+'<div class="feedback" id="lr7-fb"></div>';
|
||
if(appendTo('lr7', wgWrapper('lr7-extra', 'ЛР 7', 'ЗСЭ на горке', 'Сравни $E_p$ вверху и $E_k$ внизу.', body))){
|
||
const upd = ()=>{
|
||
const m = +document.getElementById('lr7w-m-r').value;
|
||
const h = +document.getElementById('lr7w-h-r').value;
|
||
const v = +document.getElementById('lr7w-v-r').value;
|
||
document.getElementById('lr7w-m').textContent = m.toFixed(2);
|
||
document.getElementById('lr7w-h').textContent = h.toFixed(2);
|
||
document.getElementById('lr7w-v').textContent = v.toFixed(2);
|
||
const Ep = m*9.8*h;
|
||
const Ek = m*v*v/2;
|
||
document.getElementById('lr7w-Ep').textContent = Ep.toFixed(2);
|
||
document.getElementById('lr7w-Ek').textContent = Ek.toFixed(2);
|
||
const loss = Math.max(0, (Ep-Ek)/Ep*100);
|
||
document.getElementById('lr7w-cons').textContent = loss.toFixed(0)+'% потерь';
|
||
};
|
||
['lr7w-m-r','lr7w-h-r','lr7w-v-r'].forEach(id=>document.getElementById(id).addEventListener('input', upd));
|
||
upd();
|
||
wireSubmit('lr7');
|
||
}
|
||
}
|
||
|
||
/* === ЛР 8. Закон Архимеда === */
|
||
function add_lr8(){
|
||
const body = '<div class="sliders">'
|
||
+'<label>Вес в воздухе $P_1$, Н: <b id="lr8w-P1">2.0</b><input type="range" id="lr8w-P1-r" min="0.5" max="10" step="0.1" value="2"></label>'
|
||
+'<label>Вес в воде $P_2$, Н: <b id="lr8w-P2">1.5</b><input type="range" id="lr8w-P2-r" min="0.1" max="10" step="0.1" value="1.5"></label>'
|
||
+'</div>'
|
||
+'<div class="score-display" style="flex-direction:column;align-items:flex-start;gap:4px">'
|
||
+'<span>$F_A = P_1 - P_2$ = <b id="lr8w-Fa">0.50</b> Н</span>'
|
||
+'<span>$V = F_A/(\\rho g) = $ <b id="lr8w-V">51</b> см³</span>'
|
||
+'</div>'
|
||
+'<div class="actions"><button class="btn primary" id="lr8-sub">Сдать работу (+30 XP)</button></div>'
|
||
+'<div class="feedback" id="lr8-fb"></div>';
|
||
if(appendTo('lr8', wgWrapper('lr8-extra', 'ЛР 8', 'Закон Архимеда', 'Взвешиваем тело в воздухе и в воде, находим $F_A$ и $V$.', body))){
|
||
const upd = ()=>{
|
||
const P1 = +document.getElementById('lr8w-P1-r').value;
|
||
const P2 = +document.getElementById('lr8w-P2-r').value;
|
||
document.getElementById('lr8w-P1').textContent = P1.toFixed(2);
|
||
document.getElementById('lr8w-P2').textContent = P2.toFixed(2);
|
||
const Fa = Math.max(0, P1-P2);
|
||
const V_m3 = Fa/(1000*9.8);
|
||
document.getElementById('lr8w-Fa').textContent = Fa.toFixed(2);
|
||
document.getElementById('lr8w-V').textContent = (V_m3*1e6).toFixed(0);
|
||
};
|
||
document.getElementById('lr8w-P1-r').addEventListener('input', upd);
|
||
document.getElementById('lr8w-P2-r').addEventListener('input', upd);
|
||
upd();
|
||
wireSubmit('lr8');
|
||
}
|
||
}
|
||
|
||
/* === ЛР 9. Плавание тел === */
|
||
function add_lr9(){
|
||
const body = '<div class="sliders">'
|
||
+'<label>$\\rho_{тела}$, кг/м³: <b id="lr9w-rt">700</b><input type="range" id="lr9w-rt-r" min="100" max="15000" step="50" value="700"></label>'
|
||
+'<label>$\\rho_{жидк}$, кг/м³: <b id="lr9w-rl">1000</b><input type="range" id="lr9w-rl-r" min="500" max="14000" step="50" value="1000"></label>'
|
||
+'</div>'
|
||
+'<div class="score-display" style="flex-direction:column;align-items:flex-start;gap:4px">'
|
||
+'<span>Доля погружения: <b id="lr9w-h">70</b>%</span>'
|
||
+'<span><b id="lr9w-r" style="color:var(--ok)">ПЛАВАЕТ ↑</b></span>'
|
||
+'</div>'
|
||
+'<div class="actions"><button class="btn primary" id="lr9-sub">Сдать работу (+30 XP)</button></div>'
|
||
+'<div class="feedback" id="lr9-fb"></div>';
|
||
if(appendTo('lr9', wgWrapper('lr9-extra', 'ЛР 9', 'Условие плавания', '$h_{погр}/h_{тела} = \\rho_{тела}/\\rho_{жидк}$.', body))){
|
||
const upd = ()=>{
|
||
const rt = +document.getElementById('lr9w-rt-r').value;
|
||
const rl = +document.getElementById('lr9w-rl-r').value;
|
||
document.getElementById('lr9w-rt').textContent = rt;
|
||
document.getElementById('lr9w-rl').textContent = rl;
|
||
const h = (rt/rl)*100;
|
||
document.getElementById('lr9w-h').textContent = Math.min(100, h).toFixed(0);
|
||
const r = document.getElementById('lr9w-r');
|
||
if(rt < rl){ r.innerHTML='ПЛАВАЕТ ↑'; r.style.color='var(--ok,#10b981)'; }
|
||
else if(Math.abs(rt-rl) < 5){ r.innerHTML='ВЗВЕШЕНО →'; r.style.color='var(--muted)'; }
|
||
else { r.innerHTML='ТОНЕТ ↓'; r.style.color='var(--fail,#dc2626)'; }
|
||
};
|
||
document.getElementById('lr9w-rt-r').addEventListener('input', upd);
|
||
document.getElementById('lr9w-rl-r').addEventListener('input', upd);
|
||
upd();
|
||
wireSubmit('lr9');
|
||
}
|
||
}
|
||
|
||
/* === ЛР 10. Равновесие рычага === */
|
||
function add_lr10(){
|
||
const body = '<div class="sliders">'
|
||
+'<label>$F_1$ Н: <b id="lr10w-F1">2</b><input type="range" id="lr10w-F1-r" min="0.5" max="20" step="0.5" value="2"></label>'
|
||
+'<label>$l_1$ см: <b id="lr10w-l1">30</b><input type="range" id="lr10w-l1-r" min="5" max="100" step="1" value="30"></label>'
|
||
+'<label>$F_2$ Н: <b id="lr10w-F2">3</b><input type="range" id="lr10w-F2-r" min="0.5" max="20" step="0.5" value="3"></label>'
|
||
+'</div>'
|
||
+'<div class="score-display" style="flex-direction:column;align-items:flex-start;gap:4px">'
|
||
+'<span>Для равновесия: $l_2 = F_1 l_1 / F_2$ = <b id="lr10w-l2">20</b> см</span>'
|
||
+'<span>Проверка: $F_1 l_1$ = <b id="lr10w-M1">60</b>, $F_2 l_2$ = <b id="lr10w-M2">60</b> (Н·см)</span>'
|
||
+'</div>'
|
||
+'<div class="actions"><button class="btn primary" id="lr10-sub">Сдать работу (+30 XP)</button></div>'
|
||
+'<div class="feedback" id="lr10-fb"></div>';
|
||
if(appendTo('lr10', wgWrapper('lr10-extra', 'ЛР 10', 'Равновесие рычага', 'Подбери $l_2$ так чтобы $F_1 l_1 = F_2 l_2$.', body))){
|
||
const upd = ()=>{
|
||
const F1 = +document.getElementById('lr10w-F1-r').value;
|
||
const l1 = +document.getElementById('lr10w-l1-r').value;
|
||
const F2 = +document.getElementById('lr10w-F2-r').value;
|
||
document.getElementById('lr10w-F1').textContent = F1;
|
||
document.getElementById('lr10w-l1').textContent = l1;
|
||
document.getElementById('lr10w-F2').textContent = F2;
|
||
const l2 = F1*l1/F2;
|
||
document.getElementById('lr10w-l2').textContent = l2.toFixed(1);
|
||
document.getElementById('lr10w-M1').textContent = (F1*l1).toFixed(1);
|
||
document.getElementById('lr10w-M2').textContent = (F2*l2).toFixed(1);
|
||
};
|
||
['lr10w-F1-r','lr10w-l1-r','lr10w-F2-r'].forEach(id=>document.getElementById(id).addEventListener('input', upd));
|
||
upd();
|
||
wireSubmit('lr10');
|
||
}
|
||
}
|
||
|
||
/* === ЛР 11. КПД наклонной === */
|
||
function add_lr11(){
|
||
const body = '<div class="sliders">'
|
||
+'<label>$m$ кг: <b id="lr11w-m">0.2</b><input type="range" id="lr11w-m-r" min="0.05" max="2" step="0.05" value="0.2"></label>'
|
||
+'<label>$h$ м: <b id="lr11w-h">0.3</b><input type="range" id="lr11w-h-r" min="0.05" max="1.5" step="0.05" value="0.3"></label>'
|
||
+'<label>$l$ м (длина накл.): <b id="lr11w-l">0.6</b><input type="range" id="lr11w-l-r" min="0.1" max="3" step="0.05" value="0.6"></label>'
|
||
+'<label>Сила тяги $F$, Н: <b id="lr11w-F">1.2</b><input type="range" id="lr11w-F-r" min="0.05" max="5" step="0.05" value="1.2"></label>'
|
||
+'</div>'
|
||
+'<div class="score-display" style="flex-direction:column;align-items:flex-start;gap:4px">'
|
||
+'<span>$A_{пол} = mgh$ = <b id="lr11w-Ap">0.59</b> Дж</span>'
|
||
+'<span>$A_{зат} = Fl$ = <b id="lr11w-Az">0.72</b> Дж</span>'
|
||
+'<span>$\\eta = A_{пол}/A_{зат}$ = <b id="lr11w-eta">82</b>%</span>'
|
||
+'</div>'
|
||
+'<div class="actions"><button class="btn primary" id="lr11-sub">Сдать работу (+30 XP)</button></div>'
|
||
+'<div class="feedback" id="lr11-fb"></div>';
|
||
if(appendTo('lr11', wgWrapper('lr11-extra', 'ЛР 11', 'КПД наклонной плоскости', 'Измерь силу тяги динамометром и рассчитай КПД.', body))){
|
||
const upd = ()=>{
|
||
const m = +document.getElementById('lr11w-m-r').value;
|
||
const h = +document.getElementById('lr11w-h-r').value;
|
||
const l = +document.getElementById('lr11w-l-r').value;
|
||
const F = +document.getElementById('lr11w-F-r').value;
|
||
document.getElementById('lr11w-m').textContent = m.toFixed(2);
|
||
document.getElementById('lr11w-h').textContent = h.toFixed(2);
|
||
document.getElementById('lr11w-l').textContent = l.toFixed(2);
|
||
document.getElementById('lr11w-F').textContent = F.toFixed(2);
|
||
const Ap = m*9.8*h, Az = F*l;
|
||
document.getElementById('lr11w-Ap').textContent = Ap.toFixed(2);
|
||
document.getElementById('lr11w-Az').textContent = Az.toFixed(2);
|
||
document.getElementById('lr11w-eta').textContent = Az > 0 ? Math.min(100, Math.round(Ap/Az*100)) : 0;
|
||
};
|
||
['lr11w-m-r','lr11w-h-r','lr11w-l-r','lr11w-F-r'].forEach(id=>document.getElementById(id).addEventListener('input', upd));
|
||
upd();
|
||
wireSubmit('lr11');
|
||
}
|
||
}
|
||
|
||
/* === ЛР 12. Период пружинного маятника === */
|
||
function add_lr12(){
|
||
const body = '<div class="sliders">'
|
||
+'<label>$m$ груза, кг: <b id="lr12w-m">0.2</b><input type="range" id="lr12w-m-r" min="0.05" max="2" step="0.05" value="0.2"></label>'
|
||
+'<label>10 колебаний за $t$ с: <b id="lr12w-t">3.0</b><input type="range" id="lr12w-t-r" min="0.5" max="15" step="0.1" value="3"></label>'
|
||
+'</div>'
|
||
+'<div class="score-display" style="flex-direction:column;align-items:flex-start;gap:4px">'
|
||
+'<span>$T = t/10$ = <b id="lr12w-T">0.30</b> с</span>'
|
||
+'<span>$k = 4\\pi^2 m / T^2$ = <b id="lr12w-k">88</b> Н/м</span>'
|
||
+'</div>'
|
||
+'<div class="actions"><button class="btn primary" id="lr12-sub">Сдать работу (+30 XP)</button></div>'
|
||
+'<div class="feedback" id="lr12-fb"></div>';
|
||
if(appendTo('lr12', wgWrapper('lr12-extra', 'ЛР 12', 'Жёсткость пружины', 'Засеки время 10 колебаний и рассчитай $k$.', body))){
|
||
const upd = ()=>{
|
||
const m = +document.getElementById('lr12w-m-r').value;
|
||
const t = +document.getElementById('lr12w-t-r').value;
|
||
document.getElementById('lr12w-m').textContent = m.toFixed(2);
|
||
document.getElementById('lr12w-t').textContent = t.toFixed(2);
|
||
const T = t/10;
|
||
const k = 4*Math.PI*Math.PI*m/(T*T);
|
||
document.getElementById('lr12w-T').textContent = T.toFixed(2);
|
||
document.getElementById('lr12w-k').textContent = k.toFixed(0);
|
||
};
|
||
document.getElementById('lr12w-m-r').addEventListener('input', upd);
|
||
document.getElementById('lr12w-t-r').addEventListener('input', upd);
|
||
upd();
|
||
wireSubmit('lr12');
|
||
}
|
||
}
|
||
|
||
window.PHYS9_CH5_WIDGETS = {
|
||
lr1:add_lr1, lr2:add_lr2, lr3:add_lr3, lr4:add_lr4, lr5:add_lr5, lr6:add_lr6,
|
||
lr7:add_lr7, lr8:add_lr8, lr9:add_lr9, lr10:add_lr10, lr11:add_lr11, lr12:add_lr12
|
||
};
|
||
|
||
})();
|