// F13. Маятник Фуко (§36 в ch4) — вращение Земли и розетка. (function(){ 'use strict'; const B = () => window.PHYS9_FLAG_BASE; const C = () => window.PHYS9_COLORS || {}; function init(secId){ if (!B()) return false; const body = '' + '
' + '' + '' + '
' + '' + '
' + '' + '' + '' + '
' + '
' + '
Текущая широтаМинск (52°)
' + '
Период оборота плоскости30.4 ч
' + '
Реальное время0 ч
' + '
Поворот плоскости
' + '
' + '
'; const card = B().makeCard(secId, 'F13. Маятник Фуко', 'Маятник в Париже (1851) доказал вращение Земли. Период оборота плоскости: $T = 24/\\sin\\varphi$ часов. На полюсе — 24 ч, на экваторе — никогда.', body); if (!card) return false; const cv = document.getElementById('F13-cv'); const ctx = cv.getContext('2d'); const W = cv.width, H = cv.height; const cx = W/2, cy = H/2; const R = 130; let st = { phase: 0, planeAngle: 0, t: 0, running: false, trail: [] }; function update(){ const lat = +document.getElementById('F13-l').value; const speed = +document.getElementById('F13-s').value; document.getElementById('F13-lv').textContent = lat; document.getElementById('F13-sv').textContent = speed; let loc; if (lat >= 89) loc = 'Северный полюс (90°)'; else if (lat >= 70) loc = 'Заполярье (70-89°)'; else if (lat >= 55) loc = 'Москва (55°)'; else if (lat >= 50) loc = 'Минск (52°)'; else if (lat >= 40) loc = 'Рим (42°)'; else if (lat >= 20) loc = 'Каир (30°)'; else if (lat >= 5) loc = 'тропики'; else loc = 'экватор (0°)'; document.getElementById('F13-loc').textContent = loc; const sinL = Math.sin(lat * Math.PI/180); const T = sinL > 0.001 ? 24 / sinL : Infinity; document.getElementById('F13-T').textContent = isFinite(T) ? T.toFixed(1) + ' ч' : '∞ (нет поворота)'; } function reset(){ st = { phase: 0, planeAngle: 0, t: 0, running: false, trail: [] }; document.getElementById('F13-go').textContent = 'Запустить'; draw(); } function tick(dt){ if (!st.running) { draw(); return; } const lat = +document.getElementById('F13-l').value; const speed = +document.getElementById('F13-s').value; const sinL = Math.sin(lat * Math.PI/180); const realDt = dt * speed; /* условное реальное время в секундах */ st.t += realDt; /* колебание маятника: период ~6 с реального времени */ st.phase += dt * 2 * Math.PI * 0.5; /* псевдо-период для красоты */ /* поворот плоскости: ω = 2π/(24·3600/sinL) рад/с */ const omega = sinL * 2 * Math.PI / (24*3600); st.planeAngle += omega * realDt; /* trail — текущее положение маятника */ const r = R * Math.cos(st.phase); const px = cx + r * Math.cos(st.planeAngle); const py = cy + r * Math.sin(st.planeAngle); st.trail.push({ x: px, y: py }); if (st.trail.length > 5000) st.trail.shift(); document.getElementById('F13-t').textContent = (st.t/3600).toFixed(2) + ' ч'; document.getElementById('F13-rot').textContent = ((st.planeAngle * 180/Math.PI) % 360).toFixed(1) + '°'; draw(); } function draw(){ const col = C(); ctx.fillStyle = col.bg || '#fafafa'; ctx.fillRect(0, 0, W, H); /* пол */ ctx.fillStyle = col.bgSubtle || '#f8fafc'; ctx.beginPath(); ctx.arc(cx, cy, R + 30, 0, Math.PI*2); ctx.fill(); ctx.strokeStyle = col.axis || '#1e293b'; ctx.lineWidth = 2; ctx.stroke(); /* радиальные направления (страны света) */ ctx.font = '12px Inter,sans-serif'; ctx.fillStyle = col.textMuted || '#64748b'; ctx.textAlign = 'center'; ctx.fillText('С', cx, cy - R - 15); ctx.fillText('Ю', cx, cy + R + 25); ctx.fillText('З', cx - R - 18, cy + 4); ctx.fillText('В', cx + R + 18, cy + 4); /* следы маятника */ if (st.trail.length > 1){ ctx.strokeStyle = col.velocity || '#0891b2'; ctx.lineWidth = 1.2; ctx.globalAlpha = 0.5; ctx.beginPath(); ctx.moveTo(st.trail[0].x, st.trail[0].y); for (let i = 1; i < st.trail.length; i++) ctx.lineTo(st.trail[i].x, st.trail[i].y); ctx.stroke(); ctx.globalAlpha = 1; } /* центральная точка крепления */ ctx.fillStyle = col.axis || '#1e293b'; ctx.beginPath(); ctx.arc(cx, cy, 5, 0, Math.PI*2); ctx.fill(); /* плоскость колебаний — линия */ ctx.strokeStyle = col.acceleration || '#ea580c'; ctx.lineWidth = 1.5; ctx.setLineDash([6, 4]); ctx.beginPath(); ctx.moveTo(cx - R * Math.cos(st.planeAngle), cy - R * Math.sin(st.planeAngle)); ctx.lineTo(cx + R * Math.cos(st.planeAngle), cy + R * Math.sin(st.planeAngle)); ctx.stroke(); ctx.setLineDash([]); /* маятник — груз */ const r = R * Math.cos(st.phase); const px = cx + r * Math.cos(st.planeAngle); const py = cy + r * Math.sin(st.planeAngle); ctx.fillStyle = col.forceGravity || '#2563eb'; ctx.beginPath(); ctx.arc(px, py, 10, 0, Math.PI*2); ctx.fill(); ctx.strokeStyle = col.bodyAccent || '#1e293b'; ctx.lineWidth = 1.5; ctx.stroke(); ctx.textAlign = 'left'; } document.getElementById('F13-go').addEventListener('click', () => { st.running = !st.running; document.getElementById('F13-go').textContent = st.running ? 'Пауза' : 'Запустить'; }); document.getElementById('F13-reset').addEventListener('click', reset); document.getElementById('F13-clear').addEventListener('click', () => { st.trail = []; draw(); }); ['F13-l','F13-s'].forEach(id => document.getElementById(id).addEventListener('input', update)); update(); draw(); B().startLoop('F13', cv, tick); return true; } if (window.PHYS9_FLAG_BASE) window.PHYS9_FLAG_BASE.register('F13', { init: init, cleanup: function(){} }); else document.addEventListener('DOMContentLoaded', ()=>{ if (window.PHYS9_FLAG_BASE) window.PHYS9_FLAG_BASE.register('F13', { init: init, cleanup: function(){} }); }); })();