diff --git a/frontend/js/phys9_ch3_widgets.js b/frontend/js/phys9_ch3_widgets.js new file mode 100644 index 0000000..8c5bd31 --- /dev/null +++ b/frontend/js/phys9_ch3_widgets.js @@ -0,0 +1,256 @@ +// phys9_ch3_widgets.js — виджеты для Физики 9, Глава 3 (§25-§30): статика и гидростатика. +(function(){ +'use strict'; +const C = () => window.PHYS9_COLORS || {}; +const PI = Math.PI; + +function dndPool(secId, items, cats){ + let p='
'; + items.forEach(it=>{ p += '
'+it.html+'
'; }); + p += '
'; + cats.forEach(c=>{ p += '
'+c.label+'
'; }); + return p + '
'; +} +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); + }); + }); + scope.querySelector('.dnd-check').addEventListener('click', ()=>{ + let wrong = 0; const 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='✓ Идеально!'; } + else { fb.className='feedback fail'; fb.innerHTML='✗ Ошибок: '+wrong+'.'; } + }); +} +function wgWrapper(secId, badge, title, help, body){ + return '
'+badge+'
'+title+'
'+help+'
'+body+'
'; +} +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; +} + +/* ====== §25 — Равновесие рычага F₁ l₁ = F₂ l₂ ====== */ +function add_p25(){ + const body = '
' + +'' + +'' + +'' + +'' + +'
' + +'' + +'
' + +'$M_1 = m_1 g l_1$ = 29.4 Н·м' + +'$M_2 = m_2 g l_2$ = 29.4 Н·м' + +'РАВНОВЕСИЕ ✓' + +'
'; + if(appendTo('p25', wgWrapper('p25-extra', 'CALC+VIS', 'Равновесие рычага', '$F_1 l_1 = F_2 l_2$ — моменты сил равны.', body))){ + const upd = ()=>{ + const m1 = +document.getElementById('p25w-m1-r').value; + const l1 = +document.getElementById('p25w-l1-r').value; + const m2 = +document.getElementById('p25w-m2-r').value; + const l2 = +document.getElementById('p25w-l2-r').value; + document.getElementById('p25w-m1').textContent = m1; + document.getElementById('p25w-l1').textContent = l1.toFixed(1); + document.getElementById('p25w-m2').textContent = m2; + document.getElementById('p25w-l2').textContent = l2.toFixed(1); + const M1 = m1*9.8*l1, M2 = m2*9.8*l2; + document.getElementById('p25w-M1').textContent = M1.toFixed(1); + document.getElementById('p25w-M2').textContent = M2.toFixed(1); + const eq = document.getElementById('p25w-eq'); + if(Math.abs(M1-M2) < 0.5){ eq.innerHTML = 'РАВНОВЕСИЕ ✓'; eq.style.color = 'var(--ok,#10b981)'; } + else if(M1 > M2){ eq.innerHTML = 'ЛЕВАЯ ПЕРЕВЕШИВАЕТ ⤵'; eq.style.color = 'var(--fail,#dc2626)'; } + else { eq.innerHTML = 'ПРАВАЯ ПЕРЕВЕШИВАЕТ ⤵'; eq.style.color = 'var(--fail,#dc2626)'; } + /* SVG */ + const col = C(); + const tilt = Math.max(-15, Math.min(15, (M2-M1)*0.3)); + const cx = 230, cy = 100; + const len = 180; + const rad = tilt*PI/180; + const lx = cx - len*Math.cos(rad), ly = cy + len*Math.sin(rad); + const rx = cx + len*Math.cos(rad), ry = cy - len*Math.sin(rad); + let s = ''; + /* опора */ + s += ''; + /* балка */ + s += ''; + /* грузы */ + const r1 = Math.min(20, 5 + m1*2); + const r2 = Math.min(20, 5 + m2*2); + s += ''; + s += ''; + /* подписи */ + s += ''+m1+' кг'; + s += ''+m2+' кг'; + document.getElementById('p25w-svg').innerHTML = s; + }; + ['p25w-m1-r','p25w-l1-r','p25w-m2-r','p25w-l2-r'].forEach(id=>document.getElementById(id).addEventListener('input', upd)); + upd(); + } +} + +/* ====== §26 — Простые механизмы ====== */ +function add_p26(){ + const items = [ + {id:'i1', cat:'force', html:'рычаг с длинным плечом'}, + {id:'i2', cat:'force', html:'наклонная плоскость (длинная)'}, + {id:'i3', cat:'force', html:'неподвижный блок + полиспаст'}, + {id:'i4', cat:'force', html:'клин'}, + {id:'i5', cat:'dist', html:'рычаг с коротким плечом (метла)'}, + {id:'i6', cat:'dist', html:'педаль велосипеда'}, + {id:'i7', cat:'none', html:'неподвижный блок (один)'}, + {id:'i8', cat:'none', html:'жёсткий стержень'} + ]; + const body = dndPool('p26ex', items, [ + {cat:'force', label:'Выигрыш в силе'}, + {cat:'dist', label:'Выигрыш в скор./пути'}, + {cat:'none', label:'Без выигрыша'} + ]) + '
'; + if(appendTo('p26', wgWrapper('p26-extra', 'DnD', 'Что даёт выигрыш?', 'Золотое правило: выигрываем в силе — проигрываем в расстоянии. И наоборот.', body))){ + wireDnd('p26-extra', items); + } +} + +/* ====== §27 — КПД наклонной плоскости ====== */ +function add_p27(){ + const body = '
' + +'' + +'' + +'' + +'' + +'
' + +'
' + +'$A_{пол} = m g h$ = 98 Дж' + +'$A_{зат} = F \\cdot l$ = 131 Дж' + +'$\\eta$ = 75%' + +'
'; + if(appendTo('p27', wgWrapper('p27-extra', 'CALC', 'КПД наклонной плоскости', 'Полезная работа = $mgh$. Затраченная = $F \\cdot l$, где $F$ учитывает трение.', body))){ + const upd = ()=>{ + const m = +document.getElementById('p27w-m-r').value; + const h = +document.getElementById('p27w-h-r').value; + const a = +document.getElementById('p27w-an-r').value; + const mu = +document.getElementById('p27w-mu-r').value; + document.getElementById('p27w-m').textContent = m; + document.getElementById('p27w-h').textContent = h.toFixed(1); + document.getElementById('p27w-an').textContent = a; + document.getElementById('p27w-mu').textContent = mu.toFixed(2); + const g = 9.8; + const l = h / Math.sin(a*PI/180); + const F = m*g*(Math.sin(a*PI/180) + mu*Math.cos(a*PI/180)); + const Apol = m*g*h; + const Azat = F*l; + const eta = (Apol/Azat)*100; + document.getElementById('p27w-Apol').textContent = Apol.toFixed(0); + document.getElementById('p27w-Azat').textContent = Azat.toFixed(0); + document.getElementById('p27w-eta').textContent = eta.toFixed(0); + }; + ['p27w-m-r','p27w-h-r','p27w-an-r','p27w-mu-r'].forEach(id=>document.getElementById(id).addEventListener('input', upd)); + upd(); + } +} + +/* ====== §28 — Виды равновесия ====== */ +function add_p28(){ + const items = [ + {id:'i1', cat:'st', html:'шар в углублении'}, + {id:'i2', cat:'st', html:'маятник в нижней точке'}, + {id:'i3', cat:'st', html:'столб с широким основанием'}, + {id:'i4', cat:'un', html:'шар на вершине горы'}, + {id:'i5', cat:'un', html:'карандаш на остром конце'}, + {id:'i6', cat:'un', html:'пирамида на вершине'}, + {id:'i7', cat:'in', html:'шар на горизонтальном столе'}, + {id:'i8', cat:'in', html:'цилиндр на ровной поверхности'} + ]; + const body = dndPool('p28ex', items, [ + {cat:'st', label:'Устойчивое'}, + {cat:'un', label:'Неустойчивое'}, + {cat:'in', label:'Безразличное'} + ]) + '
'; + if(appendTo('p28', wgWrapper('p28-extra', 'DnD', 'Вид равновесия', 'Устойчивое — возврат, неустойчивое — уход, безразличное — без изменений.', body))){ + wireDnd('p28-extra', items); + } +} + +/* ====== §29 — Закон Архимеда ====== */ +function add_p29(){ + const body = '
' + +'' + +'' + +'' + +'
' + +'
' + +'$F_A = \\rho g V$ = 0.98 Н' + +'Вес тела $P$ = 0.49 Н' + +'ПЛАВАЕТ ↑' + +'
'; + if(appendTo('p29', wgWrapper('p29-extra', 'CALC', 'Закон Архимеда', '$F_A = \\rho g V$. Сравни с весом тела.', body))){ + const upd = ()=>{ + const V_cm3 = +document.getElementById('p29w-V-r').value; + const V = V_cm3 * 1e-6; + const rho_l = +document.getElementById('p29w-liq').value; + const rho_t = +document.getElementById('p29w-rt-r').value; + document.getElementById('p29w-V').textContent = V_cm3; + document.getElementById('p29w-rt').textContent = rho_t; + const g = 9.8; + const Fa = rho_l*g*V; + const P = rho_t*g*V; + document.getElementById('p29w-Fa').textContent = Fa.toFixed(2); + document.getElementById('p29w-P').textContent = P.toFixed(2); + const r = document.getElementById('p29w-result'); + if(Math.abs(Fa-P) < 0.01){ r.innerHTML = 'ВИСИТ В ТОЛЩЕ →'; r.style.color = 'var(--muted)'; } + else if(Fa > P){ r.innerHTML = 'ПЛАВАЕТ ↑'; r.style.color = 'var(--ok,#10b981)'; } + else { r.innerHTML = 'ТОНЕТ ↓'; r.style.color = 'var(--fail,#dc2626)'; } + }; + ['p29w-V-r','p29w-liq','p29w-rt-r'].forEach(id=>document.getElementById(id).addEventListener('input', upd)); + document.getElementById('p29w-liq').addEventListener('change', upd); + upd(); + } +} + +/* ====== §30 — Плотности жидкостей по возрастанию ====== */ +function add_p30(){ + const items = [ + {id:'i1', cat:'r1', html:'спирт ($789$)'}, + {id:'i2', cat:'r2', html:'керосин ($800$)'}, + {id:'i3', cat:'r3', html:'вода ($1000$)'}, + {id:'i4', cat:'r4', html:'морская вода ($1030$)'}, + {id:'i5', cat:'r5', html:'ртуть ($13600$)'} + ]; + const body = dndPool('p30ex', items, [ + {cat:'r1', label:'$<800$'}, + {cat:'r2', label:'$800–999$'}, + {cat:'r3', label:'$1000–1029$'}, + {cat:'r4', label:'$1030–1500$'}, + {cat:'r5', label:'$>10000$'} + ]) + '
'; + if(appendTo('p30', wgWrapper('p30-extra', 'DnD', 'Плотности жидкостей (кг/м³)', 'Расставь жидкости по группам плотности.', body))){ + wireDnd('p30-extra', items); + } +} + +window.PHYS9_CH3_WIDGETS = { p25:add_p25, p26:add_p26, p27:add_p27, p28:add_p28, p29:add_p29, p30:add_p30 }; + +})(); diff --git a/frontend/textbooks/physics_9_ch3.html b/frontend/textbooks/physics_9_ch3.html index 556788e..97860b0 100644 --- a/frontend/textbooks/physics_9_ch3.html +++ b/frontend/textbooks/physics_9_ch3.html @@ -17,6 +17,7 @@ +