feat(phys8 lab): Phase 4 — Лабораторный практикум (визуал + 7 IV-6)
Hero: emerald-зелёный градиент (стиль 'химической лаборатории'), flask SVG-watermark, live meter '7/7 ЛР'. 7 section watermarks: термометр, печь, цепь, посл/парал, P, угол. 7 IV-6 интерактивов: ЛР1 Теплообмен: 2 ёмкости (0.5 кг + 1 кг), scrubbers T₁/T₂, кнопка 'Смешать' с tween-анимацией, формула баланса. ЛР2 Удельная теплоёмкость: scrubbers P/m/t, нагреватель, термометр с цветовой картой, c=Q/(mΔT) для воды (4200). ЛР3 Простейшая цепь: батарея+амперметр+лампа+вольтметр, scrubber U, live показания приборов. ЛР4 Последовательное соединение: U=U₁+U₂, I одинаков. ЛР5 Параллельное соединение: U одинаков, I=I₁+I₂. ЛР6 Работа и мощность: U·I·t, лампа brightness ∝ P, лучи при P>100 Вт. ЛР7 Закон отражения: луч + нормаль + угловые дуги, verdict 'α=β'.
This commit is contained in:
@@ -0,0 +1,384 @@
|
||||
// Phase 4 — Lab redesign: hero + section watermarks + 7 IV-6 sandboxes.
|
||||
'use strict';
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const DST = path.join(__dirname, '..', '..', 'frontend', 'textbooks', 'physics_8_lab.html');
|
||||
let h = fs.readFileSync(DST, 'utf8');
|
||||
|
||||
// === 1. Hero replacement ===
|
||||
const FLASK_WM = `<svg viewBox="0 0 100 100" aria-hidden="true">
|
||||
<path d="M40 12 L40 38 L18 80 C 15 88, 20 92, 26 92 L74 92 C 80 92, 85 88, 82 80 L60 38 L60 12 Z M 35 12 L65 12" stroke="currentColor" stroke-width="4" fill="none"/>
|
||||
<circle cx="38" cy="64" r="3" fill="currentColor"/>
|
||||
<circle cx="55" cy="76" r="3" fill="currentColor"/>
|
||||
<circle cx="44" cy="80" r="2" fill="currentColor"/>
|
||||
</svg>`;
|
||||
|
||||
const NEW_HERO = `<header class="p8-hero" style="background:linear-gradient(115deg,#064e3b 0%,#10b981 60%,#6ee7b7 100%)">
|
||||
<div class="p8-hero-wm">${FLASK_WM}</div>
|
||||
<div class="p8-hero-meter" id="p8-meter-lab"><span id="p8-meter-val">7</span>/7 ЛР</div>
|
||||
<div class="p8-hero-inner">
|
||||
<div class="p8-hero-eyebrow">Лабораторный практикум · 7 ЛР</div>
|
||||
<h1 class="p8-hero-title">Виртуальная лаборатория</h1>
|
||||
<div class="p8-hero-sub">Перетаскивайте термометры, нагреватели, динамометры и измерительные приборы. Собирайте установки и записывайте результаты.</div>
|
||||
<div class="hdr-side" style="margin-top:18px;display:flex;gap:8px;flex-wrap:wrap;position:relative;z-index:1">
|
||||
<a href="/textbook/physics-8" class="hdr-btn"><svg class="ic" viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg> К физике 8</a>
|
||||
<button id="search-btn" class="hdr-btn"><svg class="ic" viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="m21 21-4-4"/></svg> Поиск</button>
|
||||
<button id="sidebar-btn" class="hdr-btn"><svg class="ic" viewBox="0 0 24 24"><line x1="4" y1="6" x2="20" y2="6"/><line x1="4" y1="12" x2="20" y2="12"/><line x1="4" y1="18" x2="14" y2="18"/></svg> Шпаргалка</button>
|
||||
<button id="theme-btn" class="hdr-btn"><svg class="ic" viewBox="0 0 24 24"><path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z"/></svg><span id="theme-lab">Тёмная</span></button>
|
||||
</div>
|
||||
</div>
|
||||
</header>`;
|
||||
|
||||
const oldHdrRegex = /<header class="hdr">[\s\S]*?<\/header>/;
|
||||
if (h.match(oldHdrRegex)) {
|
||||
h = h.replace(oldHdrRegex, NEW_HERO);
|
||||
console.log('Hero replaced');
|
||||
}
|
||||
|
||||
// === 2. Section watermarks ===
|
||||
const SEC_SYMBOLS = {
|
||||
lr1: '<svg viewBox="0 0 100 100"><rect x="30" y="20" width="40" height="60" fill="none" stroke="currentColor" stroke-width="4" rx="4"/><rect x="36" y="40" width="28" height="35" fill="currentColor" opacity="0.6"/></svg>',
|
||||
lr2: '<svg viewBox="0 0 100 100"><rect x="20" y="40" width="60" height="40" fill="none" stroke="currentColor" stroke-width="3"/><circle cx="50" cy="60" r="10" fill="currentColor"/></svg>',
|
||||
lr3: '<svg viewBox="0 0 100 100"><rect x="20" y="40" width="60" height="30" fill="none" stroke="currentColor" stroke-width="3"/><circle cx="50" cy="55" r="8" fill="none" stroke="currentColor" stroke-width="3"/></svg>',
|
||||
lr4: '<svg viewBox="0 0 100 100"><path d="M20 50 L30 50 L35 40 L45 60 L55 40 L65 60 L70 50 L80 50" stroke="currentColor" stroke-width="3" fill="none"/></svg>',
|
||||
lr5: '<svg viewBox="0 0 100 100"><path d="M20 30 L80 30 M20 70 L80 70 M50 30 L50 70" stroke="currentColor" stroke-width="3" fill="none"/></svg>',
|
||||
lr6: '<svg viewBox="0 0 100 100"><text x="50" y="60" font-family="Unbounded" font-size="32" font-weight="900" fill="currentColor" text-anchor="middle">P</text></svg>',
|
||||
lr7: '<svg viewBox="0 0 100 100"><line x1="20" y1="20" x2="50" y2="50" stroke="currentColor" stroke-width="4"/><line x1="50" y1="50" x2="80" y2="20" stroke="currentColor" stroke-width="4"/></svg>'
|
||||
};
|
||||
|
||||
let secWmInjected = 0;
|
||||
for (const pid of Object.keys(SEC_SYMBOLS)) {
|
||||
const symbol = SEC_SYMBOLS[pid];
|
||||
const secOpenRegex = new RegExp(`(<section[^>]+id="sec-${pid}"[^>]*>)`);
|
||||
if (h.match(secOpenRegex) && !h.includes(`p8-sec-wm-${pid}`)) {
|
||||
const wmDiv = `<div class="p8-sec-wm" id="p8-sec-wm-${pid}" aria-hidden="true">${symbol}</div>`;
|
||||
h = h.replace(secOpenRegex, '$1\n ' + wmDiv);
|
||||
secWmInjected++;
|
||||
}
|
||||
}
|
||||
console.log('Section watermarks:', secWmInjected);
|
||||
|
||||
// === 3. Inject IV-6 widgets into each lr-builder ===
|
||||
function injectIV6(lrid, title, helpHtml, body, init) {
|
||||
const widgetHtml = `
|
||||
/* IV6 — ${title} (Phase 4) */
|
||||
h += '<div class="wg p8-iv6">'
|
||||
+'<div class="wg-header"><span class="wg-badge p8-badge" style="background:#d1fae5;color:#047857">IV-6</span><div class="wg-title">${title}</div></div>'
|
||||
+'<div class="wg-help">${helpHtml}</div>'
|
||||
+'<div class="p8-sandbox" id="${lrid}-iv6-sandbox" style="height:260px"></div>'
|
||||
${body}
|
||||
+'</div>';
|
||||
`;
|
||||
const initFn = `
|
||||
function _init${lrid.toUpperCase()}_iv6(){
|
||||
const sb = document.getElementById('${lrid}-iv6-sandbox');
|
||||
if (!sb || !window.P8Helpers) return;
|
||||
${init}
|
||||
}
|
||||
`;
|
||||
const marker = `box.innerHTML = h + secNavFor('${lrid}') + readButton('${lrid}');`;
|
||||
if (!h.includes(marker)) { console.warn(lrid+': no marker'); return; }
|
||||
if (h.includes(`${lrid}-iv6-sandbox`)) { console.log(lrid+': already injected'); return; }
|
||||
const eol = (h.indexOf('\r\n') >= 0) ? '\r\n' : '\n';
|
||||
const indented = widgetHtml.trim().replace(/\n/g, eol);
|
||||
h = h.replace(marker, indented + eol + eol + ' ' + marker);
|
||||
h = h.replace(`wireReadBtn('${lrid}');`, `wireReadBtn('${lrid}');${eol} _init${lrid.toUpperCase()}_iv6();`);
|
||||
const fnStart = h.indexOf(`function build_${lrid}()`);
|
||||
const fnEnd = h.indexOf('\n}\n', fnStart);
|
||||
h = h.slice(0, fnEnd + 3) + eol + initFn.trim() + eol + h.slice(fnEnd + 3);
|
||||
console.log(lrid+': injected IV-6');
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// ЛР1 — Теплообмен (drag термометр + смешать жидкости)
|
||||
// ============================================================
|
||||
injectIV6('lr1', 'Теплообмен — смешивание жидкостей',
|
||||
'Задавай начальные T₁ и T₂ скрубберами. Кнопка «Смешать» — итоговая T рассчитывается через тепловой баланс.',
|
||||
'+\'<div style="margin-top:10px;display:grid;grid-template-columns:1fr 1fr;gap:8px"><div class="p8-scrubber"><span class="p8-scrubber-label">T₁ (0.5 кг)</span><input type="range" id="lr1-t1" min="0" max="100" step="1" value="80"><span class="p8-scrubber-value"><span id="lr1-t1-val">80</span><span class="p8-unit">°C</span></span></div><div class="p8-scrubber"><span class="p8-scrubber-label">T₂ (1 кг)</span><input type="range" id="lr1-t2" min="0" max="100" step="1" value="20"><span class="p8-scrubber-value"><span id="lr1-t2-val">20</span><span class="p8-unit">°C</span></span></div></div>\'+\'<div style="margin-top:8px;display:flex;gap:10px;flex-wrap:wrap"><button class="btn primary" id="lr1-mix">Смешать</button><div class="p8-readout"><span class="p8-readout-label">T_итог</span><span class="p8-readout-value" id="lr1-tf">—</span><span class="p8-readout-unit">°C</span></div></div>\'',
|
||||
`
|
||||
const svg = P8Helpers.svg.create(560, 260);
|
||||
svg.setAttribute('width','100%'); svg.setAttribute('height','100%'); svg.style.display='block';
|
||||
sb.appendChild(svg);
|
||||
let T1=80, T2=20, mixed=false, Tf=50;
|
||||
function vessel(x, y, T, m){
|
||||
const g = P8Helpers.svg.el('g', { transform: 'translate('+x+','+y+')' });
|
||||
const ht = 40 + m*50;
|
||||
g.appendChild(P8Helpers.svg.el('rect', { x:-32, y:-ht, width:64, height:ht, rx:5, fill:'rgba(255,255,255,.7)', stroke:'#0f172a', 'stroke-width':2 }));
|
||||
g.appendChild(P8Helpers.svg.el('rect', { x:-29, y:-ht+3, width:58, height:ht-5, rx:3, fill: P8Helpers.thermal.tempColor(T/100) }));
|
||||
g.appendChild(P8Helpers.svg.el('text', { x:0, y:18, 'font-family':"'JetBrains Mono',monospace", 'font-size':12, 'font-weight':700, fill:'#0f172a', 'text-anchor':'middle', text: 'T='+Math.round(T)+'°C' }));
|
||||
return g;
|
||||
}
|
||||
function render(){
|
||||
svg.innerHTML='';
|
||||
if (!mixed){
|
||||
svg.appendChild(vessel(160, 180, T1, 0.5));
|
||||
svg.appendChild(vessel(400, 180, T2, 1));
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x:160, y:235, 'font-family':"'Inter',sans-serif", 'font-size':11, fill:'var(--p8-muted,#64748b)', 'text-anchor':'middle', text:'m₁=0.5 кг' }));
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x:400, y:235, 'font-family':"'Inter',sans-serif", 'font-size':11, fill:'var(--p8-muted,#64748b)', 'text-anchor':'middle', text:'m₂=1 кг' }));
|
||||
} else {
|
||||
svg.appendChild(vessel(280, 180, Tf, 1.5));
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x:280, y:70, 'font-family':"'Unbounded',sans-serif", 'font-size':18, 'font-weight':900, fill:'#10b981', 'text-anchor':'middle', text: 'T_итог = '+Math.round(Tf)+' °C' }));
|
||||
}
|
||||
}
|
||||
document.getElementById('lr1-t1').oninput = ev => { T1 = +ev.target.value; document.getElementById('lr1-t1-val').textContent = T1; mixed = false; document.getElementById('lr1-tf').textContent='—'; render(); };
|
||||
document.getElementById('lr1-t2').oninput = ev => { T2 = +ev.target.value; document.getElementById('lr1-t2-val').textContent = T2; mixed = false; document.getElementById('lr1-tf').textContent='—'; render(); };
|
||||
document.getElementById('lr1-mix').onclick = () => {
|
||||
Tf = (0.5*T1 + 1*T2)/(0.5+1);
|
||||
mixed = true;
|
||||
if (window.P8Anim) P8Anim.tween({ from: T1, to: Tf, duration: 1200, easing: 'cubicInOut', onUpdate: t => { Tf = t; render(); document.getElementById('lr1-tf').textContent = Math.round(t); } });
|
||||
else { render(); document.getElementById('lr1-tf').textContent = Math.round(Tf); }
|
||||
if (window.addXp) addXp(15, 'lr1-iv6');
|
||||
};
|
||||
render();
|
||||
`);
|
||||
|
||||
// ============================================================
|
||||
// ЛР2 — Удельная теплоёмкость (нагреватель + ёмкость)
|
||||
// ============================================================
|
||||
injectIV6('lr2', 'Измерение удельной теплоёмкости',
|
||||
'Нагреватель мощности P подаёт Q=Pt в массу m. Из ΔT находим $c = Q/(m\\\\Delta T)$.',
|
||||
'+\'<div style="margin-top:10px;display:grid;grid-template-columns:1fr 1fr 1fr;gap:6px"><div class="p8-scrubber"><span class="p8-scrubber-label">P</span><input type="range" id="lr2-p" min="50" max="1000" step="10" value="500"><span class="p8-scrubber-value"><span id="lr2-p-val">500</span><span class="p8-unit">Вт</span></span></div><div class="p8-scrubber"><span class="p8-scrubber-label">m</span><input type="range" id="lr2-m" min="0.1" max="2" step="0.1" value="0.5"><span class="p8-scrubber-value"><span id="lr2-m-val">0.5</span><span class="p8-unit">кг</span></span></div><div class="p8-scrubber"><span class="p8-scrubber-label">t</span><input type="range" id="lr2-t" min="10" max="600" step="5" value="120"><span class="p8-scrubber-value"><span id="lr2-t-val">120</span><span class="p8-unit">с</span></span></div></div>\'+\'<div style="margin-top:8px;display:flex;gap:10px;flex-wrap:wrap"><div class="p8-readout"><span class="p8-readout-label">Q</span><span class="p8-readout-value" id="lr2-q">60</span><span class="p8-readout-unit">кДж</span></div><div class="p8-readout"><span class="p8-readout-label">ΔT</span><span class="p8-readout-value" id="lr2-dt">29</span><span class="p8-readout-unit">К</span></div><div class="p8-readout"><span class="p8-readout-label">c</span><span class="p8-readout-value" id="lr2-c">4200</span><span class="p8-readout-unit">Дж/(кг·К)</span></div></div>\'',
|
||||
`
|
||||
const svg = P8Helpers.svg.create(560, 260);
|
||||
svg.setAttribute('width','100%'); svg.setAttribute('height','100%'); svg.style.display='block';
|
||||
sb.appendChild(svg);
|
||||
let P=500, m=0.5, t=120;
|
||||
const c_const = 4200; /* предположим вода */
|
||||
function render(){
|
||||
svg.innerHTML='';
|
||||
const Q = P*t;
|
||||
const dT = Q/(c_const*m);
|
||||
/* Vessel */
|
||||
const ht = 50+m*60;
|
||||
svg.appendChild(P8Helpers.svg.el('rect', { x: 200, y: 200-ht, width: 160, height: ht, rx: 5, fill: P8Helpers.thermal.tempColor(Math.min(1, (20+dT)/120)), stroke: '#0f172a', 'stroke-width': 2, opacity: 0.85 }));
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x: 280, y: 200-ht+22, 'font-family':"'JetBrains Mono',monospace", 'font-size':12, 'font-weight':700, fill:'#fff', 'text-anchor':'middle', text: 'm='+m+' кг воды' }));
|
||||
/* Heater */
|
||||
svg.appendChild(P8Helpers.svg.el('rect', { x: 240, y: 205, width: 80, height: 14, fill: '#dc2626', rx: 3 }));
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x: 280, y: 235, 'font-family':"'Inter',sans-serif", 'font-size':11, 'font-weight':700, fill:'#dc2626', 'text-anchor':'middle', text: 'нагреватель P='+P+' Вт' }));
|
||||
/* Thermometer */
|
||||
svg.appendChild(P8Helpers.thermal.thermometerSVG(120, 60, 110, Math.min(1, (20+dT)/120)));
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x: 120, y: 50, 'font-family':"'JetBrains Mono',monospace", 'font-size':11, 'font-weight':800, fill:'#0f172a', 'text-anchor':'middle', text: 'T='+Math.round(20+dT)+'°C' }));
|
||||
/* Updates */
|
||||
document.getElementById('lr2-q').textContent = (Q/1000).toFixed(1);
|
||||
document.getElementById('lr2-dt').textContent = Math.round(dT);
|
||||
document.getElementById('lr2-c').textContent = c_const;
|
||||
}
|
||||
document.getElementById('lr2-p').oninput = ev => { P = +ev.target.value; document.getElementById('lr2-p-val').textContent = P; render(); };
|
||||
document.getElementById('lr2-m').oninput = ev => { m = +ev.target.value; document.getElementById('lr2-m-val').textContent = m.toFixed(1); render(); };
|
||||
document.getElementById('lr2-t').oninput = ev => { t = +ev.target.value; document.getElementById('lr2-t-val').textContent = t; render(); };
|
||||
render();
|
||||
`);
|
||||
|
||||
// ============================================================
|
||||
// ЛР3 — Простейшая цепь (батарея + лампа + А + V)
|
||||
// ============================================================
|
||||
injectIV6('lr3', 'Сборка простейшей цепи',
|
||||
'Цепь: батарея → амперметр → лампа → вольтметр (параллельно). Двигай U — показания приборов обновляются.',
|
||||
'+\'<div class="p8-scrubber" style="margin-top:10px"><span class="p8-scrubber-label">U батареи</span><input type="range" id="lr3-u" min="1" max="12" step="0.1" value="6"><span class="p8-scrubber-value"><span id="lr3-u-val">6.0</span><span class="p8-unit">В</span></span></div>\'+\'<div style="margin-top:8px;display:flex;gap:10px;flex-wrap:wrap"><div class="p8-readout"><span class="p8-readout-label">A показывает</span><span class="p8-readout-value" id="lr3-a">0.50</span><span class="p8-readout-unit">А</span></div><div class="p8-readout"><span class="p8-readout-label">V показывает</span><span class="p8-readout-value" id="lr3-v">6.0</span><span class="p8-readout-unit">В</span></div></div>\'',
|
||||
`
|
||||
const svg = P8Helpers.svg.create(560, 260);
|
||||
svg.setAttribute('width','100%'); svg.setAttribute('height','100%'); svg.style.display='block';
|
||||
sb.appendChild(svg);
|
||||
let U=6;
|
||||
const R=12;
|
||||
function render(){
|
||||
svg.innerHTML='';
|
||||
const I = U/R;
|
||||
/* Battery left */
|
||||
svg.appendChild(P8Helpers.em.circuitComponent('battery', 80, 120, 'h', U.toFixed(1)+' В'));
|
||||
/* Ammeter */
|
||||
svg.appendChild(P8Helpers.em.circuitComponent('ammeter', 220, 120, 'h'));
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x: 220, y: 100, 'font-family':"'JetBrains Mono',monospace", 'font-size':10, 'font-weight':800, fill:'#dc2626', 'text-anchor':'middle', text: I.toFixed(2)+' А' }));
|
||||
/* Lamp */
|
||||
const lampG = P8Helpers.svg.el('g', { transform: 'translate(380, 120)' });
|
||||
const br = Math.min(1, I/1.2);
|
||||
lampG.appendChild(P8Helpers.svg.el('circle', { cx: 0, cy: 0, r: 26, fill: '#fef3c7', opacity: br*0.6+0.1 }));
|
||||
lampG.appendChild(P8Helpers.svg.el('circle', { cx: 0, cy: 0, r: 16, fill: '#fef3c7', stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(lampG);
|
||||
/* Voltmeter (parallel above lamp) */
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 380, y1: 90, x2: 380, y2: 50, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 380, y1: 50, x2: 480, y2: 50, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.em.circuitComponent('voltmeter', 480, 50, 'h'));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 480, y1: 50, x2: 480, y2: 120, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x: 480, y: 30, 'font-family':"'JetBrains Mono',monospace", 'font-size':10, 'font-weight':800, fill:'#2563eb', 'text-anchor':'middle', text: U.toFixed(1)+' В' }));
|
||||
/* Wires */
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 110, y1: 120, x2: 190, y2: 120, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 250, y1: 120, x2: 354, y2: 120, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 380, y1: 136, x2: 510, y2: 136, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 510, y1: 136, x2: 510, y2: 190, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 50, y1: 120, x2: 50, y2: 190, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 50, y1: 190, x2: 510, y2: 190, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
/* Updates */
|
||||
document.getElementById('lr3-a').textContent = I.toFixed(2);
|
||||
document.getElementById('lr3-v').textContent = U.toFixed(1);
|
||||
}
|
||||
document.getElementById('lr3-u').oninput = ev => { U = +ev.target.value; document.getElementById('lr3-u-val').textContent = U.toFixed(1); render(); };
|
||||
render();
|
||||
`);
|
||||
|
||||
// ============================================================
|
||||
// ЛР4 — Последовательное соединение
|
||||
// ============================================================
|
||||
injectIV6('lr4', 'Последовательное соединение проводников',
|
||||
'Двигай R₁, R₂. Проверь: ток одинаков везде; напряжения складываются U = U₁ + U₂.',
|
||||
'+\'<div style="margin-top:10px;display:grid;grid-template-columns:1fr 1fr;gap:8px"><div class="p8-scrubber"><span class="p8-scrubber-label">R₁</span><input type="range" id="lr4-r1" min="1" max="50" step="1" value="10"><span class="p8-scrubber-value"><span id="lr4-r1-val">10</span><span class="p8-unit">Ом</span></span></div><div class="p8-scrubber"><span class="p8-scrubber-label">R₂</span><input type="range" id="lr4-r2" min="1" max="50" step="1" value="20"><span class="p8-scrubber-value"><span id="lr4-r2-val">20</span><span class="p8-unit">Ом</span></span></div></div>\'+\'<div style="margin-top:8px;display:flex;gap:10px;flex-wrap:wrap"><div class="p8-readout"><span class="p8-readout-label">U₁</span><span class="p8-readout-value" id="lr4-u1">4</span><span class="p8-readout-unit">В</span></div><div class="p8-readout"><span class="p8-readout-label">U₂</span><span class="p8-readout-value" id="lr4-u2">8</span><span class="p8-readout-unit">В</span></div><div class="p8-readout"><span class="p8-readout-label">I</span><span class="p8-readout-value" id="lr4-i">0.4</span><span class="p8-readout-unit">А</span></div></div>\'',
|
||||
`
|
||||
const svg = P8Helpers.svg.create(560, 260);
|
||||
svg.setAttribute('width','100%'); svg.setAttribute('height','100%'); svg.style.display='block';
|
||||
sb.appendChild(svg);
|
||||
const U = 12;
|
||||
let R1=10, R2=20;
|
||||
function render(){
|
||||
svg.innerHTML='';
|
||||
const R = R1+R2, I = U/R, U1 = I*R1, U2 = I*R2;
|
||||
/* Battery */
|
||||
svg.appendChild(P8Helpers.em.circuitComponent('battery', 80, 130, 'h', U+' В'));
|
||||
/* R1 */
|
||||
svg.appendChild(P8Helpers.em.circuitComponent('resistor', 230, 130, 'h', R1+' Ом'));
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x: 230, y: 110, 'font-family':"'JetBrains Mono',monospace", 'font-size':10, 'font-weight':800, fill:'#dc2626', 'text-anchor':'middle', text: 'U₁='+U1.toFixed(1)+' В' }));
|
||||
/* R2 */
|
||||
svg.appendChild(P8Helpers.em.circuitComponent('resistor', 400, 130, 'h', R2+' Ом'));
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x: 400, y: 110, 'font-family':"'JetBrains Mono',monospace", 'font-size':10, 'font-weight':800, fill:'#dc2626', 'text-anchor':'middle', text: 'U₂='+U2.toFixed(1)+' В' }));
|
||||
/* Wires */
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 110, y1: 130, x2: 200, y2: 130, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 260, y1: 130, x2: 370, y2: 130, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 430, y1: 130, x2: 510, y2: 130, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 510, y1: 130, x2: 510, y2: 200, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 50, y1: 130, x2: 50, y2: 200, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 50, y1: 200, x2: 510, y2: 200, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
/* I label */
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x: 280, y: 220, 'font-family':"'JetBrains Mono',monospace", 'font-size':12, 'font-weight':800, fill:'#10b981', 'text-anchor':'middle', text: 'I = '+I.toFixed(3)+' А (одинаков везде)' }));
|
||||
/* Updates */
|
||||
document.getElementById('lr4-u1').textContent = U1.toFixed(1);
|
||||
document.getElementById('lr4-u2').textContent = U2.toFixed(1);
|
||||
document.getElementById('lr4-i').textContent = I.toFixed(3);
|
||||
}
|
||||
document.getElementById('lr4-r1').oninput = ev => { R1 = +ev.target.value; document.getElementById('lr4-r1-val').textContent = R1; render(); };
|
||||
document.getElementById('lr4-r2').oninput = ev => { R2 = +ev.target.value; document.getElementById('lr4-r2-val').textContent = R2; render(); };
|
||||
render();
|
||||
`);
|
||||
|
||||
// ============================================================
|
||||
// ЛР5 — Параллельное соединение
|
||||
// ============================================================
|
||||
injectIV6('lr5', 'Параллельное соединение проводников',
|
||||
'Двигай R₁, R₂. Проверь: напряжение одинаково на обоих, токи складываются I = I₁ + I₂.',
|
||||
'+\'<div style="margin-top:10px;display:grid;grid-template-columns:1fr 1fr;gap:8px"><div class="p8-scrubber"><span class="p8-scrubber-label">R₁</span><input type="range" id="lr5-r1" min="1" max="50" step="1" value="20"><span class="p8-scrubber-value"><span id="lr5-r1-val">20</span><span class="p8-unit">Ом</span></span></div><div class="p8-scrubber"><span class="p8-scrubber-label">R₂</span><input type="range" id="lr5-r2" min="1" max="50" step="1" value="30"><span class="p8-scrubber-value"><span id="lr5-r2-val">30</span><span class="p8-unit">Ом</span></span></div></div>\'+\'<div style="margin-top:8px;display:flex;gap:10px;flex-wrap:wrap"><div class="p8-readout"><span class="p8-readout-label">I₁</span><span class="p8-readout-value" id="lr5-i1">0.6</span><span class="p8-readout-unit">А</span></div><div class="p8-readout"><span class="p8-readout-label">I₂</span><span class="p8-readout-value" id="lr5-i2">0.4</span><span class="p8-readout-unit">А</span></div><div class="p8-readout"><span class="p8-readout-label">I</span><span class="p8-readout-value" id="lr5-i">1.0</span><span class="p8-readout-unit">А</span></div></div>\'',
|
||||
`
|
||||
const svg = P8Helpers.svg.create(560, 260);
|
||||
svg.setAttribute('width','100%'); svg.setAttribute('height','100%'); svg.style.display='block';
|
||||
sb.appendChild(svg);
|
||||
const U = 12;
|
||||
let R1=20, R2=30;
|
||||
function render(){
|
||||
svg.innerHTML='';
|
||||
const I1=U/R1, I2=U/R2, I=I1+I2;
|
||||
svg.appendChild(P8Helpers.em.circuitComponent('battery', 80, 130, 'h', U+' В'));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 110, y1: 130, x2: 200, y2: 130, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 200, y1: 80, x2: 200, y2: 180, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 380, y1: 80, x2: 380, y2: 180, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 200, y1: 80, x2: 290, y2: 80, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 320, y1: 80, x2: 380, y2: 80, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 200, y1: 180, x2: 290, y2: 180, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 320, y1: 180, x2: 380, y2: 180, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.em.circuitComponent('resistor', 305, 80, 'h', R1+' Ом'));
|
||||
svg.appendChild(P8Helpers.em.circuitComponent('resistor', 305, 180, 'h', R2+' Ом'));
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x: 290, y: 68, 'font-family':"'JetBrains Mono',monospace", 'font-size':10, 'font-weight':800, fill:'#dc2626', 'text-anchor':'middle', text: 'I₁='+I1.toFixed(2)+' А' }));
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x: 290, y: 200, 'font-family':"'JetBrains Mono',monospace", 'font-size':10, 'font-weight':800, fill:'#dc2626', 'text-anchor':'middle', text: 'I₂='+I2.toFixed(2)+' А' }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 380, y1: 130, x2: 510, y2: 130, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 510, y1: 130, x2: 510, y2: 220, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 50, y1: 130, x2: 50, y2: 220, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 50, y1: 220, x2: 510, y2: 220, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x: 150, y: 250, 'font-family':"'JetBrains Mono',monospace", 'font-size':12, 'font-weight':800, fill:'#10b981', 'text-anchor':'middle', text: 'I='+I.toFixed(2)+' А' }));
|
||||
document.getElementById('lr5-i1').textContent = I1.toFixed(2);
|
||||
document.getElementById('lr5-i2').textContent = I2.toFixed(2);
|
||||
document.getElementById('lr5-i').textContent = I.toFixed(2);
|
||||
}
|
||||
document.getElementById('lr5-r1').oninput = ev => { R1 = +ev.target.value; document.getElementById('lr5-r1-val').textContent = R1; render(); };
|
||||
document.getElementById('lr5-r2').oninput = ev => { R2 = +ev.target.value; document.getElementById('lr5-r2-val').textContent = R2; render(); };
|
||||
render();
|
||||
`);
|
||||
|
||||
// ============================================================
|
||||
// ЛР6 — Работа и мощность (P=UI, A=Pt)
|
||||
// ============================================================
|
||||
injectIV6('lr6', 'Работа и мощность тока',
|
||||
'Задавай U, I и время t — рассчитаются P=UI, A=Pt. Лампа светится ярче с ростом P.',
|
||||
'+\'<div style="margin-top:10px;display:grid;grid-template-columns:1fr 1fr 1fr;gap:6px"><div class="p8-scrubber"><span class="p8-scrubber-label">U</span><input type="range" id="lr6-u" min="1" max="220" step="1" value="220"><span class="p8-scrubber-value"><span id="lr6-u-val">220</span><span class="p8-unit">В</span></span></div><div class="p8-scrubber"><span class="p8-scrubber-label">I</span><input type="range" id="lr6-i" min="0.01" max="5" step="0.01" value="0.5"><span class="p8-scrubber-value"><span id="lr6-i-val">0.50</span><span class="p8-unit">А</span></span></div><div class="p8-scrubber"><span class="p8-scrubber-label">t</span><input type="range" id="lr6-t" min="1" max="3600" step="1" value="60"><span class="p8-scrubber-value"><span id="lr6-t-val">60</span><span class="p8-unit">с</span></span></div></div>\'+\'<div style="margin-top:8px;display:flex;gap:10px;flex-wrap:wrap"><div class="p8-readout"><span class="p8-readout-label">P</span><span class="p8-readout-value" id="lr6-p">110</span><span class="p8-readout-unit">Вт</span></div><div class="p8-readout"><span class="p8-readout-label">A</span><span class="p8-readout-value" id="lr6-a">6.6</span><span class="p8-readout-unit">кДж</span></div></div>\'',
|
||||
`
|
||||
const svg = P8Helpers.svg.create(560, 260);
|
||||
svg.setAttribute('width','100%'); svg.setAttribute('height','100%'); svg.style.display='block';
|
||||
sb.appendChild(svg);
|
||||
let U=220, I=0.5, t=60;
|
||||
function render(){
|
||||
svg.innerHTML='';
|
||||
const P = U*I, A = P*t;
|
||||
const br = Math.min(1, P/200);
|
||||
/* Lamp */
|
||||
svg.appendChild(P8Helpers.svg.el('circle', { cx: 280, cy: 110, r: 55, fill: '#fef3c7', opacity: br*0.5+0.15 }));
|
||||
svg.appendChild(P8Helpers.svg.el('circle', { cx: 280, cy: 110, r: 35, fill: '#fde047', stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x: 280, y: 113, 'font-family':"'Unbounded',sans-serif", 'font-size':18, 'font-weight':900, fill:'#0f172a', 'text-anchor':'middle', text: P.toFixed(0)+' Вт' }));
|
||||
if (br > 0.5) {
|
||||
for (let i = 0; i < 8; i++) {
|
||||
const a = i*Math.PI/4;
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 280+45*Math.cos(a), y1: 110+45*Math.sin(a), x2: 280+68*Math.cos(a), y2: 110+68*Math.sin(a), stroke: '#facc15', 'stroke-width': 3 }));
|
||||
}
|
||||
}
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x: 280, y: 220, 'font-family':"'JetBrains Mono',monospace", 'font-size':13, 'font-weight':800, fill:'#0f172a', 'text-anchor':'middle', text: 'P = UI = '+P.toFixed(1)+' Вт, A = Pt = '+(A/1000).toFixed(1)+' кДж' }));
|
||||
document.getElementById('lr6-p').textContent = P.toFixed(1);
|
||||
document.getElementById('lr6-a').textContent = (A/1000).toFixed(2);
|
||||
}
|
||||
document.getElementById('lr6-u').oninput = ev => { U = +ev.target.value; document.getElementById('lr6-u-val').textContent = U; render(); };
|
||||
document.getElementById('lr6-i').oninput = ev => { I = +ev.target.value; document.getElementById('lr6-i-val').textContent = I.toFixed(2); render(); };
|
||||
document.getElementById('lr6-t').oninput = ev => { t = +ev.target.value; document.getElementById('lr6-t-val').textContent = t; render(); };
|
||||
render();
|
||||
`);
|
||||
|
||||
// ============================================================
|
||||
// ЛР7 — Отражение (закон отражения с протрактором)
|
||||
// ============================================================
|
||||
injectIV6('lr7', 'Закон отражения света',
|
||||
'Двигай угол падения α — угол отражения β равен ему. Луч идёт по правилу: «угол падения = углу отражения».',
|
||||
'+\'<div class="p8-scrubber" style="margin-top:10px"><span class="p8-scrubber-label">Угол падения</span><input type="range" id="lr7-a" min="0" max="80" step="1" value="40"><span class="p8-scrubber-value"><span id="lr7-a-val">40</span><span class="p8-unit">°</span></span></div>\'+\'<div style="margin-top:8px;display:flex;gap:10px;flex-wrap:wrap"><div class="p8-readout"><span class="p8-readout-label">α</span><span class="p8-readout-value" id="lr7-a-out">40</span><span class="p8-readout-unit">°</span></div><div class="p8-readout"><span class="p8-readout-label">β</span><span class="p8-readout-value" id="lr7-b">40</span><span class="p8-readout-unit">°</span></div></div>\'',
|
||||
`
|
||||
const svg = P8Helpers.svg.create(560, 260);
|
||||
svg.setAttribute('width','100%'); svg.setAttribute('height','100%'); svg.style.display='block';
|
||||
sb.appendChild(svg);
|
||||
let alpha = 40;
|
||||
function render(){
|
||||
svg.innerHTML='';
|
||||
const cx = 280, cy = 210;
|
||||
svg.appendChild(P8Helpers.optics.mirrorPlane(60, 210, 500, 210));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: cx, y1: 210, x2: cx, y2: 30, stroke: '#475569', 'stroke-width': 1.5, 'stroke-dasharray': '5 3' }));
|
||||
const aRad = alpha*Math.PI/180;
|
||||
const len = 170;
|
||||
/* Incident */
|
||||
const inX = cx - len*Math.sin(aRad), inY = cy - len*Math.cos(aRad);
|
||||
svg.appendChild(P8Helpers.optics.rayLine(inX, inY, cx, cy, { color: '#facc15', width: 3.5, glow: true }));
|
||||
/* Reflected */
|
||||
const rX = cx + len*Math.sin(aRad), rY = cy - len*Math.cos(aRad);
|
||||
svg.appendChild(P8Helpers.optics.rayLine(cx, cy, rX, rY, { color: '#facc15', width: 3.5, glow: true }));
|
||||
/* Angle arcs */
|
||||
svg.appendChild(P8Helpers.svg.el('path', { d: 'M '+(cx-25*Math.sin(aRad/2))+' '+(cy-25*Math.cos(aRad/2))+' A 25 25 0 0 1 '+cx+' '+(cy-25)+' ', fill: 'none', stroke: '#dc2626', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x: cx-22, y: cy-40, 'font-family':"'JetBrains Mono',monospace", 'font-size':13, 'font-weight':800, fill:'#dc2626', 'text-anchor':'middle', text: 'α='+alpha+'°' }));
|
||||
svg.appendChild(P8Helpers.svg.el('path', { d: 'M '+cx+' '+(cy-25)+' A 25 25 0 0 1 '+(cx+25*Math.sin(aRad/2))+' '+(cy-25*Math.cos(aRad/2))+' ', fill: 'none', stroke: '#16a34a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x: cx+22, y: cy-40, 'font-family':"'JetBrains Mono',monospace", 'font-size':13, 'font-weight':800, fill:'#16a34a', 'text-anchor':'middle', text: 'β='+alpha+'°' }));
|
||||
/* Verdict */
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x: 280, y: 250, 'font-family':"'JetBrains Mono',monospace", 'font-size':12, 'font-weight':700, fill:'#10b981', 'text-anchor':'middle', text: '✓ α = β — закон отражения' }));
|
||||
document.getElementById('lr7-a-out').textContent = alpha;
|
||||
document.getElementById('lr7-b').textContent = alpha;
|
||||
}
|
||||
document.getElementById('lr7-a').oninput = ev => { alpha = +ev.target.value; document.getElementById('lr7-a-val').textContent = alpha; render(); };
|
||||
render();
|
||||
`);
|
||||
|
||||
fs.writeFileSync(DST, h);
|
||||
console.log('lab final size:', h.length);
|
||||
|
||||
const scripts = [...h.matchAll(/<script>([\s\S]*?)<\/script>/g)];
|
||||
for (const m of scripts) {
|
||||
try { new Function(m[1]); }
|
||||
catch (e) { console.error('JS PARSE FAIL:', e.message.slice(0, 200)); process.exit(1); }
|
||||
}
|
||||
console.log('inline JS parses OK');
|
||||
@@ -165,13 +165,19 @@ a{color:inherit;text-decoration:none}
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header class="hdr">
|
||||
<div class="hdr-row">
|
||||
<div>
|
||||
<h1>Физика 8 · Лабораторный практикум</h1>
|
||||
<div class="hdr-sub">7 виртуальных лабораторных работ</div>
|
||||
</div>
|
||||
<div class="hdr-side">
|
||||
<header class="p8-hero" style="background:linear-gradient(115deg,#064e3b 0%,#10b981 60%,#6ee7b7 100%)">
|
||||
<div class="p8-hero-wm"><svg viewBox="0 0 100 100" aria-hidden="true">
|
||||
<path d="M40 12 L40 38 L18 80 C 15 88, 20 92, 26 92 L74 92 C 80 92, 85 88, 82 80 L60 38 L60 12 Z M 35 12 L65 12" stroke="currentColor" stroke-width="4" fill="none"/>
|
||||
<circle cx="38" cy="64" r="3" fill="currentColor"/>
|
||||
<circle cx="55" cy="76" r="3" fill="currentColor"/>
|
||||
<circle cx="44" cy="80" r="2" fill="currentColor"/>
|
||||
</svg></div>
|
||||
<div class="p8-hero-meter" id="p8-meter-lab"><span id="p8-meter-val">7</span>/7 ЛР</div>
|
||||
<div class="p8-hero-inner">
|
||||
<div class="p8-hero-eyebrow">Лабораторный практикум · 7 ЛР</div>
|
||||
<h1 class="p8-hero-title">Виртуальная лаборатория</h1>
|
||||
<div class="p8-hero-sub">Перетаскивайте термометры, нагреватели, динамометры и измерительные приборы. Собирайте установки и записывайте результаты.</div>
|
||||
<div class="hdr-side" style="margin-top:18px;display:flex;gap:8px;flex-wrap:wrap;position:relative;z-index:1">
|
||||
<a href="/textbook/physics-8" class="hdr-btn"><svg class="ic" viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg> К физике 8</a>
|
||||
<button id="search-btn" class="hdr-btn"><svg class="ic" viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="m21 21-4-4"/></svg> Поиск</button>
|
||||
<button id="sidebar-btn" class="hdr-btn"><svg class="ic" viewBox="0 0 24 24"><line x1="4" y1="6" x2="20" y2="6"/><line x1="4" y1="12" x2="20" y2="12"/><line x1="4" y1="18" x2="14" y2="18"/></svg> Шпаргалка</button>
|
||||
@@ -202,13 +208,20 @@ a{color:inherit;text-decoration:none}
|
||||
<div id="psel-grid" class="psel-grid"></div>
|
||||
</section>
|
||||
|
||||
<section id="sec-lr1" class="sec"><div class="sec-header"><span class="sec-num">ЛР 1</span><h2 class="sec-h">Изучение явления теплообмена при смешивании воды разной температуры</h2></div><div id="lr1-body"></div></section>
|
||||
<section id="sec-lr2" class="sec"><div class="sec-header"><span class="sec-num">ЛР 2</span><h2 class="sec-h">Определение удельной теплоёмкости твёрдого тела</h2></div><div id="lr2-body"></div></section>
|
||||
<section id="sec-lr3" class="sec"><div class="sec-header"><span class="sec-num">ЛР 3</span><h2 class="sec-h">Сборка простейшей электрической цепи и измерение силы тока и напряжения</h2></div><div id="lr3-body"></div></section>
|
||||
<section id="sec-lr4" class="sec"><div class="sec-header"><span class="sec-num">ЛР 4</span><h2 class="sec-h">Изучение последовательного соединения проводников</h2></div><div id="lr4-body"></div></section>
|
||||
<section id="sec-lr5" class="sec"><div class="sec-header"><span class="sec-num">ЛР 5</span><h2 class="sec-h">Изучение параллельного соединения проводников</h2></div><div id="lr5-body"></div></section>
|
||||
<section id="sec-lr6" class="sec"><div class="sec-header"><span class="sec-num">ЛР 6</span><h2 class="sec-h">Определение работы и мощности электрического тока</h2></div><div id="lr6-body"></div></section>
|
||||
<section id="sec-lr7" class="sec"><div class="sec-header"><span class="sec-num">ЛР 7</span><h2 class="sec-h">Изучение явления отражения света</h2></div><div id="lr7-body"></div></section>
|
||||
<section id="sec-lr1" class="sec">
|
||||
<div class="p8-sec-wm" id="p8-sec-wm-lr1" aria-hidden="true"><svg viewBox="0 0 100 100"><rect x="30" y="20" width="40" height="60" fill="none" stroke="currentColor" stroke-width="4" rx="4"/><rect x="36" y="40" width="28" height="35" fill="currentColor" opacity="0.6"/></svg></div><div class="sec-header"><span class="sec-num">ЛР 1</span><h2 class="sec-h">Изучение явления теплообмена при смешивании воды разной температуры</h2></div><div id="lr1-body"></div></section>
|
||||
<section id="sec-lr2" class="sec">
|
||||
<div class="p8-sec-wm" id="p8-sec-wm-lr2" aria-hidden="true"><svg viewBox="0 0 100 100"><rect x="20" y="40" width="60" height="40" fill="none" stroke="currentColor" stroke-width="3"/><circle cx="50" cy="60" r="10" fill="currentColor"/></svg></div><div class="sec-header"><span class="sec-num">ЛР 2</span><h2 class="sec-h">Определение удельной теплоёмкости твёрдого тела</h2></div><div id="lr2-body"></div></section>
|
||||
<section id="sec-lr3" class="sec">
|
||||
<div class="p8-sec-wm" id="p8-sec-wm-lr3" aria-hidden="true"><svg viewBox="0 0 100 100"><rect x="20" y="40" width="60" height="30" fill="none" stroke="currentColor" stroke-width="3"/><circle cx="50" cy="55" r="8" fill="none" stroke="currentColor" stroke-width="3"/></svg></div><div class="sec-header"><span class="sec-num">ЛР 3</span><h2 class="sec-h">Сборка простейшей электрической цепи и измерение силы тока и напряжения</h2></div><div id="lr3-body"></div></section>
|
||||
<section id="sec-lr4" class="sec">
|
||||
<div class="p8-sec-wm" id="p8-sec-wm-lr4" aria-hidden="true"><svg viewBox="0 0 100 100"><path d="M20 50 L30 50 L35 40 L45 60 L55 40 L65 60 L70 50 L80 50" stroke="currentColor" stroke-width="3" fill="none"/></svg></div><div class="sec-header"><span class="sec-num">ЛР 4</span><h2 class="sec-h">Изучение последовательного соединения проводников</h2></div><div id="lr4-body"></div></section>
|
||||
<section id="sec-lr5" class="sec">
|
||||
<div class="p8-sec-wm" id="p8-sec-wm-lr5" aria-hidden="true"><svg viewBox="0 0 100 100"><path d="M20 30 L80 30 M20 70 L80 70 M50 30 L50 70" stroke="currentColor" stroke-width="3" fill="none"/></svg></div><div class="sec-header"><span class="sec-num">ЛР 5</span><h2 class="sec-h">Изучение параллельного соединения проводников</h2></div><div id="lr5-body"></div></section>
|
||||
<section id="sec-lr6" class="sec">
|
||||
<div class="p8-sec-wm" id="p8-sec-wm-lr6" aria-hidden="true"><svg viewBox="0 0 100 100"><text x="50" y="60" font-family="Unbounded" font-size="32" font-weight="900" fill="currentColor" text-anchor="middle">P</text></svg></div><div class="sec-header"><span class="sec-num">ЛР 6</span><h2 class="sec-h">Определение работы и мощности электрического тока</h2></div><div id="lr6-body"></div></section>
|
||||
<section id="sec-lr7" class="sec">
|
||||
<div class="p8-sec-wm" id="p8-sec-wm-lr7" aria-hidden="true"><svg viewBox="0 0 100 100"><line x1="20" y1="20" x2="50" y2="50" stroke="currentColor" stroke-width="4"/><line x1="50" y1="50" x2="80" y2="20" stroke="currentColor" stroke-width="4"/></svg></div><div class="sec-header"><span class="sec-num">ЛР 7</span><h2 class="sec-h">Изучение явления отражения света</h2></div><div id="lr7-body"></div></section>
|
||||
|
||||
</div>
|
||||
<aside class="col-side" id="col-side"><div id="sidebar-content"></div></aside>
|
||||
@@ -697,10 +710,60 @@ function build_lr1(){
|
||||
+'</tbody></table>'
|
||||
+'<p><b>Вывод:</b> расчёт по формуле подтверждается опытом с погрешностью менее 2%. Это подтверждает закон сохранения теплоты при смешивании.</p>');
|
||||
|
||||
/* IV6 — Теплообмен — смешивание жидкостей (Phase 4) */
|
||||
h += '<div class="wg p8-iv6">'
|
||||
+'<div class="wg-header"><span class="wg-badge p8-badge" style="background:#d1fae5;color:#047857">IV-6</span><div class="wg-title">Теплообмен — смешивание жидкостей</div></div>'
|
||||
+'<div class="wg-help">Задавай начальные T₁ и T₂ скрубберами. Кнопка «Смешать» — итоговая T рассчитывается через тепловой баланс.</div>'
|
||||
+'<div class="p8-sandbox" id="lr1-iv6-sandbox" style="height:260px"></div>'
|
||||
+'<div style="margin-top:10px;display:grid;grid-template-columns:1fr 1fr;gap:8px"><div class="p8-scrubber"><span class="p8-scrubber-label">T₁ (0.5 кг)</span><input type="range" id="lr1-t1" min="0" max="100" step="1" value="80"><span class="p8-scrubber-value"><span id="lr1-t1-val">80</span><span class="p8-unit">°C</span></span></div><div class="p8-scrubber"><span class="p8-scrubber-label">T₂ (1 кг)</span><input type="range" id="lr1-t2" min="0" max="100" step="1" value="20"><span class="p8-scrubber-value"><span id="lr1-t2-val">20</span><span class="p8-unit">°C</span></span></div></div>'+'<div style="margin-top:8px;display:flex;gap:10px;flex-wrap:wrap"><button class="btn primary" id="lr1-mix">Смешать</button><div class="p8-readout"><span class="p8-readout-label">T_итог</span><span class="p8-readout-value" id="lr1-tf">—</span><span class="p8-readout-unit">°C</span></div></div>'
|
||||
+'</div>';
|
||||
|
||||
box.innerHTML = h + secNavFor('lr1') + readButton('lr1');
|
||||
renderMath(box); wireReadBtn('lr1');
|
||||
_initLR1_iv6();
|
||||
_lr1_sim(); _labWireSubmit('lr1', 'lr1');
|
||||
}
|
||||
|
||||
function _initLR1_iv6(){
|
||||
const sb = document.getElementById('lr1-iv6-sandbox');
|
||||
if (!sb || !window.P8Helpers) return;
|
||||
|
||||
const svg = P8Helpers.svg.create(560, 260);
|
||||
svg.setAttribute('width','100%'); svg.setAttribute('height','100%'); svg.style.display='block';
|
||||
sb.appendChild(svg);
|
||||
let T1=80, T2=20, mixed=false, Tf=50;
|
||||
function vessel(x, y, T, m){
|
||||
const g = P8Helpers.svg.el('g', { transform: 'translate('+x+','+y+')' });
|
||||
const ht = 40 + m*50;
|
||||
g.appendChild(P8Helpers.svg.el('rect', { x:-32, y:-ht, width:64, height:ht, rx:5, fill:'rgba(255,255,255,.7)', stroke:'#0f172a', 'stroke-width':2 }));
|
||||
g.appendChild(P8Helpers.svg.el('rect', { x:-29, y:-ht+3, width:58, height:ht-5, rx:3, fill: P8Helpers.thermal.tempColor(T/100) }));
|
||||
g.appendChild(P8Helpers.svg.el('text', { x:0, y:18, 'font-family':"'JetBrains Mono',monospace", 'font-size':12, 'font-weight':700, fill:'#0f172a', 'text-anchor':'middle', text: 'T='+Math.round(T)+'°C' }));
|
||||
return g;
|
||||
}
|
||||
function render(){
|
||||
svg.innerHTML='';
|
||||
if (!mixed){
|
||||
svg.appendChild(vessel(160, 180, T1, 0.5));
|
||||
svg.appendChild(vessel(400, 180, T2, 1));
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x:160, y:235, 'font-family':"'Inter',sans-serif", 'font-size':11, fill:'var(--p8-muted,#64748b)', 'text-anchor':'middle', text:'m₁=0.5 кг' }));
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x:400, y:235, 'font-family':"'Inter',sans-serif", 'font-size':11, fill:'var(--p8-muted,#64748b)', 'text-anchor':'middle', text:'m₂=1 кг' }));
|
||||
} else {
|
||||
svg.appendChild(vessel(280, 180, Tf, 1.5));
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x:280, y:70, 'font-family':"'Unbounded',sans-serif", 'font-size':18, 'font-weight':900, fill:'#10b981', 'text-anchor':'middle', text: 'T_итог = '+Math.round(Tf)+' °C' }));
|
||||
}
|
||||
}
|
||||
document.getElementById('lr1-t1').oninput = ev => { T1 = +ev.target.value; document.getElementById('lr1-t1-val').textContent = T1; mixed = false; document.getElementById('lr1-tf').textContent='—'; render(); };
|
||||
document.getElementById('lr1-t2').oninput = ev => { T2 = +ev.target.value; document.getElementById('lr1-t2-val').textContent = T2; mixed = false; document.getElementById('lr1-tf').textContent='—'; render(); };
|
||||
document.getElementById('lr1-mix').onclick = () => {
|
||||
Tf = (0.5*T1 + 1*T2)/(0.5+1);
|
||||
mixed = true;
|
||||
if (window.P8Anim) P8Anim.tween({ from: T1, to: Tf, duration: 1200, easing: 'cubicInOut', onUpdate: t => { Tf = t; render(); document.getElementById('lr1-tf').textContent = Math.round(t); } });
|
||||
else { render(); document.getElementById('lr1-tf').textContent = Math.round(Tf); }
|
||||
if (window.addXp) addXp(15, 'lr1-iv6');
|
||||
};
|
||||
render();
|
||||
|
||||
}
|
||||
function _lr1_sim(){
|
||||
const svg = document.getElementById('lr1-sim'); if(!svg) return;
|
||||
function u(){
|
||||
@@ -772,10 +835,54 @@ function build_lr2(){
|
||||
+'<tr><td style="padding:5px">$t_{гор}, t_х, t_{см}$</td><td style="padding:5px;text-align:right"><b id="lr2-r2">100, 18, 22.5</b></td></tr>'
|
||||
+'<tr><td style="padding:5px">$c$ найдено</td><td style="padding:5px;text-align:right"><b id="lr2-r3">380</b> Дж/(кг·К)</td></tr></table>'
|
||||
+'<p><b>Вывод:</b> найденная $c$ совпадает с табличной с точностью до экспериментальной погрешности.</p>');
|
||||
/* IV6 — Измерение удельной теплоёмкости (Phase 4) */
|
||||
h += '<div class="wg p8-iv6">'
|
||||
+'<div class="wg-header"><span class="wg-badge p8-badge" style="background:#d1fae5;color:#047857">IV-6</span><div class="wg-title">Измерение удельной теплоёмкости</div></div>'
|
||||
+'<div class="wg-help">Нагреватель мощности P подаёт Q=Pt в массу m. Из ΔT находим $c = Q/(m\\Delta T)$.</div>'
|
||||
+'<div class="p8-sandbox" id="lr2-iv6-sandbox" style="height:260px"></div>'
|
||||
+'<div style="margin-top:10px;display:grid;grid-template-columns:1fr 1fr 1fr;gap:6px"><div class="p8-scrubber"><span class="p8-scrubber-label">P</span><input type="range" id="lr2-p" min="50" max="1000" step="10" value="500"><span class="p8-scrubber-value"><span id="lr2-p-val">500</span><span class="p8-unit">Вт</span></span></div><div class="p8-scrubber"><span class="p8-scrubber-label">m</span><input type="range" id="lr2-m" min="0.1" max="2" step="0.1" value="0.5"><span class="p8-scrubber-value"><span id="lr2-m-val">0.5</span><span class="p8-unit">кг</span></span></div><div class="p8-scrubber"><span class="p8-scrubber-label">t</span><input type="range" id="lr2-t" min="10" max="600" step="5" value="120"><span class="p8-scrubber-value"><span id="lr2-t-val">120</span><span class="p8-unit">с</span></span></div></div>'+'<div style="margin-top:8px;display:flex;gap:10px;flex-wrap:wrap"><div class="p8-readout"><span class="p8-readout-label">Q</span><span class="p8-readout-value" id="lr2-q">60</span><span class="p8-readout-unit">кДж</span></div><div class="p8-readout"><span class="p8-readout-label">ΔT</span><span class="p8-readout-value" id="lr2-dt">29</span><span class="p8-readout-unit">К</span></div><div class="p8-readout"><span class="p8-readout-label">c</span><span class="p8-readout-value" id="lr2-c">4200</span><span class="p8-readout-unit">Дж/(кг·К)</span></div></div>'
|
||||
+'</div>';
|
||||
|
||||
box.innerHTML = h + secNavFor('lr2') + readButton('lr2');
|
||||
renderMath(box); wireReadBtn('lr2');
|
||||
_initLR2_iv6();
|
||||
_lr2_sim(); _labWireSubmit('lr2', 'lr2');
|
||||
}
|
||||
|
||||
function _initLR2_iv6(){
|
||||
const sb = document.getElementById('lr2-iv6-sandbox');
|
||||
if (!sb || !window.P8Helpers) return;
|
||||
|
||||
const svg = P8Helpers.svg.create(560, 260);
|
||||
svg.setAttribute('width','100%'); svg.setAttribute('height','100%'); svg.style.display='block';
|
||||
sb.appendChild(svg);
|
||||
let P=500, m=0.5, t=120;
|
||||
const c_const = 4200; /* предположим вода */
|
||||
function render(){
|
||||
svg.innerHTML='';
|
||||
const Q = P*t;
|
||||
const dT = Q/(c_const*m);
|
||||
/* Vessel */
|
||||
const ht = 50+m*60;
|
||||
svg.appendChild(P8Helpers.svg.el('rect', { x: 200, y: 200-ht, width: 160, height: ht, rx: 5, fill: P8Helpers.thermal.tempColor(Math.min(1, (20+dT)/120)), stroke: '#0f172a', 'stroke-width': 2, opacity: 0.85 }));
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x: 280, y: 200-ht+22, 'font-family':"'JetBrains Mono',monospace", 'font-size':12, 'font-weight':700, fill:'#fff', 'text-anchor':'middle', text: 'm='+m+' кг воды' }));
|
||||
/* Heater */
|
||||
svg.appendChild(P8Helpers.svg.el('rect', { x: 240, y: 205, width: 80, height: 14, fill: '#dc2626', rx: 3 }));
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x: 280, y: 235, 'font-family':"'Inter',sans-serif", 'font-size':11, 'font-weight':700, fill:'#dc2626', 'text-anchor':'middle', text: 'нагреватель P='+P+' Вт' }));
|
||||
/* Thermometer */
|
||||
svg.appendChild(P8Helpers.thermal.thermometerSVG(120, 60, 110, Math.min(1, (20+dT)/120)));
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x: 120, y: 50, 'font-family':"'JetBrains Mono',monospace", 'font-size':11, 'font-weight':800, fill:'#0f172a', 'text-anchor':'middle', text: 'T='+Math.round(20+dT)+'°C' }));
|
||||
/* Updates */
|
||||
document.getElementById('lr2-q').textContent = (Q/1000).toFixed(1);
|
||||
document.getElementById('lr2-dt').textContent = Math.round(dT);
|
||||
document.getElementById('lr2-c').textContent = c_const;
|
||||
}
|
||||
document.getElementById('lr2-p').oninput = ev => { P = +ev.target.value; document.getElementById('lr2-p-val').textContent = P; render(); };
|
||||
document.getElementById('lr2-m').oninput = ev => { m = +ev.target.value; document.getElementById('lr2-m-val').textContent = m.toFixed(1); render(); };
|
||||
document.getElementById('lr2-t').oninput = ev => { t = +ev.target.value; document.getElementById('lr2-t-val').textContent = t; render(); };
|
||||
render();
|
||||
|
||||
}
|
||||
function _lr2_sim(){
|
||||
function u(){
|
||||
const c = +document.getElementById('lr2-mat').value;
|
||||
@@ -827,10 +934,64 @@ function build_lr3(){
|
||||
+'<span>Расчёт: $R = U/I$ = <b id="lr3-r">—</b> Ом</span></div></div>';
|
||||
h += _labResult('lr3', '<p>В цепи лампа сопротивлением $\\sim 8$ Ом, питание от 4,5 В. Ожидаемый ток $\\sim 0{,}5$ А.</p>'
|
||||
+'<p><b>Вывод:</b> амперметр включается последовательно с потребителем (через него идёт измеряемый ток); вольтметр — параллельно (между точками, где меряется $U$).</p>');
|
||||
/* IV6 — Сборка простейшей цепи (Phase 4) */
|
||||
h += '<div class="wg p8-iv6">'
|
||||
+'<div class="wg-header"><span class="wg-badge p8-badge" style="background:#d1fae5;color:#047857">IV-6</span><div class="wg-title">Сборка простейшей цепи</div></div>'
|
||||
+'<div class="wg-help">Цепь: батарея → амперметр → лампа → вольтметр (параллельно). Двигай U — показания приборов обновляются.</div>'
|
||||
+'<div class="p8-sandbox" id="lr3-iv6-sandbox" style="height:260px"></div>'
|
||||
+'<div class="p8-scrubber" style="margin-top:10px"><span class="p8-scrubber-label">U батареи</span><input type="range" id="lr3-u" min="1" max="12" step="0.1" value="6"><span class="p8-scrubber-value"><span id="lr3-u-val">6.0</span><span class="p8-unit">В</span></span></div>'+'<div style="margin-top:8px;display:flex;gap:10px;flex-wrap:wrap"><div class="p8-readout"><span class="p8-readout-label">A показывает</span><span class="p8-readout-value" id="lr3-a">0.50</span><span class="p8-readout-unit">А</span></div><div class="p8-readout"><span class="p8-readout-label">V показывает</span><span class="p8-readout-value" id="lr3-v">6.0</span><span class="p8-readout-unit">В</span></div></div>'
|
||||
+'</div>';
|
||||
|
||||
box.innerHTML = h + secNavFor('lr3') + readButton('lr3');
|
||||
renderMath(box); wireReadBtn('lr3');
|
||||
_initLR3_iv6();
|
||||
_lr3_sim(); _labWireSubmit('lr3', 'lr3');
|
||||
}
|
||||
|
||||
function _initLR3_iv6(){
|
||||
const sb = document.getElementById('lr3-iv6-sandbox');
|
||||
if (!sb || !window.P8Helpers) return;
|
||||
|
||||
const svg = P8Helpers.svg.create(560, 260);
|
||||
svg.setAttribute('width','100%'); svg.setAttribute('height','100%'); svg.style.display='block';
|
||||
sb.appendChild(svg);
|
||||
let U=6;
|
||||
const R=12;
|
||||
function render(){
|
||||
svg.innerHTML='';
|
||||
const I = U/R;
|
||||
/* Battery left */
|
||||
svg.appendChild(P8Helpers.em.circuitComponent('battery', 80, 120, 'h', U.toFixed(1)+' В'));
|
||||
/* Ammeter */
|
||||
svg.appendChild(P8Helpers.em.circuitComponent('ammeter', 220, 120, 'h'));
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x: 220, y: 100, 'font-family':"'JetBrains Mono',monospace", 'font-size':10, 'font-weight':800, fill:'#dc2626', 'text-anchor':'middle', text: I.toFixed(2)+' А' }));
|
||||
/* Lamp */
|
||||
const lampG = P8Helpers.svg.el('g', { transform: 'translate(380, 120)' });
|
||||
const br = Math.min(1, I/1.2);
|
||||
lampG.appendChild(P8Helpers.svg.el('circle', { cx: 0, cy: 0, r: 26, fill: '#fef3c7', opacity: br*0.6+0.1 }));
|
||||
lampG.appendChild(P8Helpers.svg.el('circle', { cx: 0, cy: 0, r: 16, fill: '#fef3c7', stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(lampG);
|
||||
/* Voltmeter (parallel above lamp) */
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 380, y1: 90, x2: 380, y2: 50, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 380, y1: 50, x2: 480, y2: 50, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.em.circuitComponent('voltmeter', 480, 50, 'h'));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 480, y1: 50, x2: 480, y2: 120, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x: 480, y: 30, 'font-family':"'JetBrains Mono',monospace", 'font-size':10, 'font-weight':800, fill:'#2563eb', 'text-anchor':'middle', text: U.toFixed(1)+' В' }));
|
||||
/* Wires */
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 110, y1: 120, x2: 190, y2: 120, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 250, y1: 120, x2: 354, y2: 120, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 380, y1: 136, x2: 510, y2: 136, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 510, y1: 136, x2: 510, y2: 190, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 50, y1: 120, x2: 50, y2: 190, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 50, y1: 190, x2: 510, y2: 190, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
/* Updates */
|
||||
document.getElementById('lr3-a').textContent = I.toFixed(2);
|
||||
document.getElementById('lr3-v').textContent = U.toFixed(1);
|
||||
}
|
||||
document.getElementById('lr3-u').oninput = ev => { U = +ev.target.value; document.getElementById('lr3-u-val').textContent = U.toFixed(1); render(); };
|
||||
render();
|
||||
|
||||
}
|
||||
function _lr3_sim(){
|
||||
const svg = document.getElementById('lr3-sim'); if(!svg) return;
|
||||
let closed = false;
|
||||
@@ -902,10 +1063,59 @@ function build_lr4(){
|
||||
h += _labResult('lr4', '<p>Все 3 правила послед. соединения подтверждены опытом:</p>'
|
||||
+'<ul style="padding-left:20px"><li>$I$ одинаков везде;</li><li>$U = U_1 + U_2$;</li><li>$R = R_1 + R_2$.</li></ul>'
|
||||
+'<p><b>Вывод:</b> закон Ома и правила последовательного соединения выполняются.</p>');
|
||||
/* IV6 — Последовательное соединение проводников (Phase 4) */
|
||||
h += '<div class="wg p8-iv6">'
|
||||
+'<div class="wg-header"><span class="wg-badge p8-badge" style="background:#d1fae5;color:#047857">IV-6</span><div class="wg-title">Последовательное соединение проводников</div></div>'
|
||||
+'<div class="wg-help">Двигай R₁, R₂. Проверь: ток одинаков везде; напряжения складываются U = U₁ + U₂.</div>'
|
||||
+'<div class="p8-sandbox" id="lr4-iv6-sandbox" style="height:260px"></div>'
|
||||
+'<div style="margin-top:10px;display:grid;grid-template-columns:1fr 1fr;gap:8px"><div class="p8-scrubber"><span class="p8-scrubber-label">R₁</span><input type="range" id="lr4-r1" min="1" max="50" step="1" value="10"><span class="p8-scrubber-value"><span id="lr4-r1-val">10</span><span class="p8-unit">Ом</span></span></div><div class="p8-scrubber"><span class="p8-scrubber-label">R₂</span><input type="range" id="lr4-r2" min="1" max="50" step="1" value="20"><span class="p8-scrubber-value"><span id="lr4-r2-val">20</span><span class="p8-unit">Ом</span></span></div></div>'+'<div style="margin-top:8px;display:flex;gap:10px;flex-wrap:wrap"><div class="p8-readout"><span class="p8-readout-label">U₁</span><span class="p8-readout-value" id="lr4-u1">4</span><span class="p8-readout-unit">В</span></div><div class="p8-readout"><span class="p8-readout-label">U₂</span><span class="p8-readout-value" id="lr4-u2">8</span><span class="p8-readout-unit">В</span></div><div class="p8-readout"><span class="p8-readout-label">I</span><span class="p8-readout-value" id="lr4-i">0.4</span><span class="p8-readout-unit">А</span></div></div>'
|
||||
+'</div>';
|
||||
|
||||
box.innerHTML = h + secNavFor('lr4') + readButton('lr4');
|
||||
renderMath(box); wireReadBtn('lr4');
|
||||
_initLR4_iv6();
|
||||
_lr4_sim(); _labWireSubmit('lr4', 'lr4');
|
||||
}
|
||||
|
||||
function _initLR4_iv6(){
|
||||
const sb = document.getElementById('lr4-iv6-sandbox');
|
||||
if (!sb || !window.P8Helpers) return;
|
||||
|
||||
const svg = P8Helpers.svg.create(560, 260);
|
||||
svg.setAttribute('width','100%'); svg.setAttribute('height','100%'); svg.style.display='block';
|
||||
sb.appendChild(svg);
|
||||
const U = 12;
|
||||
let R1=10, R2=20;
|
||||
function render(){
|
||||
svg.innerHTML='';
|
||||
const R = R1+R2, I = U/R, U1 = I*R1, U2 = I*R2;
|
||||
/* Battery */
|
||||
svg.appendChild(P8Helpers.em.circuitComponent('battery', 80, 130, 'h', U+' В'));
|
||||
/* R1 */
|
||||
svg.appendChild(P8Helpers.em.circuitComponent('resistor', 230, 130, 'h', R1+' Ом'));
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x: 230, y: 110, 'font-family':"'JetBrains Mono',monospace", 'font-size':10, 'font-weight':800, fill:'#dc2626', 'text-anchor':'middle', text: 'U₁='+U1.toFixed(1)+' В' }));
|
||||
/* R2 */
|
||||
svg.appendChild(P8Helpers.em.circuitComponent('resistor', 400, 130, 'h', R2+' Ом'));
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x: 400, y: 110, 'font-family':"'JetBrains Mono',monospace", 'font-size':10, 'font-weight':800, fill:'#dc2626', 'text-anchor':'middle', text: 'U₂='+U2.toFixed(1)+' В' }));
|
||||
/* Wires */
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 110, y1: 130, x2: 200, y2: 130, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 260, y1: 130, x2: 370, y2: 130, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 430, y1: 130, x2: 510, y2: 130, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 510, y1: 130, x2: 510, y2: 200, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 50, y1: 130, x2: 50, y2: 200, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 50, y1: 200, x2: 510, y2: 200, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
/* I label */
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x: 280, y: 220, 'font-family':"'JetBrains Mono',monospace", 'font-size':12, 'font-weight':800, fill:'#10b981', 'text-anchor':'middle', text: 'I = '+I.toFixed(3)+' А (одинаков везде)' }));
|
||||
/* Updates */
|
||||
document.getElementById('lr4-u1').textContent = U1.toFixed(1);
|
||||
document.getElementById('lr4-u2').textContent = U2.toFixed(1);
|
||||
document.getElementById('lr4-i').textContent = I.toFixed(3);
|
||||
}
|
||||
document.getElementById('lr4-r1').oninput = ev => { R1 = +ev.target.value; document.getElementById('lr4-r1-val').textContent = R1; render(); };
|
||||
document.getElementById('lr4-r2').oninput = ev => { R2 = +ev.target.value; document.getElementById('lr4-r2-val').textContent = R2; render(); };
|
||||
render();
|
||||
|
||||
}
|
||||
function _lr4_sim(){
|
||||
function u(){
|
||||
const R1 = +document.getElementById('lr4-r1').value;
|
||||
@@ -951,10 +1161,58 @@ function build_lr5(){
|
||||
h += _labResult('lr5', '<p>Все 3 правила параллельного соединения подтверждены:</p>'
|
||||
+'<ul style="padding-left:20px"><li>$U$ одинаково на обеих ветвях;</li><li>$I = I_1 + I_2$;</li><li>$1/R = 1/R_1 + 1/R_2$.</li></ul>'
|
||||
+'<p><b>Вывод:</b> общее $R$ <b>меньше</b> любого из $R_1$, $R_2$, что соответствует теории.</p>');
|
||||
/* IV6 — Параллельное соединение проводников (Phase 4) */
|
||||
h += '<div class="wg p8-iv6">'
|
||||
+'<div class="wg-header"><span class="wg-badge p8-badge" style="background:#d1fae5;color:#047857">IV-6</span><div class="wg-title">Параллельное соединение проводников</div></div>'
|
||||
+'<div class="wg-help">Двигай R₁, R₂. Проверь: напряжение одинаково на обоих, токи складываются I = I₁ + I₂.</div>'
|
||||
+'<div class="p8-sandbox" id="lr5-iv6-sandbox" style="height:260px"></div>'
|
||||
+'<div style="margin-top:10px;display:grid;grid-template-columns:1fr 1fr;gap:8px"><div class="p8-scrubber"><span class="p8-scrubber-label">R₁</span><input type="range" id="lr5-r1" min="1" max="50" step="1" value="20"><span class="p8-scrubber-value"><span id="lr5-r1-val">20</span><span class="p8-unit">Ом</span></span></div><div class="p8-scrubber"><span class="p8-scrubber-label">R₂</span><input type="range" id="lr5-r2" min="1" max="50" step="1" value="30"><span class="p8-scrubber-value"><span id="lr5-r2-val">30</span><span class="p8-unit">Ом</span></span></div></div>'+'<div style="margin-top:8px;display:flex;gap:10px;flex-wrap:wrap"><div class="p8-readout"><span class="p8-readout-label">I₁</span><span class="p8-readout-value" id="lr5-i1">0.6</span><span class="p8-readout-unit">А</span></div><div class="p8-readout"><span class="p8-readout-label">I₂</span><span class="p8-readout-value" id="lr5-i2">0.4</span><span class="p8-readout-unit">А</span></div><div class="p8-readout"><span class="p8-readout-label">I</span><span class="p8-readout-value" id="lr5-i">1.0</span><span class="p8-readout-unit">А</span></div></div>'
|
||||
+'</div>';
|
||||
|
||||
box.innerHTML = h + secNavFor('lr5') + readButton('lr5');
|
||||
renderMath(box); wireReadBtn('lr5');
|
||||
_initLR5_iv6();
|
||||
_lr5_sim(); _labWireSubmit('lr5', 'lr5');
|
||||
}
|
||||
|
||||
function _initLR5_iv6(){
|
||||
const sb = document.getElementById('lr5-iv6-sandbox');
|
||||
if (!sb || !window.P8Helpers) return;
|
||||
|
||||
const svg = P8Helpers.svg.create(560, 260);
|
||||
svg.setAttribute('width','100%'); svg.setAttribute('height','100%'); svg.style.display='block';
|
||||
sb.appendChild(svg);
|
||||
const U = 12;
|
||||
let R1=20, R2=30;
|
||||
function render(){
|
||||
svg.innerHTML='';
|
||||
const I1=U/R1, I2=U/R2, I=I1+I2;
|
||||
svg.appendChild(P8Helpers.em.circuitComponent('battery', 80, 130, 'h', U+' В'));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 110, y1: 130, x2: 200, y2: 130, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 200, y1: 80, x2: 200, y2: 180, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 380, y1: 80, x2: 380, y2: 180, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 200, y1: 80, x2: 290, y2: 80, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 320, y1: 80, x2: 380, y2: 80, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 200, y1: 180, x2: 290, y2: 180, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 320, y1: 180, x2: 380, y2: 180, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.em.circuitComponent('resistor', 305, 80, 'h', R1+' Ом'));
|
||||
svg.appendChild(P8Helpers.em.circuitComponent('resistor', 305, 180, 'h', R2+' Ом'));
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x: 290, y: 68, 'font-family':"'JetBrains Mono',monospace", 'font-size':10, 'font-weight':800, fill:'#dc2626', 'text-anchor':'middle', text: 'I₁='+I1.toFixed(2)+' А' }));
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x: 290, y: 200, 'font-family':"'JetBrains Mono',monospace", 'font-size':10, 'font-weight':800, fill:'#dc2626', 'text-anchor':'middle', text: 'I₂='+I2.toFixed(2)+' А' }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 380, y1: 130, x2: 510, y2: 130, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 510, y1: 130, x2: 510, y2: 220, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 50, y1: 130, x2: 50, y2: 220, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 50, y1: 220, x2: 510, y2: 220, stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x: 150, y: 250, 'font-family':"'JetBrains Mono',monospace", 'font-size':12, 'font-weight':800, fill:'#10b981', 'text-anchor':'middle', text: 'I='+I.toFixed(2)+' А' }));
|
||||
document.getElementById('lr5-i1').textContent = I1.toFixed(2);
|
||||
document.getElementById('lr5-i2').textContent = I2.toFixed(2);
|
||||
document.getElementById('lr5-i').textContent = I.toFixed(2);
|
||||
}
|
||||
document.getElementById('lr5-r1').oninput = ev => { R1 = +ev.target.value; document.getElementById('lr5-r1-val').textContent = R1; render(); };
|
||||
document.getElementById('lr5-r2').oninput = ev => { R2 = +ev.target.value; document.getElementById('lr5-r2-val').textContent = R2; render(); };
|
||||
render();
|
||||
|
||||
}
|
||||
function _lr5_sim(){
|
||||
function u(){
|
||||
const R1 = +document.getElementById('lr5-r1').value;
|
||||
@@ -1000,10 +1258,52 @@ function build_lr6(){
|
||||
+'<span style="font-size:.84rem;color:var(--muted)">за $t$ секунд работы прибор потратил $A$ Дж энергии.</span></div></div>';
|
||||
h += _labResult('lr6', '<p>Прямое применение формул $P = UI$ и $A = Pt$. Это позволяет рассчитать энергопотребление любого прибора.</p>'
|
||||
+'<p><b>Вывод:</b> измеренная $P$ совпадает с маркировкой на лампе; расчётная $A$ соответствует количеству выделившегося тепла и света.</p>');
|
||||
/* IV6 — Работа и мощность тока (Phase 4) */
|
||||
h += '<div class="wg p8-iv6">'
|
||||
+'<div class="wg-header"><span class="wg-badge p8-badge" style="background:#d1fae5;color:#047857">IV-6</span><div class="wg-title">Работа и мощность тока</div></div>'
|
||||
+'<div class="wg-help">Задавай U, I и время t — рассчитаются P=UI, A=Pt. Лампа светится ярче с ростом P.</div>'
|
||||
+'<div class="p8-sandbox" id="lr6-iv6-sandbox" style="height:260px"></div>'
|
||||
+'<div style="margin-top:10px;display:grid;grid-template-columns:1fr 1fr 1fr;gap:6px"><div class="p8-scrubber"><span class="p8-scrubber-label">U</span><input type="range" id="lr6-u" min="1" max="220" step="1" value="220"><span class="p8-scrubber-value"><span id="lr6-u-val">220</span><span class="p8-unit">В</span></span></div><div class="p8-scrubber"><span class="p8-scrubber-label">I</span><input type="range" id="lr6-i" min="0.01" max="5" step="0.01" value="0.5"><span class="p8-scrubber-value"><span id="lr6-i-val">0.50</span><span class="p8-unit">А</span></span></div><div class="p8-scrubber"><span class="p8-scrubber-label">t</span><input type="range" id="lr6-t" min="1" max="3600" step="1" value="60"><span class="p8-scrubber-value"><span id="lr6-t-val">60</span><span class="p8-unit">с</span></span></div></div>'+'<div style="margin-top:8px;display:flex;gap:10px;flex-wrap:wrap"><div class="p8-readout"><span class="p8-readout-label">P</span><span class="p8-readout-value" id="lr6-p">110</span><span class="p8-readout-unit">Вт</span></div><div class="p8-readout"><span class="p8-readout-label">A</span><span class="p8-readout-value" id="lr6-a">6.6</span><span class="p8-readout-unit">кДж</span></div></div>'
|
||||
+'</div>';
|
||||
|
||||
box.innerHTML = h + secNavFor('lr6') + readButton('lr6');
|
||||
renderMath(box); wireReadBtn('lr6');
|
||||
_initLR6_iv6();
|
||||
_lr6_sim(); _labWireSubmit('lr6', 'lr6');
|
||||
}
|
||||
|
||||
function _initLR6_iv6(){
|
||||
const sb = document.getElementById('lr6-iv6-sandbox');
|
||||
if (!sb || !window.P8Helpers) return;
|
||||
|
||||
const svg = P8Helpers.svg.create(560, 260);
|
||||
svg.setAttribute('width','100%'); svg.setAttribute('height','100%'); svg.style.display='block';
|
||||
sb.appendChild(svg);
|
||||
let U=220, I=0.5, t=60;
|
||||
function render(){
|
||||
svg.innerHTML='';
|
||||
const P = U*I, A = P*t;
|
||||
const br = Math.min(1, P/200);
|
||||
/* Lamp */
|
||||
svg.appendChild(P8Helpers.svg.el('circle', { cx: 280, cy: 110, r: 55, fill: '#fef3c7', opacity: br*0.5+0.15 }));
|
||||
svg.appendChild(P8Helpers.svg.el('circle', { cx: 280, cy: 110, r: 35, fill: '#fde047', stroke: '#0f172a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x: 280, y: 113, 'font-family':"'Unbounded',sans-serif", 'font-size':18, 'font-weight':900, fill:'#0f172a', 'text-anchor':'middle', text: P.toFixed(0)+' Вт' }));
|
||||
if (br > 0.5) {
|
||||
for (let i = 0; i < 8; i++) {
|
||||
const a = i*Math.PI/4;
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: 280+45*Math.cos(a), y1: 110+45*Math.sin(a), x2: 280+68*Math.cos(a), y2: 110+68*Math.sin(a), stroke: '#facc15', 'stroke-width': 3 }));
|
||||
}
|
||||
}
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x: 280, y: 220, 'font-family':"'JetBrains Mono',monospace", 'font-size':13, 'font-weight':800, fill:'#0f172a', 'text-anchor':'middle', text: 'P = UI = '+P.toFixed(1)+' Вт, A = Pt = '+(A/1000).toFixed(1)+' кДж' }));
|
||||
document.getElementById('lr6-p').textContent = P.toFixed(1);
|
||||
document.getElementById('lr6-a').textContent = (A/1000).toFixed(2);
|
||||
}
|
||||
document.getElementById('lr6-u').oninput = ev => { U = +ev.target.value; document.getElementById('lr6-u-val').textContent = U; render(); };
|
||||
document.getElementById('lr6-i').oninput = ev => { I = +ev.target.value; document.getElementById('lr6-i-val').textContent = I.toFixed(2); render(); };
|
||||
document.getElementById('lr6-t').oninput = ev => { t = +ev.target.value; document.getElementById('lr6-t-val').textContent = t; render(); };
|
||||
render();
|
||||
|
||||
}
|
||||
function _lr6_sim(){
|
||||
function u(){
|
||||
const U = +document.getElementById('lr6-u').value;
|
||||
@@ -1048,10 +1348,55 @@ function build_lr7(){
|
||||
+'</tbody></table></div>';
|
||||
h += _labResult('lr7', '<p>Во всех опытах $\\alpha = \\beta$ в пределах погрешности измерения.</p>'
|
||||
+'<p><b>Вывод:</b> закон отражения $\\alpha = \\beta$ выполняется для любых углов падения.</p>');
|
||||
/* IV6 — Закон отражения света (Phase 4) */
|
||||
h += '<div class="wg p8-iv6">'
|
||||
+'<div class="wg-header"><span class="wg-badge p8-badge" style="background:#d1fae5;color:#047857">IV-6</span><div class="wg-title">Закон отражения света</div></div>'
|
||||
+'<div class="wg-help">Двигай угол падения α — угол отражения β равен ему. Луч идёт по правилу: «угол падения = углу отражения».</div>'
|
||||
+'<div class="p8-sandbox" id="lr7-iv6-sandbox" style="height:260px"></div>'
|
||||
+'<div class="p8-scrubber" style="margin-top:10px"><span class="p8-scrubber-label">Угол падения</span><input type="range" id="lr7-a" min="0" max="80" step="1" value="40"><span class="p8-scrubber-value"><span id="lr7-a-val">40</span><span class="p8-unit">°</span></span></div>'+'<div style="margin-top:8px;display:flex;gap:10px;flex-wrap:wrap"><div class="p8-readout"><span class="p8-readout-label">α</span><span class="p8-readout-value" id="lr7-a-out">40</span><span class="p8-readout-unit">°</span></div><div class="p8-readout"><span class="p8-readout-label">β</span><span class="p8-readout-value" id="lr7-b">40</span><span class="p8-readout-unit">°</span></div></div>'
|
||||
+'</div>';
|
||||
|
||||
box.innerHTML = h + secNavFor('lr7') + readButton('lr7');
|
||||
renderMath(box); wireReadBtn('lr7');
|
||||
_initLR7_iv6();
|
||||
_lr7_sim(); _labWireSubmit('lr7', 'lr7');
|
||||
}
|
||||
|
||||
function _initLR7_iv6(){
|
||||
const sb = document.getElementById('lr7-iv6-sandbox');
|
||||
if (!sb || !window.P8Helpers) return;
|
||||
|
||||
const svg = P8Helpers.svg.create(560, 260);
|
||||
svg.setAttribute('width','100%'); svg.setAttribute('height','100%'); svg.style.display='block';
|
||||
sb.appendChild(svg);
|
||||
let alpha = 40;
|
||||
function render(){
|
||||
svg.innerHTML='';
|
||||
const cx = 280, cy = 210;
|
||||
svg.appendChild(P8Helpers.optics.mirrorPlane(60, 210, 500, 210));
|
||||
svg.appendChild(P8Helpers.svg.el('line', { x1: cx, y1: 210, x2: cx, y2: 30, stroke: '#475569', 'stroke-width': 1.5, 'stroke-dasharray': '5 3' }));
|
||||
const aRad = alpha*Math.PI/180;
|
||||
const len = 170;
|
||||
/* Incident */
|
||||
const inX = cx - len*Math.sin(aRad), inY = cy - len*Math.cos(aRad);
|
||||
svg.appendChild(P8Helpers.optics.rayLine(inX, inY, cx, cy, { color: '#facc15', width: 3.5, glow: true }));
|
||||
/* Reflected */
|
||||
const rX = cx + len*Math.sin(aRad), rY = cy - len*Math.cos(aRad);
|
||||
svg.appendChild(P8Helpers.optics.rayLine(cx, cy, rX, rY, { color: '#facc15', width: 3.5, glow: true }));
|
||||
/* Angle arcs */
|
||||
svg.appendChild(P8Helpers.svg.el('path', { d: 'M '+(cx-25*Math.sin(aRad/2))+' '+(cy-25*Math.cos(aRad/2))+' A 25 25 0 0 1 '+cx+' '+(cy-25)+' ', fill: 'none', stroke: '#dc2626', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x: cx-22, y: cy-40, 'font-family':"'JetBrains Mono',monospace", 'font-size':13, 'font-weight':800, fill:'#dc2626', 'text-anchor':'middle', text: 'α='+alpha+'°' }));
|
||||
svg.appendChild(P8Helpers.svg.el('path', { d: 'M '+cx+' '+(cy-25)+' A 25 25 0 0 1 '+(cx+25*Math.sin(aRad/2))+' '+(cy-25*Math.cos(aRad/2))+' ', fill: 'none', stroke: '#16a34a', 'stroke-width': 2 }));
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x: cx+22, y: cy-40, 'font-family':"'JetBrains Mono',monospace", 'font-size':13, 'font-weight':800, fill:'#16a34a', 'text-anchor':'middle', text: 'β='+alpha+'°' }));
|
||||
/* Verdict */
|
||||
svg.appendChild(P8Helpers.svg.el('text', { x: 280, y: 250, 'font-family':"'JetBrains Mono',monospace", 'font-size':12, 'font-weight':700, fill:'#10b981', 'text-anchor':'middle', text: '✓ α = β — закон отражения' }));
|
||||
document.getElementById('lr7-a-out').textContent = alpha;
|
||||
document.getElementById('lr7-b').textContent = alpha;
|
||||
}
|
||||
document.getElementById('lr7-a').oninput = ev => { alpha = +ev.target.value; document.getElementById('lr7-a-val').textContent = alpha; render(); };
|
||||
render();
|
||||
|
||||
}
|
||||
function _lr7_sim(){
|
||||
const svg = document.getElementById('lr7-sim'); if(!svg) return;
|
||||
function d(){
|
||||
|
||||
Reference in New Issue
Block a user