fix(textbooks): Физика 9 — STATE collision, KaTeX escape, авто-init симуляций

Три бага из жалобы пользователя:

1) phys9_legacy.js упал с 'Identifier STATE has already been declared' —
   const STATE в монолите конфликтовал с const STATE в chapter inline JS.
   Скрипт extract_phys9_legacy.cjs теперь оборачивает извлечённый код в IIFE
   и явно экспортит через window 70 функций (upd*/draw*/init*/start*/lab*/
   check*/toggle*/render*/show*/...) + 7 const-массивов (TASKS_PN, PUZ_PN).

2) В боковой панели формулы рендерились как 'Delta vecr' вместо Δr⃗ —
   мой переход на JSON.stringify в gen_phys9_ch.js добавил лишний слой
   escape backslash. Уменьшил \\ → \ в SIDEBAR_ROWS, TIPS_HTML,
   PARA_SUBS, LR_SUBS (90 строк). Цепочка теперь: source \Delta → string
   \Delta → JSON "\\Delta" → HTML JS \Delta → runtime \Delta →
   KaTeX \Delta ✓.

3) 'не работают симуляции' — функции из legacy.js были доступны, но
   chapter goTo(id) их не вызывал. Добавлен авто-вызов upd<N>(),
   startAnim<N>(), init<N>(), draw<N>() при переключении на параграф,
   и updLab<N>(), drawLab<N>() — для ЛР.
