diff --git a/frontend/js/phys9_ch2_widgets.js b/frontend/js/phys9_ch2_widgets.js new file mode 100644 index 0000000..20ba52b --- /dev/null +++ b/frontend/js/phys9_ch2_widgets.js @@ -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 '' + + ''; +} +function dndPool(secId, items, cats){ + let pool='
'; + items.forEach(it=>{ + pool += '
'+it.html+'
'; + }); + pool += '
'; + let boxes = '
'; + cats.forEach(c=>{ + boxes += '
'+c.label+'
'; + }); + boxes += '
'; + 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='✓ Идеально!'; } + 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; +} + +/* ====== §15 — Гравитация F = G m1 m2 / r² ====== */ +function add_p15(){ + const body = '
' + +'' + +'' + +'' + +'
' + +'
' + +'$F = G\\dfrac{m_1 m_2}{r^2}$ = 6.67 Н' + +'Аналог: Земля-Луна' + +'
'; + 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$ г'} + ]) + '
' + + ''; + if(appendTo('p16', wgWrapper('p16-extra', 'DnD', 'Планеты по периоду', 'III закон Кеплера: чем дальше от Солнца, тем больше период.', body))){ + wireDnd('p16-extra', items); + } +} + +/* ====== §17 — Период, частота, угловая скорость ====== */ +function add_p17(){ + const body = '
' + +'' + +'' + +'
' + +'
' + +'$T$ = 2.0 с' + +'$\\nu = 1/T$ = 0.50 Гц' + +'$\\omega = 2\\pi/T$ = 3.14 рад/с' + +'
'; + 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 = '
' + +'' + +'' + +'
' + +'' + +'
$a_n = v^2/R$ = 20 м/с²(2.0 g)
'; + 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 += ''; + s += ''; + s += ''; + /* 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 += 'v'; + s += 'a_n'; + 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 = '
' + +'' + +'' + +'
' + +'
' + +'$F = kx$ = 10 Н' + +'это вес тела массой 1.02 кг' + +'
'; + 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:'Малое'} + ]) + '
' + + ''; + 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:'Неинерц. СО'} + ]) + '
' + + ''; + if(appendTo('p21', wgWrapper('p21-extra', 'DnD', 'Инерциальная или нет?', 'Инерциальная — где $\\vec a = 0$ (тело покоится или движется равномерно прямолинейно).', body))){ + wireDnd('p21-extra', items); + } +} + +/* ====== §22 — F = ma ====== */ +function add_p22(){ + const body = '
' + +'' + +'' + +'
' + +'
' + +'$a = F/m$ = 5.00 м/с²' + +'За 1 с скорость возрастёт на 5.0 м/с' + +'
'; + 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 = '
' + +'' + +'
' + +'
' + +'$g(h) = GM/(R+h)^2$ = 9.80 м/с²' + +'место: поверхность Земли' + +'
'; + 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 = '
' + +'' + +'' + +'
' + +'
' + +'Вес $P = m(g + a)$ = 686 Н' + +'НОРМАЛЬНЫЙ ВЕС' + +'
'; + 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 +}; + +})(); diff --git a/frontend/textbooks/physics_9_ch2.html b/frontend/textbooks/physics_9_ch2.html index b778b1a..f8f144b 100644 --- a/frontend/textbooks/physics_9_ch2.html +++ b/frontend/textbooks/physics_9_ch2.html @@ -17,6 +17,7 @@ +