fix(phys7): главный визуал курса работает + §22, §24 интерактивы улучшены
1. БАГ В HillSlideSim (phys.js):
- При reset() начальное состояние x=0, h=hStart, v=0.
- Первый step(): dropped=0 → v=0 → x не растёт → h не падает → тележка
навсегда стоит на вершине (бесконечный нуль). Анимация ничего не показывала.
- Фикс: reset() даёт начальный толчок (x = L*0.01) и v по энергии для
этой малой высоты падения. step() теперь корректно ускоряет тележку.
- Тест node: за 2.05 с тележка проходит 11.7 м, h падает с 4.9 м до 0.86 м,
v растёт с 1.4 до 9.0 м/с. Е_полн ≈ const.
2. §22 «Сила тяжести» — новый IV-2 «Падение на 4 планетах»:
- SVG 4-колоночная сцена, 4 шарика стартуют с одной высоты.
- Slider высоты 2..20 м, кнопки «Уронить» / «Сброс».
- Свободное падение по h(t) = h₀ − gt²/2 для каждой планеты (Земля 9.8,
Луна 1.6, Марс 3.7, Юпитер 24.8).
- Видно: Юпитер падает первым, Луна последней; для каждого сохраняется
время падения √(2h/g) и итоговая v = g·t.
- Live info: текущее t, статус каждого шарика (падает / упал за X с,
v = Y м/с).
3. §24 «Вес тела» — переработан IV-1 «Лифт с динамометром»:
- Было: 4 статичных схемы покой/падение/верх/вниз.
- Стало: динамический симулятор. Кабина лифта со стрелкой ускорения
снаружи, внутри — груз на пружинном динамометре с шкалой.
- 2 slider'а: масса 0.5..10 кг, ускорение −10..+10 м/с².
- 4 кнопки-пресета: Покой / Едет вверх / Едет вниз / Свободное падение.
- Формула P = m(g + a) считается в реальном времени.
- 4 режима с автоопределением: ПОКОЙ / НЕВЕСОМОСТЬ / ПЕРЕГРУЗКА /
ПОНИЖЕННЫЙ ВЕС с разной цветовой индикацией.
- Пружина динамометра реально растягивается/сжимается в зависимости
от P; указатель и шкала тоже.
Parse OK, smoke (15 экспортов CH3) OK.
This commit is contained in:
+23
-5
@@ -672,15 +672,33 @@ class HillSlideSim {
|
||||
this.scale = opts.scale || 30;
|
||||
this.reset();
|
||||
}
|
||||
reset() { this.t = 0; this.x = 0; this.v = 0; this.h = this.hStart; }
|
||||
reset() {
|
||||
// Начальный импульс: тележка стартует с лёгким толчком (1% от L) и небольшой скоростью,
|
||||
// иначе при h=hStart, v=0 — она навсегда останется на вершине (бесконечный нуль).
|
||||
const L = this.hStart * 4;
|
||||
this.t = 0;
|
||||
this.x = L * 0.01;
|
||||
const xRel = this.x / L;
|
||||
this.h = this.hStart * Math.pow(1 - xRel, 2);
|
||||
this.v = Math.sqrt(2 * this.g * (this.hStart - this.h));
|
||||
}
|
||||
step(dt) {
|
||||
const gEff = this.g * (1 - this.friction);
|
||||
this.t += dt;
|
||||
const dropped = this.hStart - this.h;
|
||||
if (this.h <= 0) { this.h = 0; this.v = Math.sqrt(2 * gEff * this.hStart); return; }
|
||||
this.v = Math.sqrt(2 * gEff * Math.max(0, dropped));
|
||||
this.x += this.v * dt;
|
||||
const L = this.hStart * 4;
|
||||
if (this.h <= 0.001 || this.x >= L) {
|
||||
this.h = 0;
|
||||
// Финальная скорость с учётом потерь на трение.
|
||||
this.v = Math.sqrt(2 * gEff * this.hStart);
|
||||
this.x = L;
|
||||
return;
|
||||
}
|
||||
// Скорость по закону сохранения энергии (с учётом трения).
|
||||
const dropped = Math.max(0.0001, this.hStart - this.h);
|
||||
this.v = Math.sqrt(2 * gEff * dropped);
|
||||
// Скорость по x — это горизонтальная компонента; для наглядного моделирования
|
||||
// используем её напрямую как темп роста x.
|
||||
this.x += this.v * dt;
|
||||
const xRel = Math.min(this.x, L) / L;
|
||||
this.h = this.hStart * Math.pow(1 - xRel, 2);
|
||||
}
|
||||
|
||||
@@ -1223,8 +1223,18 @@ function add_p22(){
|
||||
+ '$F_т = m g = $ <b id="p22-Ft" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">0.98</b> Н (на <span id="p22-pl-nm" style="font-weight:700">Земле</span>, $g = $ <span id="p22-g-val" style="font-family:JetBrains Mono,monospace;font-weight:700">9.8</span> Н/кг)'
|
||||
+ '</div>');
|
||||
|
||||
/* IV-2 КВИЗ */
|
||||
h += wgWrap('p22-iv2', 'КВИЗ', 'Сила тяжести', '',
|
||||
/* IV-2 СИМ — Падение тела на 4 планетах */
|
||||
h += wgWrap('p22-iv2', 'СИМ', 'Падение с одной высоты на 4 планетах', 'Нажми «Уронить» — увидь, кто упадёт быстрее. Время и скорость в реальном времени.',
|
||||
'<div style="display:flex;gap:6px;margin-bottom:10px;flex-wrap:wrap">'
|
||||
+ '<button id="p22-drop" type="button" style="background:#dc2626;color:#fff;border:none;padding:9px 18px;border-radius:9px;cursor:pointer;font-weight:700;font-family:inherit;font-size:.9rem">Уронить</button>'
|
||||
+ '<button id="p22-drop-reset" type="button" style="background:#fff;color:#dc2626;border:1.5px solid #dc2626;padding:9px 14px;border-radius:9px;cursor:pointer;font-weight:700;font-family:inherit;font-size:.88rem">Сброс</button>'
|
||||
+ '<label style="display:inline-flex;align-items:center;gap:6px;background:#fff;border:1px solid ' + ACCENT_SOFT + ';padding:6px 12px;border-radius:8px;font-size:.86rem;color:#475569">Высота $h$, м: <b id="p22-drop-h" style="color:#dc2626;font-family:JetBrains Mono,monospace">10</b><input type="range" id="p22-drop-h-r" min="2" max="20" step="1" value="10" style="width:120px;accent-color:#dc2626"></label>'
|
||||
+ '</div>'
|
||||
+ '<svg id="p22-drop-svg" viewBox="0 0 380 200" width="100%" style="max-width:600px;display:block;margin:0 auto;background:#fef2f2;border-radius:9px;border:1px solid ' + ACCENT_SOFT + '"></svg>'
|
||||
+ '<div id="p22-drop-info" style="background:' + ACCENT_SOFT + ';border-radius:9px;padding:10px 14px;margin-top:8px;font-size:.92rem;line-height:1.55"></div>');
|
||||
|
||||
/* IV-3 КВИЗ (был IV-2) */
|
||||
h += wgWrap('p22-iv3', 'КВИЗ', 'Сила тяжести', '',
|
||||
'<div id="p22-q-host">'
|
||||
+ quizQuestion('p22-q', 0, 'Куда направлена сила тяжести на поверхности Земли?', ['Вверх','Вертикально вниз (к центру Земли)','В сторону Солнца','В произвольном направлении'], 1)
|
||||
+ quizQuestion('p22-q', 1, '$g$ на Земле примерно равно…', ['1 Н/кг','9,8 Н/кг','100 Н/кг','1000 Н/кг'], 1)
|
||||
@@ -1280,6 +1290,80 @@ function add_p22(){
|
||||
document.getElementById('p22-m-r').addEventListener('input', upd22);
|
||||
upd22();
|
||||
|
||||
// §22 IV-2 — Падение тел на 4 планетах
|
||||
const planets22 = [
|
||||
{ nm:'Земля', g:9.8, col:'#0284c7' },
|
||||
{ nm:'Луна', g:1.6, col:'#94a3b8' },
|
||||
{ nm:'Марс', g:3.7, col:'#dc2626' },
|
||||
{ nm:'Юпитер', g:24.8, col:'#d97706' }
|
||||
];
|
||||
let drop22 = { t:0, raf:0, running:false, h0:10 };
|
||||
function drawDrop22(){
|
||||
const svg = document.getElementById('p22-drop-svg');
|
||||
if(!svg) return;
|
||||
const W = 380, H = 200, baseY = 175;
|
||||
const pxPerM = (baseY - 25) / drop22.h0;
|
||||
const colW = W / planets22.length;
|
||||
let s = '';
|
||||
s += '<line x1="0" y1="' + baseY + '" x2="' + W + '" y2="' + baseY + '" stroke="#0f172a" stroke-width="1.5"/>';
|
||||
planets22.forEach((p, i) => {
|
||||
const cx = colW * i + colW/2;
|
||||
const startY = baseY - drop22.h0 * pxPerM;
|
||||
// Падение: h(t) = h0 - g*t²/2 (свободное падение)
|
||||
const fall = 0.5 * p.g * drop22.t * drop22.t;
|
||||
const hNow = Math.max(0, drop22.h0 - fall);
|
||||
const cy = baseY - hNow * pxPerM - 6;
|
||||
const v = p.g * drop22.t;
|
||||
const fellTime = Math.sqrt(2 * drop22.h0 / p.g);
|
||||
const onGround = drop22.t >= fellTime;
|
||||
// Опорная линия высоты
|
||||
s += '<line x1="' + (cx - colW/2 + 10) + '" y1="' + startY + '" x2="' + (cx + colW/2 - 10) + '" y2="' + startY + '" stroke="#cbd5e1" stroke-width="1" stroke-dasharray="3 2"/>';
|
||||
// Шарик
|
||||
s += '<circle cx="' + cx.toFixed(1) + '" cy="' + (onGround ? baseY - 6 : cy).toFixed(1) + '" r="9" fill="' + p.col + '" stroke="#0f172a" stroke-width="1.5"/>';
|
||||
// Подпись планеты
|
||||
s += '<text x="' + cx + '" y="' + (baseY + 16) + '" text-anchor="middle" font-family="Inter,sans-serif" font-size="11" font-weight="700" fill="' + p.col + '">' + p.nm + '</text>';
|
||||
s += '<text x="' + cx + '" y="' + 18 + '" text-anchor="middle" font-family="Inter,sans-serif" font-size="9" fill="#475569">g=' + p.g + '</text>';
|
||||
if(onGround) s += '<text x="' + cx + '" y="' + (baseY - 14) + '" text-anchor="middle" font-family="JetBrains Mono,monospace" font-size="10" font-weight="700" fill="#10b981">' + fellTime.toFixed(2) + ' с</text>';
|
||||
});
|
||||
svg.innerHTML = s;
|
||||
// Info
|
||||
const status = planets22.map(p => {
|
||||
const fellTime = Math.sqrt(2 * drop22.h0 / p.g);
|
||||
const onGround = drop22.t >= fellTime;
|
||||
const vNow = onGround ? p.g * fellTime : p.g * drop22.t;
|
||||
return '<b style="color:' + p.col + '">' + p.nm + '</b>: ' + (onGround ? 'упал за ' + fellTime.toFixed(2) + ' с, $v = ' + vNow.toFixed(1) + '$ м/с' : 'падает, $v = ' + vNow.toFixed(1) + '$ м/с');
|
||||
}).join(' · ');
|
||||
document.getElementById('p22-drop-info').innerHTML = '$t = ' + drop22.t.toFixed(2) + '$ с · ' + status;
|
||||
renderMath(document.getElementById('p22-drop-info'));
|
||||
}
|
||||
function loop22(){
|
||||
if(!drop22.running) return;
|
||||
drop22.t += 0.04;
|
||||
drawDrop22();
|
||||
// Останавливаем когда даже самая медленная (Луна) упала
|
||||
const maxT = Math.sqrt(2 * drop22.h0 / 1.6);
|
||||
if(drop22.t >= maxT + 0.5){ drop22.running = false; return; }
|
||||
drop22.raf = requestAnimationFrame(loop22);
|
||||
}
|
||||
document.getElementById('p22-drop-h-r').addEventListener('input', () => {
|
||||
drop22.h0 = +document.getElementById('p22-drop-h-r').value;
|
||||
document.getElementById('p22-drop-h').textContent = drop22.h0;
|
||||
drop22.t = 0; drop22.running = false;
|
||||
if(drop22.raf) cancelAnimationFrame(drop22.raf);
|
||||
drawDrop22();
|
||||
});
|
||||
document.getElementById('p22-drop').addEventListener('click', () => {
|
||||
drop22.t = 0; drop22.running = true;
|
||||
if(drop22.raf) cancelAnimationFrame(drop22.raf);
|
||||
loop22();
|
||||
});
|
||||
document.getElementById('p22-drop-reset').addEventListener('click', () => {
|
||||
drop22.t = 0; drop22.running = false;
|
||||
if(drop22.raf) cancelAnimationFrame(drop22.raf);
|
||||
drawDrop22();
|
||||
});
|
||||
drawDrop22();
|
||||
|
||||
wireDnd('p22-dnd', [
|
||||
{ id:'a1', cat:'1n' },{ id:'a2', cat:'10n' },{ id:'a3', cat:'100n' },
|
||||
{ id:'a4', cat:'1n' },{ id:'a5', cat:'10n' },{ id:'a6', cat:'100n' }
|
||||
@@ -1444,14 +1528,18 @@ function add_p24(){
|
||||
+ 'На <b>пружинных весах (динамометре)</b> измеряют силу, с которой тело растягивает пружину. '
|
||||
+ 'Это и есть вес тела в Ньютонах.');
|
||||
|
||||
/* IV-1 СИМ: тело в 3 ситуациях */
|
||||
h += wgWrap('p24-iv1', 'СИМ', 'Три ситуации: покой, падение, ускорение', 'Выбери ситуацию — увидь стрелки сил.',
|
||||
'<div style="display:flex;gap:6px;margin-bottom:10px;flex-wrap:wrap">'
|
||||
+ [['rest','На столе (покой)'],['fall','Свободное падение'],['up','Ускоряется вверх'],['down','Ускоряется вниз']].map((s, i) =>
|
||||
'<button class="p24-sit" data-s="' + s[0] + '" type="button" style="background:' + (i===0 ? '#dc2626' : '#fff') + ';color:' + (i===0 ? '#fff' : '#dc2626') + ';border:2px solid #dc2626;padding:7px 12px;border-radius:9px;cursor:pointer;font-weight:700;font-family:inherit;font-size:.84rem">' + s[1] + '</button>').join('')
|
||||
/* IV-1 СИМ: динамический лифт с динамометром */
|
||||
h += wgWrap('p24-iv1', 'СИМ', 'Лифт с динамометром: вес меняется при ускорении', 'Подвинь slider ускорения — увидь, как меняется показание динамометра (вес).',
|
||||
'<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:8px;margin-bottom:10px">'
|
||||
+ '<label style="display:block;font-size:.86rem;color:#475569;background:#fff;padding:7px 11px;border-radius:8px;border:1px solid ' + ACCENT_SOFT + '">Масса груза $m$, кг: <b id="p24-m" style="color:#dc2626;font-family:JetBrains Mono,monospace">2</b><input type="range" id="p24-m-r" min="0.5" max="10" step="0.5" value="2" style="display:block;width:100%;margin-top:5px;accent-color:#dc2626"></label>'
|
||||
+ '<label style="display:block;font-size:.86rem;color:#475569;background:#fff;padding:7px 11px;border-radius:8px;border:1px solid ' + ACCENT_SOFT + '">Ускорение лифта $a$, м/с²: <b id="p24-a" style="color:#dc2626;font-family:JetBrains Mono,monospace">0</b><input type="range" id="p24-a-r" min="-10" max="10" step="0.5" value="0" style="display:block;width:100%;margin-top:5px;accent-color:#dc2626"></label>'
|
||||
+ '</div>'
|
||||
+ '<svg id="p24-svg" viewBox="0 0 360 200" width="100%" style="max-width:500px;display:block;margin:0 auto;background:#fef2f2;border-radius:9px;border:1px solid ' + ACCENT_SOFT + '"></svg>'
|
||||
+ '<div id="p24-info" style="background:' + ACCENT_SOFT + ';border-radius:9px;padding:10px 14px;margin-top:8px;font-size:.92rem;line-height:1.6"></div>');
|
||||
+ '<div style="display:flex;gap:6px;margin-bottom:10px;flex-wrap:wrap">'
|
||||
+ [['0','Покой'],['2','Едет вверх с ускорением'],['-2','Едет вниз с ускорением'],['-10','Свободное падение']].map(p =>
|
||||
'<button class="p24-preset" data-a="' + p[0] + '" type="button" style="background:#fff;color:#dc2626;border:1.5px solid #dc2626;padding:6px 12px;border-radius:8px;cursor:pointer;font-weight:600;font-family:inherit;font-size:.82rem">' + p[1] + '</button>').join('')
|
||||
+ '</div>'
|
||||
+ '<svg id="p24-svg" viewBox="0 0 380 260" width="100%" style="max-width:560px;display:block;margin:0 auto;background:#fef2f2;border-radius:9px;border:1px solid ' + ACCENT_SOFT + '"></svg>'
|
||||
+ '<div id="p24-info" style="background:' + ACCENT_SOFT + ';border-radius:9px;padding:10px 14px;margin-top:8px;font-size:.94rem;line-height:1.65"></div>');
|
||||
|
||||
/* IV-2 КВИЗ */
|
||||
h += wgWrap('p24-iv2', 'КВИЗ', 'Вес vs сила тяжести', '',
|
||||
@@ -1489,72 +1577,86 @@ function add_p24(){
|
||||
h += readButton('p24');
|
||||
body.innerHTML = h;
|
||||
|
||||
function draw24(s){
|
||||
function draw24(){
|
||||
const svg = document.getElementById('p24-svg');
|
||||
if(!svg) return;
|
||||
const cx = 180, cy = 100;
|
||||
let html = '';
|
||||
let info = '';
|
||||
if(s === 'rest'){
|
||||
// Тело на столе
|
||||
html += '<rect x="20" y="160" width="320" height="10" fill="#475569"/>';
|
||||
for(let i = 0; i < 14; i++) html += '<line x1="' + (30 + i*22) + '" y1="170" x2="' + (24 + i*22) + '" y2="180" stroke="#0f172a" stroke-width="0.8"/>';
|
||||
html += '<rect x="' + (cx-25) + '" y="' + (cy+30) + '" width="50" height="30" fill="#dc2626" stroke="#7f1d1d" stroke-width="1.5" rx="3"/>';
|
||||
// F_т вниз (фиолетовая)
|
||||
html += '<line x1="' + (cx-30) + '" y1="' + (cy+45) + '" x2="' + (cx-30) + '" y2="' + (cy+85) + '" stroke="#7c3aed" stroke-width="3"/>';
|
||||
html += '<polygon points="' + (cx-35) + ',' + (cy+78) + ' ' + (cx-25) + ',' + (cy+78) + ' ' + (cx-30) + ',' + (cy+88) + '" fill="#7c3aed"/>';
|
||||
html += '<text x="' + (cx-70) + '" y="' + (cy+85) + '" font-family="Inter,sans-serif" font-size="11" font-weight="700" fill="#7c3aed">F_т (на тело)</text>';
|
||||
// P вниз от низа тела (индиго)
|
||||
html += '<line x1="' + (cx+30) + '" y1="' + (cy+60) + '" x2="' + (cx+30) + '" y2="' + (cy+100) + '" stroke="#4338ca" stroke-width="3"/>';
|
||||
html += '<polygon points="' + (cx+25) + ',' + (cy+93) + ' ' + (cx+35) + ',' + (cy+93) + ' ' + (cx+30) + ',' + (cy+103) + '" fill="#4338ca"/>';
|
||||
html += '<text x="' + (cx+40) + '" y="' + (cy+100) + '" font-family="Inter,sans-serif" font-size="11" font-weight="700" fill="#4338ca">P (на стол)</text>';
|
||||
info = '<b>Покой на горизонтальной опоре:</b> $P = F_т = mg$, но приложены к разным телам.';
|
||||
} else if(s === 'fall'){
|
||||
html += '<rect x="' + (cx-25) + '" y="' + (cy-15) + '" width="50" height="30" fill="#dc2626" stroke="#7f1d1d" stroke-width="1.5" rx="3"/>';
|
||||
// F_т вниз
|
||||
html += '<line x1="' + cx + '" y1="' + (cy+20) + '" x2="' + cx + '" y2="' + (cy+70) + '" stroke="#7c3aed" stroke-width="3"/>';
|
||||
html += '<polygon points="' + (cx-5) + ',' + (cy+63) + ' ' + (cx+5) + ',' + (cy+63) + ' ' + cx + ',' + (cy+73) + '" fill="#7c3aed"/>';
|
||||
html += '<text x="' + (cx+10) + '" y="' + (cy+55) + '" font-family="Inter,sans-serif" font-size="11" font-weight="700" fill="#7c3aed">F_т ↓</text>';
|
||||
// P = 0 — пиктограмма
|
||||
html += '<text x="' + (cx-100) + '" y="' + (cy-15) + '" font-family="Inter,sans-serif" font-size="14" font-weight="700" fill="#10b981">P = 0</text>';
|
||||
html += '<text x="' + (cx-100) + '" y="' + (cy+5) + '" font-family="Inter,sans-serif" font-size="10" fill="#475569">невесомость</text>';
|
||||
info = '<b>Свободное падение / орбита:</b> сила тяжести есть ($F_т = mg \\ne 0$), но вес $P = 0$ — тело ни на что не давит.';
|
||||
} else if(s === 'up'){
|
||||
html += '<rect x="20" y="160" width="320" height="10" fill="#475569"/>';
|
||||
html += '<line x1="' + cx + '" y1="160" x2="' + cx + '" y2="' + (cy+30) + '" stroke="#92400e" stroke-width="2"/>'; // тяга вверх
|
||||
html += '<rect x="' + (cx-25) + '" y="' + (cy+30) + '" width="50" height="30" fill="#dc2626" stroke="#7f1d1d" stroke-width="1.5" rx="3"/>';
|
||||
// F_т
|
||||
html += '<line x1="' + (cx-30) + '" y1="' + (cy+45) + '" x2="' + (cx-30) + '" y2="' + (cy+85) + '" stroke="#7c3aed" stroke-width="3"/>';
|
||||
html += '<polygon points="' + (cx-35) + ',' + (cy+78) + ' ' + (cx-25) + ',' + (cy+78) + ' ' + (cx-30) + ',' + (cy+88) + '" fill="#7c3aed"/>';
|
||||
html += '<text x="' + (cx-90) + '" y="' + (cy+88) + '" font-family="Inter,sans-serif" font-size="11" font-weight="700" fill="#7c3aed">F_т = mg</text>';
|
||||
// P больше — длинная стрелка
|
||||
html += '<line x1="' + (cx+30) + '" y1="' + (cy+60) + '" x2="' + (cx+30) + '" y2="' + (cy+115) + '" stroke="#dc2626" stroke-width="3.5"/>';
|
||||
html += '<polygon points="' + (cx+25) + ',' + (cy+108) + ' ' + (cx+35) + ',' + (cy+108) + ' ' + (cx+30) + ',' + (cy+118) + '" fill="#dc2626"/>';
|
||||
html += '<text x="' + (cx+40) + '" y="' + (cy+118) + '" font-family="Inter,sans-serif" font-size="11" font-weight="700" fill="#dc2626">P > mg (перегрузка)</text>';
|
||||
info = '<b>Лифт ускоряется вверх:</b> вес <b>больше</b> $mg$ — это перегрузка. Космонавты на старте испытывают $P \\approx 3 mg$.';
|
||||
} else {
|
||||
// down
|
||||
html += '<rect x="20" y="160" width="320" height="10" fill="#475569"/>';
|
||||
html += '<rect x="' + (cx-25) + '" y="' + (cy+30) + '" width="50" height="30" fill="#dc2626" stroke="#7f1d1d" stroke-width="1.5" rx="3"/>';
|
||||
html += '<line x1="' + (cx-30) + '" y1="' + (cy+45) + '" x2="' + (cx-30) + '" y2="' + (cy+85) + '" stroke="#7c3aed" stroke-width="3"/>';
|
||||
html += '<polygon points="' + (cx-35) + ',' + (cy+78) + ' ' + (cx-25) + ',' + (cy+78) + ' ' + (cx-30) + ',' + (cy+88) + '" fill="#7c3aed"/>';
|
||||
html += '<text x="' + (cx-90) + '" y="' + (cy+88) + '" font-family="Inter,sans-serif" font-size="11" font-weight="700" fill="#7c3aed">F_т = mg</text>';
|
||||
// P меньше — короткая стрелка
|
||||
html += '<line x1="' + (cx+30) + '" y1="' + (cy+60) + '" x2="' + (cx+30) + '" y2="' + (cy+80) + '" stroke="#10b981" stroke-width="2.5"/>';
|
||||
html += '<polygon points="' + (cx+25) + ',' + (cy+73) + ' ' + (cx+35) + ',' + (cy+73) + ' ' + (cx+30) + ',' + (cy+83) + '" fill="#10b981"/>';
|
||||
html += '<text x="' + (cx+40) + '" y="' + (cy+78) + '" font-family="Inter,sans-serif" font-size="11" font-weight="700" fill="#10b981">P < mg</text>';
|
||||
info = '<b>Лифт ускоряется вниз:</b> вес <b>меньше</b> $mg$. Если ускорение $= g$, то $P = 0$ — невесомость.';
|
||||
const m = +document.getElementById('p24-m-r').value;
|
||||
const a = +document.getElementById('p24-a-r').value; // положительное = вверх
|
||||
const g = 10;
|
||||
// Вес на пружине: P = m(g + a). a > 0 (лифт ускоряется вверх) → P > mg.
|
||||
// Если лифт в свободном падении (a = -g), P = 0.
|
||||
const P = Math.max(0, m * (g + a));
|
||||
const W = 380, H = 260;
|
||||
// Кабина лифта 160×220, центрирована
|
||||
const cabX = 110, cabY = 20, cabW = 160, cabH = 220;
|
||||
let s = '';
|
||||
// Шахта (стенки)
|
||||
s += '<line x1="' + (cabX - 10) + '" y1="0" x2="' + (cabX - 10) + '" y2="' + H + '" stroke="#94a3b8" stroke-width="2" stroke-dasharray="6 4"/>';
|
||||
s += '<line x1="' + (cabX + cabW + 10) + '" y1="0" x2="' + (cabX + cabW + 10) + '" y2="' + H + '" stroke="#94a3b8" stroke-width="2" stroke-dasharray="6 4"/>';
|
||||
// Кабина
|
||||
s += '<rect x="' + cabX + '" y="' + cabY + '" width="' + cabW + '" height="' + cabH + '" fill="#fff" stroke="#0f172a" stroke-width="2" rx="3"/>';
|
||||
// Стрелка ускорения слева снаружи
|
||||
if(Math.abs(a) > 0.3){
|
||||
const aY = cabY + cabH/2;
|
||||
const arrLen = Math.min(50, Math.abs(a) * 4);
|
||||
const dir = a > 0 ? -1 : 1; // вверх = -y, вниз = +y
|
||||
s += '<line x1="60" y1="' + aY + '" x2="60" y2="' + (aY + arrLen * dir) + '" stroke="#10b981" stroke-width="3"/>';
|
||||
s += '<polygon points="' + 55 + ',' + (aY + arrLen * dir - 8 * (-dir)) + ' ' + 65 + ',' + (aY + arrLen * dir - 8 * (-dir)) + ' ' + 60 + ',' + (aY + arrLen * dir) + '" fill="#10b981"/>';
|
||||
s += '<text x="60" y="' + (a > 0 ? aY - arrLen - 8 : aY + arrLen + 18) + '" text-anchor="middle" font-family="Inter,sans-serif" font-size="11" font-weight="700" fill="#10b981">a = ' + (a > 0 ? '+' : '') + a + '</text>';
|
||||
}
|
||||
svg.innerHTML = html;
|
||||
document.getElementById('p24-info').innerHTML = info;
|
||||
// Динамометр (вертикальный): корпус, пружина, груз
|
||||
const dynX = cabX + cabW/2, dynTop = cabY + 30;
|
||||
s += '<line x1="' + dynX + '" y1="' + cabY + '" x2="' + dynX + '" y2="' + dynTop + '" stroke="#475569" stroke-width="2"/>';
|
||||
// Корпус
|
||||
s += '<rect x="' + (dynX - 15) + '" y="' + dynTop + '" width="30" height="120" fill="#fef3c7" stroke="#92400e" stroke-width="1.5" rx="3"/>';
|
||||
// Пружина — длина пропорц. P
|
||||
const maxStretch = 80;
|
||||
const Pmax = m * (g + 10); // P при a = +10
|
||||
const stretch = Math.min(maxStretch, (P / Pmax) * maxStretch);
|
||||
const sprBot = dynTop + 5 + stretch;
|
||||
const coils = 6;
|
||||
let path = 'M ' + dynX + ' ' + (dynTop + 5);
|
||||
for(let i = 0; i < coils; i++){
|
||||
path += ' L ' + (dynX + (i%2 ? 9 : -9)) + ' ' + (dynTop + 5 + (i + 0.5) * stretch/coils);
|
||||
}
|
||||
path += ' L ' + dynX + ' ' + sprBot;
|
||||
s += '<path d="' + path + '" fill="none" stroke="#92400e" stroke-width="1.5"/>';
|
||||
// Шкала справа
|
||||
for(let i = 0; i <= 10; i++){
|
||||
const ty = dynTop + 5 + (i / 10) * maxStretch;
|
||||
s += '<line x1="' + (dynX + 15) + '" y1="' + ty + '" x2="' + (dynX + 22) + '" y2="' + ty + '" stroke="#92400e" stroke-width="1"/>';
|
||||
if(i % 2 === 0) s += '<text x="' + (dynX + 26) + '" y="' + (ty + 3) + '" font-family="Inter,sans-serif" font-size="8" fill="#92400e">' + ((Pmax * i / 10).toFixed(0)) + '</text>';
|
||||
}
|
||||
// Указатель
|
||||
s += '<line x1="' + (dynX - 10) + '" y1="' + sprBot + '" x2="' + (dynX + 12) + '" y2="' + sprBot + '" stroke="#dc2626" stroke-width="2.5"/>';
|
||||
// Груз — кружок снизу пружины
|
||||
s += '<circle cx="' + dynX + '" cy="' + (sprBot + 18) + '" r="14" fill="#dc2626" stroke="#7f1d1d" stroke-width="1.5"/>';
|
||||
s += '<text x="' + dynX + '" y="' + (sprBot + 22) + '" text-anchor="middle" font-family="Inter,sans-serif" font-size="9" font-weight="700" fill="#fff">' + m + ' кг</text>';
|
||||
// Показание динамометра в нижней части кабины
|
||||
s += '<text x="' + dynX + '" y="' + (cabY + cabH - 12) + '" text-anchor="middle" font-family="Unbounded,sans-serif" font-size="13" font-weight="800" fill="' + (P < 0.1 ? '#10b981' : (P > m*g ? '#dc2626' : (P < m*g ? '#0284c7' : '#475569'))) + '">P = ' + P.toFixed(1) + ' Н</text>';
|
||||
// Подпись режима
|
||||
let mode, modeCol;
|
||||
if(Math.abs(P - m*g) < 0.01){ mode = 'ПОКОЙ или равномерно: P = mg'; modeCol = '#475569'; }
|
||||
else if(P < 0.1){ mode = 'НЕВЕСОМОСТЬ: P = 0'; modeCol = '#10b981'; }
|
||||
else if(P > m*g){ mode = 'ПЕРЕГРУЗКА: P > mg'; modeCol = '#dc2626'; }
|
||||
else { mode = 'ПОНИЖЕННЫЙ ВЕС: P < mg'; modeCol = '#0284c7'; }
|
||||
s += '<text x="' + (cabX + cabW/2) + '" y="14" text-anchor="middle" font-family="Inter,sans-serif" font-size="11" font-weight="800" fill="' + modeCol + '">' + mode + '</text>';
|
||||
svg.innerHTML = s;
|
||||
document.getElementById('p24-m').textContent = m;
|
||||
document.getElementById('p24-a').textContent = a > 0 ? '+' + a : a;
|
||||
const Ft = m * g;
|
||||
document.getElementById('p24-info').innerHTML =
|
||||
'<b>$F_т = mg = ' + Ft.toFixed(1) + '$ Н</b> — сила тяжести на тело (не меняется при ускорении).<br>'
|
||||
+ '<b>$P = m(g + a) = ' + m + ' \\cdot (' + g + (a >= 0 ? ' + ' : ' − ') + Math.abs(a) + ') = ' + P.toFixed(1) + '$ Н</b> — показание динамометра (вес).<br>'
|
||||
+ '<span style="color:' + modeCol + ';font-weight:700">' + mode + '</span>';
|
||||
renderMath(document.getElementById('p24-info'));
|
||||
}
|
||||
body.querySelectorAll('.p24-sit').forEach(btn => btn.addEventListener('click', () => {
|
||||
body.querySelectorAll('.p24-sit').forEach(b => { b.style.background = '#fff'; b.style.color = '#dc2626'; });
|
||||
btn.style.background = '#dc2626'; btn.style.color = '#fff';
|
||||
draw24(btn.dataset.s);
|
||||
body.querySelectorAll('.p24-preset').forEach(btn => btn.addEventListener('click', () => {
|
||||
document.getElementById('p24-a-r').value = btn.dataset.a;
|
||||
draw24();
|
||||
}));
|
||||
draw24('rest');
|
||||
['p24-m-r','p24-a-r'].forEach(id => document.getElementById(id).addEventListener('input', draw24));
|
||||
draw24();
|
||||
|
||||
wireDnd('p24-dnd', [
|
||||
{ id:'a1', cat:'ft' },{ id:'a2', cat:'ft' },{ id:'a3', cat:'p' },
|
||||
|
||||
Reference in New Issue
Block a user