This commit is contained in:
Maxim Dolgolyov
2026-05-30 09:06:20 +03:00
parent c26423b7d4
commit 66bd7ac1f4
8 changed files with 412 additions and 194 deletions
+33 -16
View File
@@ -15,7 +15,6 @@
<script src="/js/api.js" defer></script>
<script src="/js/xp.js" defer></script>
<script src="/js/phys.js" defer></script>
<script src="/js/phys9_legacy.js" defer></script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Manrope:wght@600;700;800;900&family=Unbounded:wght@700;800;900&family=JetBrains+Mono:wght@500;700&display=swap" rel="stylesheet">
<style>
:root{
@@ -629,15 +628,15 @@ const TOTAL_PARAS = 13;
const _TB_SLUG = 'physics-9-ch5';
const PARAS = [
{ id:"lr1", num:"ЛР 1", name:"Определение абсолютной и относительной погрешностей прямых измерений", sub:"$\\\\Delta t$, $\\\\varepsilon_t$" },
{ id:"lr1", num:"ЛР 1", name:"Определение абсолютной и относительной погрешностей прямых измерений", sub:"$\\Delta t$, $\\varepsilon_t$" },
{ id:"lr2", num:"ЛР 2", name:"Измерение ускорения при равноускоренном движении", sub:"$a = 2l/t^2$" },
{ id:"lr3", num:"ЛР 3", name:"Изучение движения тела по окружности", sub:"$a_n = 4\\\\pi^2 R/T^2$" },
{ id:"lr3", num:"ЛР 3", name:"Изучение движения тела по окружности", sub:"$a_n = 4\\pi^2 R/T^2$" },
{ id:"lr4", num:"ЛР 4", name:"Проверка закона Гука", sub:"$k = F/x$" },
{ id:"lr5", num:"ЛР 5", name:"Измерение коэффициента трения скольжения", sub:"$\\\\mu = F_{тр}/P$" },
{ id:"lr6", num:"ЛР 6", name:"Изучение движения тела, брошенного горизонтально", sub:"$v_0 = l\\\\sqrt{g/(2h)}$" },
{ id:"lr5", num:"ЛР 5", name:"Измерение коэффициента трения скольжения", sub:"$\\mu = F_{тр}/P$" },
{ id:"lr6", num:"ЛР 6", name:"Изучение движения тела, брошенного горизонтально", sub:"$v_0 = l\\sqrt{g/(2h)}$" },
{ id:"lr7", num:"ЛР 7", name:"Проверка условия равновесия рычага", sub:"$F_1 l_1 = F_2 l_2$" },
{ id:"lr8", num:"ЛР 8", name:"Изучение неподвижного и подвижного блоков", sub:"$P h_1 = F h_2$" },
{ id:"lr9", num:"ЛР 9", name:"Изучение наклонной плоскости и измерение её КПД", sub:"$\\\\eta = mgh/A_{сов}$" },
{ id:"lr9", num:"ЛР 9", name:"Изучение наклонной плоскости и измерение её КПД", sub:"$\\eta = mgh/A_{сов}$" },
{ id:"lr10", num:"ЛР 10", name:"Изучение выталкивающей силы", sub:"$F_A = F_1 - F_2$" },
{ id:"lr11", num:"ЛР 11", name:"Проверка закона сохранения импульса", sub:"$m_1 l_1 = m_1 l_1' + m_2 l_2'$" },
{ id:"lr12", num:"ЛР 12", name:"Проверка закона сохранения механической энергии", sub:"$F|x| = ml^2 g/(2h)$" },
@@ -778,19 +777,37 @@ function goTo(id){
window.scrollTo({top:0,behavior:'smooth'});
if((STATE.progress[id]||0)<10) bumpProgress(id, 10);
if(window.renderMathInElement) setTimeout(()=>renderMath(el), 0);
// Auto-init legacy simulations: call upd<N>() / startAnim<N>() / draw<N>() if defined in phys9_legacy.js.
if(id.startsWith('p')){
const n = id.slice(1);
setTimeout(()=>{
['upd','startAnim','init','draw'].forEach(prefix=>{
const fn = window[prefix + n];
if(typeof fn === 'function'){ try{ fn(); }catch(e){ console.warn(prefix + n + ' init:', e.message); } }
});
}, 50);
} else if(id.startsWith('lr')){
const n = id.slice(2);
setTimeout(()=>{
['updLab','drawLab'].forEach(prefix=>{
const fn = window[prefix + n];
if(typeof fn === 'function'){ try{ fn(); }catch(e){} }
});
}, 50);
}
markLastPara(id);
}
const SIDEBARS = {
lr1:{title:"Шпаргалка ЛР 1",rows:[["Цель","$\\\\Delta t$, $\\\\varepsilon_t$"],["Обор.","мерная лента, шарик, секундомер"],["Формула","$\\\\varepsilon_t = \\\\Delta t/\\\\langle t\\\\rangle \\\\cdot 100\\\\%$"]]},
lr1:{title:"Шпаргалка ЛР 1",rows:[["Цель","$\\Delta t$, $\\varepsilon_t$"],["Обор.","мерная лента, шарик, секундомер"],["Формула","$\\varepsilon_t = \\Delta t/\\langle t\\rangle \\cdot 100\\%$"]]},
lr2:{title:"Шпаргалка ЛР 2",rows:[["Цель","измерить $a$ при равноускор."],["Обор.","жёлоб, шарик, секундомер"],["Формула","$a = 2l/t^2$"]]},
lr3:{title:"Шпаргалка ЛР 3",rows:[["Цель","$T$, $a_n$, $\\\\omega$, $v$"],["Обор.","штатив, нить, шарик"],["Формула","$a_n = 4\\\\pi^2 R/T^2$"]]},
lr3:{title:"Шпаргалка ЛР 3",rows:[["Цель","$T$, $a_n$, $\\omega$, $v$"],["Обор.","штатив, нить, шарик"],["Формула","$a_n = 4\\pi^2 R/T^2$"]]},
lr4:{title:"Шпаргалка ЛР 4",rows:[["Цель","$k$ пружины"],["Обор.","штатив, динамометр, грузы"],["Формула","$k = mg/|x|$"]]},
lr5:{title:"Шпаргалка ЛР 5",rows:[["Цель","$\\\\mu$ дерево/дерево"],["Обор.","брусок, доска, динамометр"],["Формула","$\\\\mu = F_{упр}/P$"]]},
lr6:{title:"Шпаргалка ЛР 6",rows:[["Цель","$v_0$ гориз. бросок"],["Обор.","лоток, шарик, копир. бумага"],["Формула","$v_0 = l\\\\sqrt{g/(2h)}$"]]},
lr5:{title:"Шпаргалка ЛР 5",rows:[["Цель","$\\mu$ дерево/дерево"],["Обор.","брусок, доска, динамометр"],["Формула","$\\mu = F_{упр}/P$"]]},
lr6:{title:"Шпаргалка ЛР 6",rows:[["Цель","$v_0$ гориз. бросок"],["Обор.","лоток, шарик, копир. бумага"],["Формула","$v_0 = l\\sqrt{g/(2h)}$"]]},
lr7:{title:"Шпаргалка ЛР 7",rows:[["Цель","правило рычага"],["Обор.","рычаг, грузы"],["Формула","$F_1 l_1 = F_2 l_2$"]]},
lr8:{title:"Шпаргалка ЛР 8",rows:[["Цель","выигр. подв. блока"],["Обор.","блоки, динамометр"],["Формула","$P h_1 = F h_2$"]]},
lr9:{title:"Шпаргалка ЛР 9",rows:[["Цель","КПД накл. плоскости"],["Обор.","доска, брусок, динамометр"],["Формула","$\\\\eta = mgh/(F_{упр}l)\\\\cdot 100\\\\%$"]]},
lr9:{title:"Шпаргалка ЛР 9",rows:[["Цель","КПД накл. плоскости"],["Обор.","доска, брусок, динамометр"],["Формула","$\\eta = mgh/(F_{упр}l)\\cdot 100\\%$"]]},
lr10:{title:"Шпаргалка ЛР 10",rows:[["Цель","$F_A$ для разных жидк."],["Обор.","цилиндры, динамометр, вода, соль"],["Формула","$F_A = F_{упр1} - F_{упр2}$"]]},
lr11:{title:"Шпаргалка ЛР 11",rows:[["Цель","проверить ЗСИ"],["Обор.","лоток, два шара, бумага"],["Формула","$m_1 l_1 = m_1 l_1' + m_2 l_2'$"]]},
lr12:{title:"Шпаргалка ЛР 12",rows:[["Цель","проверить ЗСЭ"],["Обор.","лоток, шар, пружина, бумага"],["Формула","$F|x| = ml^2g/(2h)$"]]},
@@ -798,15 +815,15 @@ const SIDEBARS = {
};
const TIPS=[
{sec:"lr1",html:"ЛР1: погрешности прямых измерений. $\\\\Delta t = \\\\Delta t_{сист} + \\\\Delta t_{случ}$. Результат в интервальной форме: $t = \\\\langle t\\\\rangle \\\\pm \\\\Delta t$."},
{sec:"lr1",html:"ЛР1: погрешности прямых измерений. $\\Delta t = \\Delta t_{сист} + \\Delta t_{случ}$. Результат в интервальной форме: $t = \\langle t\\rangle \\pm \\Delta t$."},
{sec:"lr2",html:"ЛР2: ускорение шарика по наклонному жёлобу. $a = 2l/t^2$ (из $s = at^2/2$ при $v_0 = 0$)."},
{sec:"lr3",html:"ЛР3: движение по окружности. Измеряем $T$, считаем $a_n = 4\\\\pi^2 R/T^2$, $\\\\omega = 2\\\\pi/T$, $v = \\\\omega R$."},
{sec:"lr3",html:"ЛР3: движение по окружности. Измеряем $T$, считаем $a_n = 4\\pi^2 R/T^2$, $\\omega = 2\\pi/T$, $v = \\omega R$."},
{sec:"lr4",html:"ЛР4: закон Гука. Подвешиваем грузы, строим график $F_{упр}(x)$. Жёсткость $k = mg/|x|$."},
{sec:"lr5",html:"ЛР5: коэффициент трения скольжения дерева по дереву. $\\\\mu = F_{упр}/P$."},
{sec:"lr6",html:"ЛР6: тело, брошенное горизонтально. Измеряем дальность $l$ и высоту $h$. $v_0 = l\\\\sqrt{g/(2h)}$."},
{sec:"lr5",html:"ЛР5: коэффициент трения скольжения дерева по дереву. $\\mu = F_{упр}/P$."},
{sec:"lr6",html:"ЛР6: тело, брошенное горизонтально. Измеряем дальность $l$ и высоту $h$. $v_0 = l\\sqrt{g/(2h)}$."},
{sec:"lr7",html:"ЛР7: условие равновесия рычага. Проверяем $F_1 l_1 = F_2 l_2$."},
{sec:"lr8",html:"ЛР8: блоки. Неподв. — без выигрыша; подвижный — выигрыш в силе в 2 раза, проигрыш в пути в 2 раза."},
{sec:"lr9",html:"ЛР9: КПД наклонной плоскости. $\\\\eta = A_{пол}/A_{сов} = mgh/(F_{упр}l)\\\\cdot 100\\\\%$. Сравниваем при 30° и 45°."},
{sec:"lr9",html:"ЛР9: КПД наклонной плоскости. $\\eta = A_{пол}/A_{сов} = mgh/(F_{упр}l)\\cdot 100\\%$. Сравниваем при 30° и 45°."},
{sec:"lr10",html:"ЛР10: выталкивающая сила Архимеда. $F_A = F_{упр1} - F_{упр2}$ (вес в воздухе минус вес в жидкости)."},
{sec:"lr11",html:"ЛР11: ЗСИ. Шар $m_1$ скатывается, сталкивается с покоящимся шаром $m_2$. Проверяем $m_1 l_1 = m_1 l_1' + m_2 l_2'$."},
{sec:"lr12",html:"ЛР12: ЗСЭ. Сжатая пружина → шар → дальность полёта. $F_{упр}|x| = ml^2 g/(2h)$."},