218baef4ad
electrolysis.js (556 → 1072 строк): - База электролитов с 3 до 6: NaCl/CuSO4/H2SO4 + KI/ZnSO4/AgNO3 - Стеклянный сосуд с бликами, волнующаяся поверхность раствора (sin-анимация) - Ионы со стробоскопным шлейфом (4 точки) и радиальным свечением - Пузырьки: растут при подъёме + pop-эффект на поверхности (LabFX) - Осадок: градиент по металлу (Cu медь / Zn серый / Ag серебро) + метка - Электроды с bevel и polarity badge (− / +) - Внешняя цепь: батарея + провода + анимированные жёлтые электроны - Закон Фарадея: панель с живой подстановкой U/I/t/Q/m/V в формулу - Графики m(t)/V(t): мини-холст 200×75 с двумя трендами - info() добавлены Q (Кл) и n_электронов lab.html (sim-electrolysis): - Панель 220 → 280px, класс elec-panel-modern - elec-quick-bar: Старт/Сброс всегда видны - 4 collapsible-секции elec-acc: Электролит / Скорость / Отображение / Уравнения - Stats bar 4 → 6: добавлены Q и e⁻ lab.css: стили .elec-panel-modern, .elec-quick-bar, .elec-acc по паттерну geo-acc/dyn-acc
4847 lines
383 KiB
HTML
4847 lines
383 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="ru">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||
<title>Лаборатория — LearnSpace</title>
|
||
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
|
||
<link href="https://fonts.googleapis.com/css2?family=Unbounded:wght@400;700;800&family=Manrope:wght@400;500;600;700&display=swap" rel="stylesheet" />
|
||
<link rel="stylesheet" href="/css/ls.css" />
|
||
<link rel="stylesheet" href="/css/lab.css" />
|
||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.css">
|
||
<script src="https://cdn.jsdelivr.net/npm/lucide@0.469.0/dist/umd/lucide.min.js"></script>
|
||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.js"></script>
|
||
</head>
|
||
<body>
|
||
<div class="app-layout">
|
||
<aside class="sidebar" id="app-sidebar"></aside>
|
||
<div class="notif-drop" id="notif-drop"></div>
|
||
|
||
<div class="sb-content">
|
||
|
||
<!-- ══════════ HOME VIEW ══════════ -->
|
||
<div id="lab-home">
|
||
|
||
<div class="lab-hero">
|
||
<div class="lab-hero-icon">
|
||
<i data-lucide="atom" style="width:30px;height:30px;stroke:var(--violet);stroke-width:1.5"></i>
|
||
</div>
|
||
<div>
|
||
<div class="lab-hero-title">Лаборатория</div>
|
||
<div class="lab-hero-sub">Интерактивные симуляции по математике и физике</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="lab-filters">
|
||
<button class="lab-filter active" onclick="filterSims('all',this)">Все</button>
|
||
<button class="lab-filter" onclick="filterSims('math',this)">
|
||
<i data-lucide="sigma" style="width:12px;height:12px;vertical-align:-2px;margin-right:4px"></i>Математика
|
||
</button>
|
||
<button class="lab-filter" onclick="filterSims('phys',this)">
|
||
<i data-lucide="zap" style="width:12px;height:12px;vertical-align:-2px;margin-right:4px"></i>Физика
|
||
</button>
|
||
<button class="lab-filter" onclick="filterSims('chem',this)">
|
||
<i data-lucide="flask-conical" style="width:12px;height:12px;vertical-align:-2px;margin-right:4px"></i>Химия
|
||
</button>
|
||
<button class="lab-filter" onclick="filterSims('bio',this)">
|
||
<i data-lucide="dna" style="width:12px;height:12px;vertical-align:-2px;margin-right:4px"></i>Биология
|
||
</button>
|
||
<button class="lab-filter" onclick="filterSims('game',this)">
|
||
<i data-lucide="gamepad-2" style="width:12px;height:12px;vertical-align:-2px;margin-right:4px"></i>Игры
|
||
</button>
|
||
</div>
|
||
|
||
<div class="sim-grid" id="sim-grid"></div>
|
||
</div>
|
||
|
||
<!-- ══════════ SIM VIEW ══════════ -->
|
||
<div id="lab-sim">
|
||
|
||
<!-- top bar -->
|
||
<div class="sim-topbar">
|
||
<button class="sim-back" onclick="closeSim()">
|
||
<svg viewBox="0 0 24 24" fill="none"><polyline points="15 18 9 12 15 6"/></svg>
|
||
Назад
|
||
</button>
|
||
<div class="sim-topbar-title" id="sim-topbar-title"></div>
|
||
|
||
<!-- graph controls -->
|
||
<div id="ctrl-graph" class="sim-zoom-btns">
|
||
<button class="zoom-btn" onclick="gSim.zoomIn()" title="Приблизить">
|
||
<svg viewBox="0 0 24 24" fill="none"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/><line x1="11" y1="8" x2="11" y2="14"/><line x1="8" y1="11" x2="14" y2="11"/></svg>
|
||
</button>
|
||
<button class="zoom-btn" onclick="gSim.zoomOut()" title="Отдалить">
|
||
<svg viewBox="0 0 24 24" fill="none"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/><line x1="8" y1="11" x2="14" y2="11"/></svg>
|
||
</button>
|
||
<button class="zoom-btn" onclick="gSim.resetView()" title="Сброс вида">
|
||
<svg viewBox="0 0 24 24" fill="none"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>
|
||
</button>
|
||
</div>
|
||
|
||
<!-- projectile controls -->
|
||
<div id="ctrl-proj" class="sim-zoom-btns" style="display:none">
|
||
<button class="zoom-btn" id="proj-play-btn" onclick="projPlayPause()" title="Запустить">
|
||
<svg viewBox="0 0 24 24" fill="currentColor"><polygon points="5 3 19 12 5 21 5 3"/></svg>
|
||
</button>
|
||
<button class="zoom-btn" onclick="pSim && pSim.reset(); _projSyncPlayBtn()" title="Сброс">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>
|
||
</button>
|
||
<div style="width:1px;height:20px;background:rgba(255,255,255,0.15);margin:0 2px"></div>
|
||
<button class="zoom-btn" onclick="projSaveGhost()" title="Зафиксировать траекторию" style="font-size:.65rem;font-weight:800"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="display:inline-block;vertical-align:middle"><path d="M12 2a7 7 0 00-7 7c0 5.25 7 13 7 13s7-7.75 7-13a7 7 0 00-7-7z"/><circle cx="12" cy="9" r="2.5"/></svg></button>
|
||
<button class="zoom-btn" onclick="projClearGhosts()" title="Очистить следы" style="font-size:.65rem"><svg class="ic" viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button>
|
||
</div>
|
||
|
||
<!-- emfield controls -->
|
||
<div id="ctrl-emfield" class="sim-zoom-btns" style="display:none">
|
||
<button class="zoom-btn" id="em-sign-pos" onclick="emSign(1)" title="Добавлять + заряды" style="font-size:1.1rem;font-weight:900;color:#EF476F">+</button>
|
||
<button class="zoom-btn" id="em-sign-neg" onclick="emSign(-1)" title="Добавлять − заряды" style="font-size:1.1rem;font-weight:900;color:#4CC9F0">−</button>
|
||
<button class="zoom-btn" id="em-dir-out" onclick="emWireDir('out')" title="Провод • (ток на нас)" style="font-size:1rem">•</button>
|
||
<button class="zoom-btn" id="em-dir-in" onclick="emWireDir('in')" title="Провод × (ток от нас)" style="font-size:1rem">×</button>
|
||
<button class="zoom-btn" onclick="emSim && emSim.clearAll()" title="Очистить">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14H6L5 6"/></svg>
|
||
</button>
|
||
</div>
|
||
|
||
<!-- triangle controls -->
|
||
<div id="ctrl-tri" class="sim-zoom-btns" style="display:none">
|
||
<button class="zoom-btn" onclick="tSim && tSim.reset()" title="Сбросить треугольник">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>
|
||
</button>
|
||
</div>
|
||
|
||
<!-- geometry controls -->
|
||
<div id="ctrl-geometry" class="sim-zoom-btns" style="display:none">
|
||
<button class="zoom-btn" onclick="geomSim&&geomSim.undo()" title="Отменить (Ctrl+Z)">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M3 7v6h6"/><path d="M3 13A9 9 0 1 0 6 6.3L3 7"/></svg>
|
||
</button>
|
||
<button class="zoom-btn" onclick="geomSim&&geomSim.redo()" title="Повторить (Ctrl+Y)">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M21 7v6h-6"/><path d="M21 13A9 9 0 1 1 18 6.3L21 7"/></svg>
|
||
</button>
|
||
<button class="zoom-btn" onclick="geomSim&&geomSim.deleteSelected()" title="Удалить выбранное">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14H6L5 6"/><path d="M10 11v6"/><path d="M14 11v6"/><path d="M9 6V4h6v2"/></svg>
|
||
</button>
|
||
<div style="width:1px;height:20px;background:rgba(255,255,255,0.1);margin:0 2px"></div>
|
||
<button class="zoom-btn" onclick="geomSim&&geomSim.resetView()" title="Сброс вида">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>
|
||
</button>
|
||
<button class="zoom-btn" onclick="geomSim&&geomSim.exportPNG()" title="Экспорт PNG">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
|
||
</button>
|
||
</div>
|
||
|
||
<!-- trig circle controls -->
|
||
<div id="ctrl-trigcircle" class="sim-zoom-btns" style="display:none">
|
||
<button class="zoom-btn" onclick="trigReset()" title="Сбросить на 45°">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>
|
||
</button>
|
||
</div>
|
||
|
||
<!-- collision controls -->
|
||
<div id="ctrl-coll" class="sim-zoom-btns" style="display:none">
|
||
<button class="zoom-btn" id="coll-play-btn" onclick="collPlayPause()" title="Запустить">
|
||
<svg viewBox="0 0 24 24" fill="currentColor"><polygon points="5 3 19 12 5 21 5 3"/></svg>
|
||
</button>
|
||
<button class="zoom-btn" onclick="var _as=_activeSim&&_activeSim();if(_as)_as.reset();_collSyncBtn();" title="Сброс">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>
|
||
</button>
|
||
</div>
|
||
|
||
<!-- molphys controls (unified: gas + brownian + states + diffusion) -->
|
||
<div id="ctrl-molphys" class="sim-zoom-btns" style="display:none">
|
||
<!-- diffusion-only: partition button -->
|
||
<span id="ctrl-mol-diff" style="display:none">
|
||
<button class="zoom-btn" onclick="diffSim && diffSim.togglePartition(); diffPartitionBtn()" title="Снять/поставить раздел" style="font-size:0.72rem;font-weight:800;font-family:Manrope,sans-serif" id="diffusion-part-btn">
|
||
‖ Раздел
|
||
</button>
|
||
</span>
|
||
<button class="zoom-btn" onclick="molReset()" title="Сброс">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>
|
||
</button>
|
||
</div>
|
||
|
||
<!-- (coulomb merged into ctrl-emfield) -->
|
||
|
||
<!-- circuit controls -->
|
||
<div id="ctrl-circuit" class="sim-zoom-btns" style="display:none">
|
||
<button class="zoom-btn circ-top-btn active" id="ctool-wire" onclick="circTool('wire',this)" title="Провод (W)" style="font-size:.7rem;font-weight:800">~</button>
|
||
<button class="zoom-btn circ-top-btn" id="ctool-resistor" onclick="circTool('resistor',this)" title="Резистор (R)" style="font-size:.6rem;font-weight:800">R</button>
|
||
<button class="zoom-btn circ-top-btn" id="ctool-battery" onclick="circTool('battery',this)" title="Батарея (B)" style="font-size:.6rem;font-weight:800">U</button>
|
||
<button class="zoom-btn circ-top-btn" id="ctool-capacitor" onclick="circTool('capacitor',this)" title="Конденсатор (C)" style="font-size:.6rem;font-weight:800">C</button>
|
||
<button class="zoom-btn circ-top-btn" id="ctool-inductor" onclick="circTool('inductor',this)" title="Катушка индуктивности (I)" style="font-size:.65rem"><svg class="ic" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M2 12 Q4 8 6 12 Q8 8 10 12 Q12 8 14 12"/><line x1="14" y1="12" x2="22" y2="12"/><line x1="2" y1="12" x2="2" y2="12"/></svg></button>
|
||
<button class="zoom-btn circ-top-btn" id="ctool-diode" onclick="circTool('diode',this)" title="Диод (D)" style="font-size:.75rem"><svg class="ic" viewBox="0 0 24 24"><polygon points="5 3 19 12 5 21 5 3"/></svg>|</button>
|
||
<button class="zoom-btn circ-top-btn" id="ctool-led" onclick="circTool('led',this)" title="LED" style="font-size:.6rem;font-weight:800">LED</button>
|
||
<button class="zoom-btn circ-top-btn" id="ctool-ac" onclick="circTool('ac',this)" title="AC источник" style="font-size:.65rem;font-weight:800">AC</button>
|
||
<button class="zoom-btn circ-top-btn" id="ctool-switch" onclick="circTool('switch',this)" title="Выключатель (S)" style="font-size:.7rem"><svg class="ic" viewBox="0 0 24 24"><line x1="3" y1="12" x2="9" y2="12"/><line x1="15" y1="12" x2="21" y2="12"/><line x1="9" y1="12" x2="17" y2="6"/></svg></button>
|
||
<button class="zoom-btn circ-top-btn" id="ctool-lamp" onclick="circTool('lamp',this)" title="Лампа (L)" style="font-size:.75rem"><svg class="ic" viewBox="0 0 24 24"><circle cx="12" cy="12" r="8"/><circle cx="12" cy="12" r="3"/></svg></button>
|
||
<button class="zoom-btn circ-top-btn" id="ctool-ammeter" onclick="circTool('ammeter',this)" title="Амперметр (A)" style="font-size:.6rem;font-weight:800">А</button>
|
||
<button class="zoom-btn circ-top-btn" id="ctool-voltmeter" onclick="circTool('voltmeter',this)" title="Вольтметр (V)" style="font-size:.6rem;font-weight:800">V</button>
|
||
<button class="zoom-btn circ-top-btn" id="ctool-erase" onclick="circTool('erase',this)" title="Ластик (E)">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M20 20H7L3 16l11.5-11.5a2 2 0 0 1 2.83 0l3.17 3.17a2 2 0 0 1 0 2.83L13 18"/><line x1="6" y1="14" x2="18" y2="2"/></svg>
|
||
</button>
|
||
<div style="width:1px;height:20px;background:rgba(255,255,255,0.15);margin:0 2px"></div>
|
||
<button class="zoom-btn" onclick="cirSim&&cirSim.undo()" title="Отменить (Ctrl+Z)" style="font-size:.65rem"><svg class="ic" viewBox="0 0 24 24"><polyline points="9 14 4 9 9 4"/><path d="M20 20v-7a4 4 0 0 0-4-4H4"/></svg></button>
|
||
<button class="zoom-btn" onclick="cirSim&&cirSim.redo()" title="Повторить (Ctrl+Y)" style="font-size:.65rem"><svg class="ic" viewBox="0 0 24 24"><polyline points="15 14 20 9 15 4"/><path d="M4 20v-7a4 4 0 0 1 4-4h12"/></svg></button>
|
||
<button class="zoom-btn" onclick="cirSim&&cirSim.preset('clear')" title="Очистить">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14H6L5 6"/></svg>
|
||
</button>
|
||
<div style="width:1px;height:20px;background:rgba(255,255,255,0.15);margin:0 2px"></div>
|
||
<button class="zoom-btn" id="ctool-heat" onclick="circToggleHeat()" title="Тепловая карта мощности" style="font-size:.6rem;font-weight:700">
|
||
<svg class="ic" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M12 2C8 6 6 10 8 14c1 2 3 4 4 6"/><path d="M16 6c-2 3-3 6-1 9 1 1.5 1 3 0 4"/><path d="M8 6C6 9 5 12 7 15"/></svg>
|
||
</button>
|
||
<button class="zoom-btn" id="btn-osc-toggle" onclick="circToggleOsc()" title="Осциллограф U(t) / I(t)" style="font-size:.6rem;font-weight:700">
|
||
<svg class="ic" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><rect x="2" y="4" width="20" height="16" rx="2"/><polyline points="6 16 8 10 11 14 13 8 16 16"/></svg>
|
||
</button>
|
||
</div>
|
||
|
||
<!-- reactions controls -->
|
||
<!-- chemistry controls (unified) -->
|
||
<div id="ctrl-chemistry" class="sim-zoom-btns" style="display:none">
|
||
<!-- kinetics tools -->
|
||
<span id="ctrl-chem-kin" style="display:contents">
|
||
<button class="zoom-btn" id="reac-pause-btn" onclick="reacTogglePause()" title="Пауза реакций" style="font-size:.68rem;font-weight:800;font-family:Manrope,sans-serif"><svg class="ic" viewBox="0 0 24 24"><rect x="6" y="4" width="4" height="16"/><rect x="14" y="4" width="4" height="16"/></svg> Пауза</button>
|
||
</span>
|
||
<!-- flask tools -->
|
||
<span id="ctrl-chem-flask" style="display:none">
|
||
<button class="zoom-btn" onclick="flaskSim && flaskSim.dropMetal()" title="Бросить металл" style="font-size:.65rem;font-weight:800"><svg class="ic" viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><polyline points="19 12 12 19 5 12"/></svg> Металл</button>
|
||
<button class="zoom-btn" id="flask-flame-btn" onclick="flaskToggleFlame()" title="Поджечь H₂" style="font-size:.75rem"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="display:inline-block;vertical-align:middle"><path d="M12 2c.5 3.5-1.5 6-1.5 6 1 1.5 3 2 3 5a4 4 0 01-8 0c0-2 .5-3 1.5-4.5C8.5 6.5 7 4.5 7 4.5S9.5 2 12 2z"/></svg></button>
|
||
<button class="zoom-btn" id="flask-pause-btn" onclick="flaskTogglePause()" title="Пауза" style="font-size:.68rem;font-weight:800;font-family:Manrope,sans-serif"><svg class="ic" viewBox="0 0 24 24"><rect x="6" y="4" width="4" height="16"/><rect x="14" y="4" width="4" height="16"/></svg></button>
|
||
</span>
|
||
<!-- redox tools -->
|
||
<span id="ctrl-chem-redox" style="display:none">
|
||
<button class="zoom-btn" onclick="redoxStart()" title="Начать" style="font-size:.65rem;font-weight:800"><svg class="ic" viewBox="0 0 24 24"><polygon points="5 3 19 12 5 21 5 3"/></svg> Старт</button>
|
||
</span>
|
||
<!-- ionex tools -->
|
||
<span id="ctrl-chem-ionex" style="display:none">
|
||
<button class="zoom-btn" onclick="ionexStart()" title="Смешать" style="font-size:.65rem;font-weight:800"><svg class="ic" viewBox="0 0 24 24"><path d="M9 3h6m-4.5 0v5.5l-4 7.5a1 1 0 0 0 .9 1.5h8.2a1 1 0 0 0 .9-1.5l-4-7.5V3"/></svg> Смешать</button>
|
||
</span>
|
||
<div style="width:1px;height:20px;background:rgba(255,255,255,0.15);margin:0 3px"></div>
|
||
<button class="zoom-btn" onclick="chemReset()" title="Сброс">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>
|
||
</button>
|
||
</div>
|
||
|
||
<!-- newton controls -->
|
||
<!-- dynamics controls (unified newton + sandbox) -->
|
||
<div id="ctrl-dynamics" class="sim-zoom-btns" style="display:none">
|
||
<!-- sandbox tools (shown in sandbox mode) -->
|
||
<span id="ctrl-dyn-sb" style="display:contents">
|
||
<button class="zoom-btn sb-tool-btn active" id="sbt-box" onclick="sbTool('box',this)" style="font-size:.78rem;font-weight:700"><svg class="ic" viewBox="0 0 24 24"><rect x="3" y="3" width="18" height="18" rx="2"/></svg> Блок</button>
|
||
<button class="zoom-btn sb-tool-btn" id="sbt-ball" onclick="sbTool('ball',this)" style="font-size:.78rem;font-weight:700"><svg class="ic" viewBox="0 0 24 24"><circle cx="12" cy="12" r="8" fill="currentColor" stroke="none"/></svg> Шар</button>
|
||
<button class="zoom-btn sb-tool-btn" id="sbt-spring" onclick="sbTool('spring',this)" style="font-size:.78rem;font-weight:700"><svg class="ic" viewBox="0 0 24 24" fill="none"><path d="M3 12 L6 8 L9 16 L12 8 L15 16 L18 8 L21 12"/></svg> Пружина</button>
|
||
<button class="zoom-btn sb-tool-btn" id="sbt-rope" onclick="sbTool('rope',this)" style="font-size:.78rem;font-weight:700">— Нить</button>
|
||
<button class="zoom-btn sb-tool-btn" id="sbt-anchor" onclick="sbTool('anchor',this)" style="font-size:.78rem;font-weight:700"><svg class="ic" viewBox="0 0 24 24"><path d="M12 2 2 12 12 22 22 12Z"/></svg> Якорь</button>
|
||
<button class="zoom-btn sb-tool-btn" id="sbt-erase" onclick="sbTool('erase',this)" style="font-size:.78rem;font-weight:700"><svg class="ic" viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg> Ластик</button>
|
||
</span>
|
||
<!-- newton tools (shown in law modes) -->
|
||
<span id="ctrl-dyn-nw" style="display:none">
|
||
<button class="zoom-btn nscene-btn active" id="nscn-A" onclick="newtonScene('A',this)" style="font-size:.82rem;font-weight:700;padding:4px 12px">A</button>
|
||
<button class="zoom-btn nscene-btn" id="nscn-B" onclick="newtonScene('B',this)" style="font-size:.82rem;font-weight:700;padding:4px 12px">B</button>
|
||
<button class="zoom-btn nscene-btn" id="nscn-C" onclick="newtonScene('C',this)" style="font-size:.82rem;font-weight:700;padding:4px 12px">C</button>
|
||
<!-- classic scenes (law 4, hidden by default) -->
|
||
<button class="zoom-btn nscene-btn cl-scene-btn" id="nscn-cl-atwood" data-scene="atwood" onclick="classicScene('atwood')" style="display:none;font-size:.78rem;font-weight:700">Атвуд</button>
|
||
<button class="zoom-btn nscene-btn cl-scene-btn" id="nscn-cl-ramp" data-scene="ramp" onclick="classicScene('ramp')" style="display:none;font-size:.78rem;font-weight:700">Наклон</button>
|
||
<button class="zoom-btn nscene-btn cl-scene-btn" id="nscn-cl-roll" data-scene="roll" onclick="classicScene('roll')" style="display:none;font-size:.78rem;font-weight:700">Качение</button>
|
||
<div style="width:1px;height:20px;background:rgba(255,255,255,0.15);margin:0 3px"></div>
|
||
<button class="zoom-btn" id="newton-action-top" onclick="newtonAction()" style="font-size:.78rem;font-weight:700;font-family:Manrope,sans-serif"><svg class="ic" viewBox="0 0 24 24"><polygon points="5 3 19 12 5 21 5 3"/></svg> Действие</button>
|
||
</span>
|
||
<div style="width:1px;height:20px;background:rgba(255,255,255,0.15);margin:0 3px"></div>
|
||
<button class="zoom-btn" onclick="dynPause()" title="Пауза" style="font-size:.75rem"><svg class="ic" viewBox="0 0 24 24"><rect x="6" y="4" width="4" height="16"/><rect x="14" y="4" width="4" height="16"/></svg></button>
|
||
<button class="zoom-btn" onclick="dynReset()" title="Сброс">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>
|
||
</button>
|
||
</div>
|
||
|
||
|
||
<!-- chemsandbox controls -->
|
||
<div id="ctrl-chemsandbox" class="sim-zoom-btns" style="display:none">
|
||
<button class="zoom-btn" onclick="chemSandResetReaction()" title="Сбросить реакцию" style="font-size:.65rem;font-weight:800"><svg class="ic" viewBox="0 0 24 24"><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 .49-4.12"/></svg> Сброс реакции</button>
|
||
<button class="zoom-btn" onclick="chemSandReset()" title="Очистить всё" style="font-size:.65rem;font-weight:800"><svg class="ic" viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg> Очистить</button>
|
||
</div>
|
||
|
||
<!-- celldivision controls -->
|
||
<div id="ctrl-celldivision" class="sim-zoom-btns" style="display:none">
|
||
<button class="zoom-btn" onclick="cdPrevPhase()" title="Предыдущая фаза" style="font-size:.65rem;font-weight:800"><svg class="ic" viewBox="0 0 24 24"><polygon points="19 20 9 12 19 4 19 20"/></svg> Назад</button>
|
||
<button class="zoom-btn" onclick="cdNextPhase()" title="Следующая фаза" style="font-size:.65rem;font-weight:800">Далее <svg class="ic" viewBox="0 0 24 24"><polygon points="5 3 19 12 5 21 5 3"/></svg></button>
|
||
<button class="zoom-btn" id="ctrl-cd-auto" onclick="cdAutoPlay(document.getElementById('cd-auto-btn'))" title="Авто" style="font-size:.65rem;font-weight:800"><svg class="ic" viewBox="0 0 24 24"><polygon points="5 3 19 12 5 21 5 3"/></svg> Авто</button>
|
||
</div>
|
||
|
||
<!-- photosynthesis controls -->
|
||
<div id="ctrl-photosynthesis" class="sim-zoom-btns" style="display:none">
|
||
<button class="zoom-btn" onclick="psReset()" title="Сброс" style="font-size:.65rem;font-weight:800"><svg class="ic" viewBox="0 0 24 24"><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 .49-4.12"/></svg> Сброс</button>
|
||
</div>
|
||
|
||
<div id="ctrl-angrybirds" class="sim-zoom-btns" style="display:none">
|
||
<button class="zoom-btn" onclick="angryBirdsRestart()" title="Начать уровень заново" style="font-size:.65rem;font-weight:800"><svg class="ic" viewBox="0 0 24 24"><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 .49-4.12"/></svg> Сначала</button>
|
||
</div>
|
||
|
||
<!-- waves controls -->
|
||
<div id="ctrl-waves" class="sim-zoom-btns" style="display:none">
|
||
<button class="zoom-btn" id="waves-play-btn" onclick="wavesPlayPause()" title="Пауза/Старт">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><rect x="6" y="4" width="4" height="16"/><rect x="14" y="4" width="4" height="16"/></svg>
|
||
</button>
|
||
<button class="zoom-btn" onclick="wavesSim && wavesSim.reset()" title="Сброс">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>
|
||
</button>
|
||
</div>
|
||
|
||
<!-- hydrostatics controls -->
|
||
<div id="ctrl-hydro" class="sim-zoom-btns" style="display:none">
|
||
<select id="hydro-mode-sel" onchange="hydroMode(this.value)" style="background:#1a1030;color:#f0e8ff;border:1px solid rgba(255,255,255,.15);border-radius:7px;padding:3px 8px;font-size:.72rem;cursor:pointer">
|
||
<option value="pressure">Давление P=ρgh</option>
|
||
<option value="surface">Пов. натяжение</option>
|
||
<option value="communicating">Сообщ. сосуды</option>
|
||
<option value="archimedes">Архимед</option>
|
||
</select>
|
||
<select id="hydro-liq-sel" onchange="hydroSim&&hydroSim.setLiquid(this.value)" style="background:#1a1030;color:#f0e8ff;border:1px solid rgba(255,255,255,.15);border-radius:7px;padding:3px 8px;font-size:.72rem;cursor:pointer">
|
||
<option value="water">Вода</option>
|
||
<option value="saltwater">Солёная вода</option>
|
||
<option value="oil">Масло</option>
|
||
<option value="alcohol">Спирт</option>
|
||
<option value="glycerin">Глицерин</option>
|
||
<option value="mercury">Ртуть</option>
|
||
</select>
|
||
<div id="hydro-arch-ctrl" style="display:none;gap:4px;align-items:center">
|
||
<select id="hydro-mat-sel" onchange="hydroSim&&hydroSim.setMaterial(this.value)" style="background:#1a1030;color:#f0e8ff;border:1px solid rgba(255,255,255,.15);border-radius:7px;padding:3px 8px;font-size:.72rem;cursor:pointer">
|
||
<option value="styrofoam">Пенопласт</option>
|
||
<option value="cork">Пробка</option>
|
||
<option value="wood">Дерево</option>
|
||
<option value="ice">Лёд</option>
|
||
<option value="plastic">Пластик</option>
|
||
<option value="glass">Стекло</option>
|
||
<option value="aluminum">Алюминий</option>
|
||
<option value="iron">Железо</option>
|
||
<option value="gold">Золото</option>
|
||
</select>
|
||
<button class="zoom-btn" onclick="hydroSim&&hydroSim.addBody()" title="Добавить тело">+ Тело</button>
|
||
<button class="zoom-btn" onclick="hydroSim&&hydroSim.clearBodies()" title="Очистить">Очистить</button>
|
||
</div>
|
||
<div id="hydro-comm-ctrl" style="display:none;gap:4px;align-items:center">
|
||
<label style="font-size:.72rem;color:rgba(255,255,255,.5)">Сосудов:</label>
|
||
<select onchange="hydroSim&&hydroSim.setNumVessels(+this.value)" style="background:#1a1030;color:#f0e8ff;border:1px solid rgba(255,255,255,.15);border-radius:7px;padding:3px 6px;font-size:.72rem;cursor:pointer">
|
||
<option value="2">2</option>
|
||
<option value="3">3</option>
|
||
<option value="4">4</option>
|
||
</select>
|
||
<button class="zoom-btn" id="hydro-valve-btn" onclick="hydroToggleValve()" title="Кран">Кран: откр.</button>
|
||
</div>
|
||
<div id="hydro-surf-ctrl" style="display:none;gap:4px;align-items:center">
|
||
<label style="font-size:.72rem;color:rgba(255,255,255,.5);white-space:nowrap">θ:</label>
|
||
<input type="range" min="0" max="160" value="20" step="5" style="width:72px;accent-color:var(--violet)" oninput="hydroSim&&hydroSim.setContactAngle(+this.value);document.getElementById('hydro-theta-val').textContent=this.value+'\u00B0';document.getElementById('hydro-theta-lbl').textContent=this.value+'\u00B0';document.querySelector('#hydro-panel-theta input[type=range]').value=this.value">
|
||
<span id="hydro-theta-val" style="font-size:.72rem;color:var(--violet);min-width:28px;white-space:nowrap">20°</span>
|
||
<button class="zoom-btn" id="hydro-surf-toggle" onclick="hydroToggleSurface()" title="Переключить: капилляры / капля" style="white-space:nowrap">Капилляры</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- radioactive controls -->
|
||
<div id="ctrl-radioactive" class="sim-zoom-btns" style="display:none">
|
||
<button class="zoom-btn" id="rd-ctrl-play" onclick="radioactivePlay()" title="Старт / Пауза">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><polygon points="5,3 19,12 5,21"/></svg>
|
||
</button>
|
||
<button class="zoom-btn" onclick="radioactiveReset()" title="Сброс">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>
|
||
</button>
|
||
</div>
|
||
|
||
<!-- theory toggle (all sims) -->
|
||
<button class="zoom-btn" id="theory-toggle" onclick="toggleTheory()" title="Теория и формулы" style="margin-left:auto">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M2 3h6a4 4 0 014 4v14a3 3 0 00-3-3H2z"/><path d="M22 3h-6a4 4 0 00-4 4v14a3 3 0 013-3h7z"/></svg>
|
||
</button>
|
||
|
||
<!-- sound toggle -->
|
||
<button class="zoom-btn" id="labfx-sound-btn" onclick="(function(){var e=window.LabFX&&window.LabFX.sound;if(!e)return;e.setEnabled(!e.isEnabled());document.getElementById('labfx-sound-btn').setAttribute('aria-pressed',e.isEnabled());document.getElementById('labfx-sound-icon-on').style.display=e.isEnabled()?'':'none';document.getElementById('labfx-sound-icon-off').style.display=e.isEnabled()?'none':'';})()" title="Звук симуляций" style="position:relative" aria-pressed="true">
|
||
<!-- speaker on -->
|
||
<svg id="labfx-sound-icon-on" class="ic" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"/>
|
||
<path d="M15.54 8.46a5 5 0 0 1 0 7.07"/>
|
||
<path d="M19.07 4.93a10 10 0 0 1 0 14.14"/>
|
||
</svg>
|
||
<!-- speaker off (muted) -->
|
||
<svg id="labfx-sound-icon-off" class="ic" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="display:none">
|
||
<polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"/>
|
||
<line x1="23" y1="9" x2="17" y2="15"/>
|
||
<line x1="17" y1="9" x2="23" y2="15"/>
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
|
||
<!-- ── GRAPH sim body ── -->
|
||
<div id="sim-graph" class="sim-body-wrap">
|
||
|
||
<!-- left panel -->
|
||
<div class="graph-panel">
|
||
<div class="gp-section-title">Функции</div>
|
||
|
||
<!-- fn 1 -->
|
||
<div style="--fn-color:var(--violet)">
|
||
<div class="fn-row">
|
||
<div class="fn-dot"></div>
|
||
<span class="fn-label">y =</span>
|
||
<input class="fn-input" id="fn0" placeholder="sin(x)" autocomplete="off" spellcheck="false" oninput="updateFn(0)" />
|
||
</div>
|
||
<div class="fn-preview" id="fn0-prev"></div>
|
||
<div class="fn-err" id="fn0-err">Синтаксическая ошибка</div>
|
||
</div>
|
||
|
||
<!-- fn 2 -->
|
||
<div style="--fn-color:var(--cyan)">
|
||
<div class="fn-row">
|
||
<div class="fn-dot"></div>
|
||
<span class="fn-label">y =</span>
|
||
<input class="fn-input" id="fn1" placeholder="x^2 - 4" autocomplete="off" spellcheck="false" oninput="updateFn(1)" />
|
||
</div>
|
||
<div class="fn-preview" id="fn1-prev"></div>
|
||
<div class="fn-err" id="fn1-err">Синтаксическая ошибка</div>
|
||
</div>
|
||
|
||
<!-- fn 3 -->
|
||
<div style="--fn-color:var(--pink)">
|
||
<div class="fn-row">
|
||
<div class="fn-dot"></div>
|
||
<span class="fn-label">y =</span>
|
||
<input class="fn-input" id="fn2" placeholder="tg(x)" autocomplete="off" spellcheck="false" oninput="updateFn(2)" />
|
||
</div>
|
||
<div class="fn-preview" id="fn2-prev"></div>
|
||
<div class="fn-err" id="fn2-err">Синтаксическая ошибка</div>
|
||
</div>
|
||
|
||
<div style="margin-top:8px"></div>
|
||
<div class="gp-section-title">Примеры</div>
|
||
|
||
<div class="gp-preset-group">
|
||
<div class="gp-preset-label">Линейные / степенные</div>
|
||
<div class="presets-wrap">
|
||
<button class="preset-btn" onclick="applyPreset('2x-1')">2x−1</button>
|
||
<button class="preset-btn" onclick="applyPreset('x^2')">x²</button>
|
||
<button class="preset-btn" onclick="applyPreset('x^2-4')">x²−4</button>
|
||
<button class="preset-btn" onclick="applyPreset('x^3-3x')">x³−3x</button>
|
||
<button class="preset-btn" onclick="applyPreset('x^4-4x^2+3')">x⁴−4x²+3</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="gp-preset-group">
|
||
<div class="gp-preset-label">Тригонометрия</div>
|
||
<div class="presets-wrap">
|
||
<button class="preset-btn" onclick="applyPreset('sin(x)')">sin x</button>
|
||
<button class="preset-btn" onclick="applyPreset('cos(x)')">cos x</button>
|
||
<button class="preset-btn" onclick="applyPreset('tg(x)')">tg x</button>
|
||
<button class="preset-btn" onclick="applyPreset('sin(2x)')">sin 2x</button>
|
||
<button class="preset-btn" onclick="applyPreset('x*sin(x)')">x·sin x</button>
|
||
<button class="preset-btn" onclick="applyPreset('sin(x)/x')">sin(x)/x</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="gp-preset-group">
|
||
<div class="gp-preset-label">Показательные / логарифмы</div>
|
||
<div class="presets-wrap">
|
||
<button class="preset-btn" onclick="applyPreset('exp(x)')">eˣ</button>
|
||
<button class="preset-btn" onclick="applyPreset('2^x')">2ˣ</button>
|
||
<button class="preset-btn" onclick="applyPreset('ln(x)')">ln x</button>
|
||
<button class="preset-btn" onclick="applyPreset('log(x)')">log x</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="gp-preset-group">
|
||
<div class="gp-preset-label">Прочие</div>
|
||
<div class="presets-wrap">
|
||
<button class="preset-btn" onclick="applyPreset('sqrt(x)')">√x</button>
|
||
<button class="preset-btn" onclick="applyPreset('1/x')">1/x</button>
|
||
<button class="preset-btn" onclick="applyPreset('abs(x)')">|x|</button>
|
||
<button class="preset-btn" onclick="applyPreset('floor(x)')">⌊x⌋</button>
|
||
<button class="preset-btn" onclick="applyPreset('1/(1+exp(-x))')">σ(x)</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="margin-top:auto;padding-top:14px"></div>
|
||
<button class="gp-btn" onclick="clearAll()">
|
||
<svg viewBox="0 0 24 24" fill="none"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14H6L5 6"/><path d="M10 11v6"/><path d="M14 11v6"/><path d="M9 6V4h6v2"/></svg>
|
||
Очистить всё
|
||
</button>
|
||
</div>
|
||
|
||
<!-- canvas area -->
|
||
<div class="graph-canvas-outer">
|
||
<div class="graph-canvas-wrap">
|
||
<canvas id="graph-canvas"></canvas>
|
||
</div>
|
||
<div class="graph-info-bar" id="graph-info-bar">
|
||
<div class="info-coord">
|
||
<span class="ic-label">x =</span>
|
||
<span class="ic-val" id="info-x">—</span>
|
||
</div>
|
||
<div class="info-fn-val">
|
||
<div class="info-fn-dot" style="background:var(--violet);box-shadow:0 0 5px var(--violet)"></div>
|
||
<span class="ic-label">y₁ =</span>
|
||
<span class="ic-val" id="info-y0">—</span>
|
||
</div>
|
||
<div class="info-fn-val">
|
||
<div class="info-fn-dot" style="background:var(--cyan);box-shadow:0 0 5px var(--cyan)"></div>
|
||
<span class="ic-label">y₂ =</span>
|
||
<span class="ic-val" id="info-y1">—</span>
|
||
</div>
|
||
<div class="info-fn-val">
|
||
<div class="info-fn-dot" style="background:var(--pink);box-shadow:0 0 5px var(--pink)"></div>
|
||
<span class="ic-label">y₃ =</span>
|
||
<span class="ic-val" id="info-y2">—</span>
|
||
</div>
|
||
<div class="info-hint">Скролл — зум · Перетащи — панорама</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div><!-- /#sim-graph -->
|
||
|
||
<!-- ══ ЭЛЕКТРОМАГНИТНЫЕ ПОЛЯ (EMField) ══
|
||
replaces sim-mag + sim-coulomb -->
|
||
<div id="sim-emfield" class="sim-proj-wrap" style="display:none">
|
||
<div class="sim-body-wrap">
|
||
|
||
<div class="proj-panel" style="width:258px;gap:0">
|
||
|
||
<!-- Mode tabs -->
|
||
<div style="display:flex;gap:4px;margin-bottom:12px">
|
||
<button id="em-tab-E" class="mag-mode-btn active" onclick="emSwitchMode('E')" style="flex:1;font-size:.72rem">Электрическое</button>
|
||
<button id="em-tab-B" class="mag-mode-btn" onclick="emSwitchMode('B')" style="flex:1;font-size:.72rem">Магнитное</button>
|
||
<button id="em-tab-combined" class="mag-mode-btn" onclick="emSwitchMode('combined')" style="flex:1;font-size:.72rem">Комбо</button>
|
||
</div>
|
||
|
||
<!-- E controls -->
|
||
<div id="em-ctrl-E">
|
||
<div class="gp-section-title" style="margin-bottom:6px">Заряд</div>
|
||
<div style="display:flex;gap:6px;margin-bottom:10px">
|
||
<button class="mag-mode-btn active" id="em-sign-pos" onclick="emSign(1)" style="flex:1">
|
||
<span style="font-size:1.2rem;font-weight:900;color:#EF476F">+</span> Полож.
|
||
</button>
|
||
<button class="mag-mode-btn" id="em-sign-neg" onclick="emSign(-1)" style="flex:1">
|
||
<span style="font-size:1.2rem;font-weight:900;color:#4CC9F0">−</span> Отриц.
|
||
</button>
|
||
</div>
|
||
|
||
<div class="gp-section-title" style="margin-bottom:6px">Слои E</div>
|
||
<div style="display:flex;flex-direction:column;gap:5px;margin-bottom:10px">
|
||
<label class="tri-layer-row active" onclick="emLayer('E','colormap',this)">
|
||
<span class="tri-dot" style="background:linear-gradient(90deg,#EF476F,#9B5DE5,#4CC9F0)"></span>
|
||
<span class="tri-layer-name">Карта потенциала</span>
|
||
<span class="tri-layer-hint" style="color:rgba(255,255,255,.4)">V</span>
|
||
<span class="tri-toggle" style="background:var(--violet)"><span style="display:block;width:12px;height:12px;border-radius:50%;background:#fff;margin:2px;margin-left:14px"></span></span>
|
||
</label>
|
||
<label class="tri-layer-row active" onclick="emLayer('E','fieldlines',this)">
|
||
<span class="tri-dot" style="background:rgba(255,255,255,0.8)"></span>
|
||
<span class="tri-layer-name">Линии поля E</span>
|
||
<span class="tri-layer-hint" style="color:rgba(255,255,255,.4)">E</span>
|
||
<span class="tri-toggle" style="background:var(--violet)"><span style="display:block;width:12px;height:12px;border-radius:50%;background:#fff;margin:2px;margin-left:14px"></span></span>
|
||
</label>
|
||
<label class="tri-layer-row" onclick="emLayer('E','vectors',this)">
|
||
<span class="tri-dot" style="background:rgba(255,255,255,0.4)"></span>
|
||
<span class="tri-layer-name">Векторы E</span>
|
||
<span class="tri-toggle"><span style="display:block;width:12px;height:12px;border-radius:50%;background:#fff;margin:2px;margin-left:2px"></span></span>
|
||
</label>
|
||
<label class="tri-layer-row active" onclick="emLayer('E','equipotentials',this)">
|
||
<span class="tri-dot" style="background:rgba(255,255,255,0.5)"></span>
|
||
<span class="tri-layer-name">Эквипотенциали</span>
|
||
<span class="tri-layer-hint" style="color:rgba(255,255,255,.3)">V=const</span>
|
||
<span class="tri-toggle" style="background:var(--violet)"><span style="display:block;width:12px;height:12px;border-radius:50%;background:#fff;margin:2px;margin-left:14px"></span></span>
|
||
</label>
|
||
<label class="tri-layer-row" onclick="emLayer('E','forces',this)">
|
||
<span class="tri-dot" style="background:#FFD166;box-shadow:0 0 5px #FFD166"></span>
|
||
<span class="tri-layer-name">Силы Кулона</span>
|
||
<span class="tri-layer-hint" style="color:#FFD166">F</span>
|
||
<span class="tri-toggle"><span style="display:block;width:12px;height:12px;border-radius:50%;background:#fff;margin:2px;margin-left:2px"></span></span>
|
||
</label>
|
||
</div>
|
||
|
||
<div class="gp-section-title" style="margin-bottom:6px">Поверхность Гаусса</div>
|
||
<label class="tri-layer-row" id="em-gauss-row" onclick="emGaussToggle(this)" style="margin-bottom:6px">
|
||
<span class="tri-dot" style="background:#34d399;box-shadow:0 0 5px #34d399"></span>
|
||
<span class="tri-layer-name">Поток Гаусса Φₐ</span>
|
||
<span class="tri-layer-hint" style="color:#34d399">Φ=q/ε₀</span>
|
||
<span class="tri-toggle"><span style="display:block;width:12px;height:12px;border-radius:50%;background:#fff;margin:2px;margin-left:2px"></span></span>
|
||
</label>
|
||
<div class="param-block" id="em-gauss-r-block" style="display:none;margin-bottom:10px">
|
||
<div class="param-header">
|
||
<span class="param-name">Радиус поверхности</span>
|
||
<span class="param-val" id="em-gaussR-val">70 пкс</span>
|
||
</div>
|
||
<input type="range" class="param-slider" id="sl-emGaussR" min="20" max="200" value="70" oninput="emGaussRChange()">
|
||
</div>
|
||
|
||
<div class="gp-section-title" style="margin-bottom:6px">Пресеты E</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:5px;margin-bottom:10px">
|
||
<button class="proj-preset-chip" onclick="emPresetE('dipole')">Диполь ±</button>
|
||
<button class="proj-preset-chip" onclick="emPresetE('equal')">Два + заряда</button>
|
||
<button class="proj-preset-chip" onclick="emPresetE('quadrupole')">Квадруполь</button>
|
||
<button class="proj-preset-chip" onclick="emPresetE('ring')">Кольцо</button>
|
||
</div>
|
||
</div><!-- /#em-ctrl-E -->
|
||
|
||
<!-- B controls -->
|
||
<div id="em-ctrl-B" style="display:none">
|
||
<div class="gp-section-title" style="margin-bottom:6px">Провод</div>
|
||
<div style="display:flex;gap:6px;margin-bottom:10px">
|
||
<button class="mag-mode-btn active" id="em-dir-out" onclick="emWireDir('out')" style="flex:1">
|
||
<span style="font-size:1.2rem;font-weight:900;color:#06D6E0">•</span> Ток на нас
|
||
</button>
|
||
<button class="mag-mode-btn" id="em-dir-in" onclick="emWireDir('in')" style="flex:1">
|
||
<span style="font-size:1.1rem;font-weight:900;color:#F15BB5">×</span> Ток от нас
|
||
</button>
|
||
</div>
|
||
|
||
<div class="param-block" style="margin-bottom:10px">
|
||
<div class="param-header">
|
||
<span class="param-name">Сила тока I</span>
|
||
<span class="param-val" id="em-curI-val">6 А</span>
|
||
</div>
|
||
<input type="range" class="param-slider" id="sl-emI" min="1" max="20" value="6" oninput="emCurrentChange()">
|
||
</div>
|
||
|
||
<div class="gp-section-title" style="margin-bottom:6px">Слои B</div>
|
||
<div style="display:flex;flex-direction:column;gap:5px;margin-bottom:10px">
|
||
<label class="tri-layer-row active" onclick="emLayer('B','colormap',this)">
|
||
<span class="tri-dot" style="background:linear-gradient(90deg,#9B5DE5,#06D6E0,#F15BB5)"></span>
|
||
<span class="tri-layer-name">Карта поля B</span>
|
||
<span class="tri-layer-hint" style="color:rgba(255,255,255,.4)">hue=угол</span>
|
||
<span class="tri-toggle" style="background:var(--violet)"><span style="display:block;width:12px;height:12px;border-radius:50%;background:#fff;margin:2px;margin-left:14px"></span></span>
|
||
</label>
|
||
<label class="tri-layer-row active" onclick="emLayer('B','fieldlines',this)">
|
||
<span class="tri-dot" style="background:var(--cyan);box-shadow:0 0 5px var(--cyan)"></span>
|
||
<span class="tri-layer-name">Силовые линии B</span>
|
||
<span class="tri-layer-hint" style="color:rgba(255,255,255,.4)">+ стрелки</span>
|
||
<span class="tri-toggle" style="background:var(--violet)"><span style="display:block;width:12px;height:12px;border-radius:50%;background:#fff;margin:2px;margin-left:14px"></span></span>
|
||
</label>
|
||
<label class="tri-layer-row" onclick="emLayer('B','vectors',this)">
|
||
<span class="tri-dot" style="background:var(--violet);box-shadow:0 0 5px var(--violet)"></span>
|
||
<span class="tri-layer-name">Векторное поле B</span>
|
||
<span class="tri-toggle"><span style="display:block;width:12px;height:12px;border-radius:50%;background:#fff;margin:2px;margin-left:2px"></span></span>
|
||
</label>
|
||
</div>
|
||
|
||
<div class="gp-section-title" style="margin-bottom:6px">Проводник в поле</div>
|
||
<label class="tri-layer-row" id="em-cond-row" onclick="emCondToggle(this)" style="margin-bottom:6px">
|
||
<span class="tri-dot" style="background:#fbbf24;box-shadow:0 0 5px #fbbf24"></span>
|
||
<span class="tri-layer-name">Проводник (Ампер)</span>
|
||
<span class="tri-layer-hint" style="color:#fbbf24">F=IL×B</span>
|
||
<span class="tri-toggle"></span>
|
||
</label>
|
||
<div class="param-block" id="em-cond-I-block" style="display:none;margin-bottom:10px">
|
||
<div class="param-header">
|
||
<span class="param-name">Ток проводника I*</span>
|
||
<span class="param-val" id="em-condI-val">8 А</span>
|
||
</div>
|
||
<input type="range" class="param-slider" id="sl-emCondI" min="1" max="20" value="8" oninput="emCondCurrentChange()">
|
||
</div>
|
||
|
||
<div class="gp-section-title" style="margin-bottom:6px">Магнитный поток</div>
|
||
<label class="tri-layer-row" id="em-flux-row" onclick="emFluxToggle(this)" style="margin-bottom:10px">
|
||
<span class="tri-dot" style="background:#34d399;box-shadow:0 0 5px #34d399"></span>
|
||
<span class="tri-layer-name">Индикатор потока</span>
|
||
<span class="tri-layer-hint" style="color:#34d399">Φ=B·S</span>
|
||
<span class="tri-toggle"></span>
|
||
</label>
|
||
|
||
<div class="gp-section-title" style="margin-bottom:6px">ЭДС индукции</div>
|
||
<label class="tri-layer-row" id="em-rod-row" onclick="emRodToggle(this)" style="margin-bottom:6px">
|
||
<span class="tri-dot" style="background:#f59e0b;box-shadow:0 0 5px #f59e0b"></span>
|
||
<span class="tri-layer-name">Движущийся проводник</span>
|
||
<span class="tri-layer-hint" style="color:#f59e0b">ε=∫vBdl</span>
|
||
<span class="tri-toggle"><span style="display:block;width:12px;height:12px;border-radius:50%;background:#fff;margin:2px;margin-left:2px"></span></span>
|
||
</label>
|
||
|
||
<div class="gp-section-title" style="margin-bottom:6px">Пресеты B</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:5px;margin-bottom:10px">
|
||
<button class="proj-preset-chip" onclick="emPresetB('single')">Один провод</button>
|
||
<button class="proj-preset-chip" onclick="emPresetB('parallel')">Параллельные</button>
|
||
<button class="proj-preset-chip" onclick="emPresetB('anti')">Антипарал.</button>
|
||
<button class="proj-preset-chip" onclick="emPresetB('solenoid')">Соленоид</button>
|
||
<button class="proj-preset-chip" onclick="emPresetB('quadrupole')">Квадруполь</button>
|
||
<button class="proj-preset-chip" onclick="emPresetB('ring')">Кольцо</button>
|
||
<button class="proj-preset-chip" onclick="emPresetB('toroid')">Тороид</button>
|
||
</div>
|
||
</div><!-- /#em-ctrl-B -->
|
||
|
||
<!-- combined extra -->
|
||
<div id="em-ctrl-combined" style="display:none">
|
||
<div class="gp-section-title" style="margin-bottom:6px">Тип добавляемого</div>
|
||
<div style="display:flex;gap:6px;margin-bottom:10px">
|
||
<button class="mag-mode-btn active" id="em-add-charge" onclick="emAddTypeSwitch('charge')" style="flex:1;font-size:.72rem">Заряд</button>
|
||
<button class="mag-mode-btn" id="em-add-wire" onclick="emAddTypeSwitch('wire')" style="flex:1;font-size:.72rem">Провод</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Particle -->
|
||
<div class="gp-section-title" style="margin-bottom:6px">Частица</div>
|
||
<label class="tri-layer-row" id="em-particle-row" onclick="emParticle(this)" style="margin-bottom:10px">
|
||
<span class="tri-dot" style="background:#ffff50;box-shadow:0 0 5px #ffff50"></span>
|
||
<span class="tri-layer-name">Заряженная частица</span>
|
||
<span class="tri-layer-hint" style="color:#ffff50">Лоренц</span>
|
||
<span class="tri-toggle"></span>
|
||
</label>
|
||
|
||
<div style="margin-top:auto;padding-top:6px;display:flex;flex-direction:column;gap:5px">
|
||
<div class="tri-stats-grid" style="grid-template-columns:auto 1fr">
|
||
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">Зарядов</div>
|
||
<div class="tri-stat-v" id="embar-charges" style="color:#EF476F">0</div>
|
||
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">Проводов</div>
|
||
<div class="tri-stat-v" id="embar-wires" style="color:var(--cyan)">0</div>
|
||
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">Курсор |E|</div>
|
||
<div class="tri-stat-v" id="embar-curE" style="color:rgba(255,255,255,0.6)">—</div>
|
||
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">Курсор V</div>
|
||
<div class="tri-stat-v" id="embar-curV" style="color:rgba(255,255,255,0.5)">—</div>
|
||
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">Курсор |B|</div>
|
||
<div class="tri-stat-v" id="embar-curB" style="color:var(--cyan)">—</div>
|
||
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">Φₐ Гаусса</div>
|
||
<div class="tri-stat-v" id="embar-gauss" style="color:#34d399">—</div>
|
||
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">ЭДС ε</div>
|
||
<div class="tri-stat-v" id="embar-rod" style="color:#f59e0b">—</div>
|
||
</div>
|
||
<div style="font-size:0.68rem;color:var(--text-3);text-align:center;line-height:1.6;margin-top:4px">
|
||
Клик — добавить · ПКМ / 2×клик — удалить<br>
|
||
Перетащи источник для перемещения
|
||
</div>
|
||
</div>
|
||
|
||
</div><!-- /.proj-panel -->
|
||
|
||
<div class="proj-canvas-outer">
|
||
<canvas id="emfield-canvas" style="display:block;position:absolute;top:0;left:0;width:100%;height:100%;cursor:crosshair"></canvas>
|
||
</div>
|
||
|
||
</div><!-- /.sim-body-wrap -->
|
||
|
||
<div class="proj-stats-bar">
|
||
<div class="pstat"><div class="pstat-label">Зарядов</div><div class="pstat-val" id="embar-charges-bar" style="color:#EF476F">0</div></div>
|
||
<div class="pstat"><div class="pstat-label">Проводов</div><div class="pstat-val" id="embar-wires-bar" style="color:var(--cyan)">0</div></div>
|
||
<div class="pstat"><div class="pstat-label">Частица</div><div class="pstat-val" id="embar-particle">выкл</div></div>
|
||
<div class="pstat"><div class="pstat-label">|E| курсора</div><div class="pstat-val" id="embar-curE-bar" style="color:#EF476F">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">|B| курсора</div><div class="pstat-val" id="embar-curB-bar" style="color:var(--cyan)">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Сила Ампера</div><div class="pstat-val" id="embar-ampere" style="color:#fbbf24">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Поток Φ</div><div class="pstat-val" id="embar-flux" style="color:#34d399">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Φₐ Гаусса</div><div class="pstat-val" id="embar-gauss-bar" style="color:#34d399">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">ЭДС ε</div><div class="pstat-val" id="embar-rod-bar" style="color:#f59e0b">—</div></div>
|
||
</div>
|
||
</div><!-- /#sim-emfield -->
|
||
|
||
<!-- ── TRIANGLE sim body ── -->
|
||
<div id="sim-tri" class="sim-proj-wrap" style="display:none">
|
||
<div class="sim-body-wrap">
|
||
|
||
<!-- left panel -->
|
||
<div class="proj-panel" style="width:240px;gap:0">
|
||
|
||
<!-- Layer toggles -->
|
||
<div class="gp-section-title" style="margin-bottom:10px">Слои</div>
|
||
<div style="display:flex;flex-direction:column;gap:5px;margin-bottom:10px">
|
||
<label class="tri-layer-row" onclick="triToggle('medians',this)">
|
||
<span class="tri-dot" style="background:#22d55e;box-shadow:0 0 5px #22d55e"></span>
|
||
<span class="tri-layer-name">Медианы</span>
|
||
<span class="tri-layer-hint" style="color:#22d55e">G — центроид</span>
|
||
<span class="tri-toggle" id="tl-medians"></span>
|
||
</label>
|
||
<label class="tri-layer-row" onclick="triToggle('altitudes',this)">
|
||
<span class="tri-dot" style="background:#f59e0b;box-shadow:0 0 5px #f59e0b"></span>
|
||
<span class="tri-layer-name">Высоты</span>
|
||
<span class="tri-layer-hint" style="color:#f59e0b">H — ортоцентр</span>
|
||
<span class="tri-toggle" id="tl-altitudes"></span>
|
||
</label>
|
||
<label class="tri-layer-row" onclick="triToggle('bisectors',this)">
|
||
<span class="tri-dot" style="background:#ec4899;box-shadow:0 0 5px #ec4899"></span>
|
||
<span class="tri-layer-name">Биссектрисы</span>
|
||
<span class="tri-layer-hint" style="color:#ec4899">I — инцентр</span>
|
||
<span class="tri-toggle" id="tl-bisectors"></span>
|
||
</label>
|
||
<label class="tri-layer-row" onclick="triToggle('circumcircle',this)">
|
||
<span class="tri-dot" style="background:var(--pink);box-shadow:0 0 5px var(--pink)"></span>
|
||
<span class="tri-layer-name">Описанная окружность</span>
|
||
<span class="tri-layer-hint" style="color:var(--pink)">O, R</span>
|
||
<span class="tri-toggle" id="tl-circumcircle"></span>
|
||
</label>
|
||
<label class="tri-layer-row" onclick="triToggle('incircle',this)">
|
||
<span class="tri-dot" style="background:var(--cyan);box-shadow:0 0 5px var(--cyan)"></span>
|
||
<span class="tri-layer-name">Вписанная окружность</span>
|
||
<span class="tri-layer-hint" style="color:var(--cyan)">I, r</span>
|
||
<span class="tri-toggle" id="tl-incircle"></span>
|
||
</label>
|
||
<label class="tri-layer-row" onclick="triToggle('eulerLine',this)">
|
||
<span class="tri-dot" style="background:rgba(255,255,100,0.8);box-shadow:0 0 5px yellow"></span>
|
||
<span class="tri-layer-name">Прямая Эйлера</span>
|
||
<span class="tri-layer-hint" style="color:rgba(255,255,100,0.7)">O<svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>G<svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>H</span>
|
||
<span class="tri-toggle" id="tl-eulerLine"></span>
|
||
</label>
|
||
</div>
|
||
|
||
<div class="gp-section-title" style="margin-bottom:10px">Теоремы</div>
|
||
<div style="display:flex;flex-direction:column;gap:5px;margin-bottom:10px">
|
||
<label class="tri-layer-row" onclick="triToggle('sineLaw',this)">
|
||
<span class="tri-dot" style="background:#60a5fa;box-shadow:0 0 5px #60a5fa"></span>
|
||
<span class="tri-layer-name">Теорема синусов</span>
|
||
<span class="tri-layer-hint" style="color:#60a5fa">a/sinA = 2R</span>
|
||
<span class="tri-toggle" id="tl-sineLaw"></span>
|
||
</label>
|
||
<label class="tri-layer-row" onclick="triToggle('cosineLaw',this)">
|
||
<span class="tri-dot" style="background:#fbbf24;box-shadow:0 0 5px #fbbf24"></span>
|
||
<span class="tri-layer-name">Теорема косинусов</span>
|
||
<span class="tri-layer-hint" style="color:#fbbf24">c²=a²+b²−2ab·cosC</span>
|
||
<span class="tri-toggle" id="tl-cosineLaw"></span>
|
||
</label>
|
||
<label class="tri-layer-row" onclick="triToggle('pythagorean',this)">
|
||
<span class="tri-dot" style="background:#EF476F;box-shadow:0 0 5px #EF476F"></span>
|
||
<span class="tri-layer-name">Теорема Пифагора</span>
|
||
<span class="tri-layer-hint" style="color:#EF476F">a²+b² = c²</span>
|
||
<span class="tri-toggle" id="tl-pythagorean"></span>
|
||
</label>
|
||
</div>
|
||
|
||
<!-- Stats -->
|
||
<div class="gp-section-title" style="margin-bottom:8px">Стороны</div>
|
||
<div class="tri-stats-grid" style="margin-bottom:10px">
|
||
<span class="tri-stat-k" style="color:var(--violet)">a</span><span class="tri-stat-v" id="ts-a">—</span>
|
||
<span class="tri-stat-k" style="color:var(--cyan)">b</span><span class="tri-stat-v" id="ts-b">—</span>
|
||
<span class="tri-stat-k" style="color:var(--pink)">c</span><span class="tri-stat-v" id="ts-c">—</span>
|
||
</div>
|
||
|
||
<div class="gp-section-title" style="margin-bottom:8px">Углы</div>
|
||
<div class="tri-stats-grid" style="margin-bottom:10px">
|
||
<span class="tri-stat-k" style="color:var(--violet)">∠A</span><span class="tri-stat-v" id="ts-A">—</span>
|
||
<span class="tri-stat-k" style="color:var(--cyan)">∠B</span><span class="tri-stat-v" id="ts-B">—</span>
|
||
<span class="tri-stat-k" style="color:var(--pink)">∠C</span><span class="tri-stat-v" id="ts-C">—</span>
|
||
</div>
|
||
|
||
<div class="gp-section-title" style="margin-bottom:8px">Вычисляемые</div>
|
||
<div class="tri-stats-grid" style="margin-bottom:10px">
|
||
<span class="tri-stat-k">S</span><span class="tri-stat-v" id="ts-S">—</span>
|
||
<span class="tri-stat-k">P</span><span class="tri-stat-v" id="ts-P">—</span>
|
||
<span class="tri-stat-k">R</span><span class="tri-stat-v" id="ts-R">—</span>
|
||
<span class="tri-stat-k">r</span><span class="tri-stat-v" id="ts-r">—</span>
|
||
</div>
|
||
|
||
<!-- Type badge -->
|
||
<div style="margin-top:auto;padding-top:10px">
|
||
<div style="font-size:0.62rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3);margin-bottom:6px">Тип</div>
|
||
<div id="ts-type" style="
|
||
padding:8px 14px;border-radius:12px;
|
||
background:rgba(155,93,229,0.12);border:1.5px solid rgba(155,93,229,0.25);
|
||
font-family:'Manrope',sans-serif;font-size:0.82rem;font-weight:700;
|
||
color:var(--violet);text-align:center;
|
||
">—</div>
|
||
<div style="margin-top:8px;font-size:0.7rem;color:var(--text-3);text-align:center;line-height:1.5">
|
||
Перетащи вершины<br>A, B, C для изменения
|
||
</div>
|
||
</div>
|
||
|
||
</div><!-- /.proj-panel -->
|
||
|
||
<!-- canvas -->
|
||
<div class="proj-canvas-outer">
|
||
<canvas id="tri-canvas"></canvas>
|
||
</div>
|
||
|
||
</div><!-- /.sim-body-wrap -->
|
||
|
||
<!-- stats bar -->
|
||
<div class="proj-stats-bar">
|
||
<div class="pstat">
|
||
<div class="pstat-label">Сторона a</div>
|
||
<div class="pstat-val" id="tbar-a">—</div>
|
||
</div>
|
||
<div class="pstat">
|
||
<div class="pstat-label">Сторона b</div>
|
||
<div class="pstat-val" id="tbar-b">—</div>
|
||
</div>
|
||
<div class="pstat">
|
||
<div class="pstat-label">Сторона c</div>
|
||
<div class="pstat-val" id="tbar-c">—</div>
|
||
</div>
|
||
<div class="pstat">
|
||
<div class="pstat-label">Площадь S</div>
|
||
<div class="pstat-val" id="tbar-S">—</div>
|
||
</div>
|
||
<div class="pstat">
|
||
<div class="pstat-label">Периметр P</div>
|
||
<div class="pstat-val" id="tbar-P">—</div>
|
||
</div>
|
||
<div class="pstat">
|
||
<div class="pstat-label">R / r</div>
|
||
<div class="pstat-val" id="tbar-Rr">—</div>
|
||
</div>
|
||
</div>
|
||
</div><!-- /#sim-tri -->
|
||
|
||
<!-- ══════════════════════════════════════════════
|
||
ТРИГОНОМЕТРИЧЕСКАЯ ОКРУЖНОСТЬ
|
||
══════════════════════════════════════════════ -->
|
||
<div id="sim-trigcircle" class="sim-proj-wrap" style="display:none">
|
||
<div class="sim-body-wrap">
|
||
|
||
<!-- left panel -->
|
||
<div class="proj-panel" style="width:240px;gap:0">
|
||
|
||
<!-- Function toggles -->
|
||
<div class="gp-section-title" style="margin-bottom:10px">Отрезки</div>
|
||
<div style="display:flex;flex-direction:column;gap:5px;margin-bottom:14px">
|
||
<label class="tri-layer-row active" onclick="trigToggle('sin',this)">
|
||
<span class="tri-dot" style="background:#EF476F;box-shadow:0 0 5px #EF476F"></span>
|
||
<span class="tri-layer-name">sin</span>
|
||
<span class="tri-layer-hint" style="color:#EF476F">вертикаль</span>
|
||
<span class="tri-toggle" id="trig-tl-sin"></span>
|
||
</label>
|
||
<label class="tri-layer-row active" onclick="trigToggle('cos',this)">
|
||
<span class="tri-dot" style="background:var(--cyan);box-shadow:0 0 5px var(--cyan)"></span>
|
||
<span class="tri-layer-name">cos</span>
|
||
<span class="tri-layer-hint" style="color:var(--cyan)">горизонталь</span>
|
||
<span class="tri-toggle" id="trig-tl-cos"></span>
|
||
</label>
|
||
<label class="tri-layer-row" onclick="trigToggle('tan',this)">
|
||
<span class="tri-dot" style="background:#FFD166;box-shadow:0 0 5px #FFD166"></span>
|
||
<span class="tri-layer-name">tg</span>
|
||
<span class="tri-layer-hint" style="color:#FFD166">касательная</span>
|
||
<span class="tri-toggle" id="trig-tl-tan"></span>
|
||
</label>
|
||
<label class="tri-layer-row" onclick="trigToggle('cot',this)">
|
||
<span class="tri-dot" style="background:#7BF5A4;box-shadow:0 0 5px #7BF5A4"></span>
|
||
<span class="tri-layer-name">ctg</span>
|
||
<span class="tri-layer-hint" style="color:#7BF5A4">кокасательная</span>
|
||
<span class="tri-toggle" id="trig-tl-cot"></span>
|
||
</label>
|
||
</div>
|
||
|
||
<!-- Graph function selector -->
|
||
<div class="gp-section-title" style="margin-bottom:8px">График</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:5px;margin-bottom:14px">
|
||
<button class="trig-fn-btn active" onclick="trigSetGraphFn('sin',this)" style="--fc:#EF476F">sin</button>
|
||
<button class="trig-fn-btn" onclick="trigSetGraphFn('cos',this)" style="--fc:#06D6E0">cos</button>
|
||
<button class="trig-fn-btn" onclick="trigSetGraphFn('tan',this)" style="--fc:#FFD166">tg</button>
|
||
<button class="trig-fn-btn" onclick="trigSetGraphFn('cot',this)" style="--fc:#7BF5A4">ctg</button>
|
||
</div>
|
||
|
||
<!-- Values display -->
|
||
<div class="gp-section-title" style="margin-bottom:8px">Значения</div>
|
||
<div class="tri-stats-grid" style="margin-bottom:14px">
|
||
<span class="tri-stat-k" style="color:#EF476F">sin</span><span class="tri-stat-v" id="trig-v-sin">—</span>
|
||
<span class="tri-stat-k" style="color:#06D6E0">cos</span><span class="tri-stat-v" id="trig-v-cos">—</span>
|
||
<span class="tri-stat-k" style="color:#FFD166">tg</span><span class="tri-stat-v" id="trig-v-tan">—</span>
|
||
<span class="tri-stat-k" style="color:#7BF5A4">ctg</span><span class="tri-stat-v" id="trig-v-cot">—</span>
|
||
</div>
|
||
|
||
<!-- Notable angles -->
|
||
<div class="gp-section-title" style="margin-bottom:8px">Табличные углы</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:14px">
|
||
<button class="preset-btn" onclick="trigGoTo(0)">0°</button>
|
||
<button class="preset-btn" onclick="trigGoTo(Math.PI/6)">30°</button>
|
||
<button class="preset-btn" onclick="trigGoTo(Math.PI/4)">45°</button>
|
||
<button class="preset-btn" onclick="trigGoTo(Math.PI/3)">60°</button>
|
||
<button class="preset-btn" onclick="trigGoTo(Math.PI/2)">90°</button>
|
||
<button class="preset-btn" onclick="trigGoTo(2*Math.PI/3)">120°</button>
|
||
<button class="preset-btn" onclick="trigGoTo(Math.PI)">180°</button>
|
||
<button class="preset-btn" onclick="trigGoTo(3*Math.PI/2)">270°</button>
|
||
</div>
|
||
|
||
<!-- Angle info -->
|
||
<div style="margin-top:auto;padding-top:10px">
|
||
<div style="font-size:0.62rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3);margin-bottom:6px">Угол</div>
|
||
<div id="trig-angle-badge" style="
|
||
padding:10px 14px;border-radius:12px;
|
||
background:rgba(155,93,229,0.12);border:1.5px solid rgba(155,93,229,0.25);
|
||
font-family:'Manrope',sans-serif;font-size:0.85rem;font-weight:700;
|
||
color:var(--violet);text-align:center;line-height:1.6;
|
||
">45° = π/4</div>
|
||
<div style="margin-top:8px;font-size:0.7rem;color:var(--text-3);text-align:center;line-height:1.5">
|
||
Перетащи точку по окружности<br>или выбери табличный угол
|
||
</div>
|
||
</div>
|
||
|
||
</div><!-- /.proj-panel -->
|
||
|
||
<!-- canvas -->
|
||
<div class="proj-canvas-outer">
|
||
<canvas id="trigcircle-canvas"></canvas>
|
||
</div>
|
||
|
||
</div><!-- /.sim-body-wrap -->
|
||
|
||
<!-- stats bar -->
|
||
<div class="proj-stats-bar">
|
||
<div class="pstat">
|
||
<div class="pstat-label">Угол</div>
|
||
<div class="pstat-val" id="trigbar-angle" style="color:var(--violet)">45°</div>
|
||
</div>
|
||
<div class="pstat">
|
||
<div class="pstat-label">sin</div>
|
||
<div class="pstat-val" id="trigbar-sin" style="color:#EF476F">—</div>
|
||
</div>
|
||
<div class="pstat">
|
||
<div class="pstat-label">cos</div>
|
||
<div class="pstat-val" id="trigbar-cos" style="color:#06D6E0">—</div>
|
||
</div>
|
||
<div class="pstat">
|
||
<div class="pstat-label">tg</div>
|
||
<div class="pstat-val" id="trigbar-tan" style="color:#FFD166">—</div>
|
||
</div>
|
||
<div class="pstat">
|
||
<div class="pstat-label">ctg</div>
|
||
<div class="pstat-val" id="trigbar-cot" style="color:#7BF5A4">—</div>
|
||
</div>
|
||
<div class="pstat">
|
||
<div class="pstat-label">Четверть</div>
|
||
<div class="pstat-val" id="trigbar-quad" style="color:var(--violet)">—</div>
|
||
</div>
|
||
</div>
|
||
</div><!-- /#sim-trigcircle -->
|
||
|
||
<!-- ══════════════════════════════════════════════
|
||
ИДЕАЛЬНЫЙ ГАЗ
|
||
══════════════════════════════════════════════ -->
|
||
<!-- ══════════════════════════════════════════════
|
||
МОЛЕКУЛЯРНАЯ ФИЗИКА (газ + броуновское + состояния + диффузия)
|
||
══════════════════════════════════════════════ -->
|
||
<div id="sim-molphys" class="sim-proj-wrap" style="display:none">
|
||
<div class="sim-body-wrap">
|
||
|
||
<div class="proj-panel" style="width:248px;gap:0">
|
||
|
||
<!-- Mode selector -->
|
||
<div style="display:flex;gap:3px;margin-bottom:12px;padding:3px;background:rgba(255,255,255,0.04);border-radius:10px;border:1px solid var(--border)">
|
||
<button class="mag-mode-btn mol-mode active" id="mol-mode-gas" onclick="molMode('gas',this)" style="flex:1;font-size:.63rem;padding:5px 2px">Газ</button>
|
||
<button class="mag-mode-btn mol-mode" id="mol-mode-brownian" onclick="molMode('brownian',this)" style="flex:1;font-size:.63rem;padding:5px 2px">Броуновское</button>
|
||
<button class="mag-mode-btn mol-mode" id="mol-mode-states" onclick="molMode('states',this)" style="flex:1;font-size:.63rem;padding:5px 2px">Фазы</button>
|
||
<button class="mag-mode-btn mol-mode" id="mol-mode-diffusion" onclick="molMode('diffusion',this)" style="flex:1;font-size:.63rem;padding:5px 2px">Диффузия</button>
|
||
</div>
|
||
|
||
<!-- ── Gas panel ── -->
|
||
<div id="mol-panel-gas">
|
||
<div class="gp-section-title" style="margin-bottom:8px">Параметры газа</div>
|
||
<div class="param-block">
|
||
<div class="param-header"><span class="param-name">Число молекул N</span><span class="param-val" id="g-N">80</span></div>
|
||
<input type="range" class="param-slider" id="sl-gN" min="20" max="200" value="80" oninput="gasNChange()">
|
||
</div>
|
||
<div class="param-block">
|
||
<div class="param-header"><span class="param-name">Температура T</span><span class="param-val" id="g-T">1.0 у.е.</span></div>
|
||
<input type="range" class="param-slider" id="sl-gT" min="2" max="30" value="10" oninput="gasTChange()">
|
||
</div>
|
||
<div class="param-block">
|
||
<div class="param-header"><span class="param-name">Поршень (объём)</span><span class="param-val" id="g-piston">100%</span></div>
|
||
<input type="range" class="param-slider" id="sl-gPiston" min="30" max="100" value="100" oninput="gasPistonChange()">
|
||
</div>
|
||
<div style="margin-bottom:10px">
|
||
<button class="proj-preset-chip" id="gas-vec-btn" onclick="gasToggleVectors(this)" style="width:100%">Векторы скоростей: Выкл</button>
|
||
</div>
|
||
<div class="gp-section-title" style="margin-top:4px;margin-bottom:8px">Состояние</div>
|
||
<div class="tri-stats-grid" style="grid-template-columns:1fr 1fr;margin-bottom:8px">
|
||
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">Давление P</div>
|
||
<div class="tri-stat-v" id="gstat-P" style="text-align:center;color:var(--violet)">—</div>
|
||
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">Объём V</div>
|
||
<div class="tri-stat-v" id="gstat-V" style="text-align:center;color:var(--cyan)">—</div>
|
||
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">PV</div>
|
||
<div class="tri-stat-v" id="gstat-PV" style="text-align:center;color:#34d399">—</div>
|
||
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">⟨v⟩ средн.</div>
|
||
<div class="tri-stat-v" id="gstat-v" style="text-align:center;color:#FFD166">—</div>
|
||
</div>
|
||
<div style="font-size:.65rem;color:var(--text-3);text-align:center;line-height:1.6;margin-top:auto">Стенки светятся по P · Поршень перетащи мышью</div>
|
||
</div>
|
||
|
||
<!-- ── Brownian panel ── -->
|
||
<div id="mol-panel-brownian" style="display:none">
|
||
<div class="gp-section-title" style="margin-bottom:8px">Параметры</div>
|
||
<div class="param-block">
|
||
<div class="param-header"><span class="param-name">Молекул газа N</span><span class="param-val" id="br-N">120</span></div>
|
||
<input type="range" class="param-slider" id="sl-brN" min="30" max="300" value="120" oninput="brownNChange()">
|
||
</div>
|
||
<div class="param-block">
|
||
<div class="param-header"><span class="param-name">Температура T</span><span class="param-val" id="br-T">1.0 у.е.</span></div>
|
||
<input type="range" class="param-slider" id="sl-brT" min="2" max="20" value="10" oninput="brownTChange()">
|
||
</div>
|
||
<div class="gp-section-title" style="margin-top:10px;margin-bottom:8px">Статистика частицы B</div>
|
||
<div class="tri-stats-grid" style="grid-template-columns:1fr 1fr;margin-bottom:8px">
|
||
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">|Δr| смещение</div>
|
||
<div class="tri-stat-v" id="brstat-dr" style="text-align:center;color:#FFD166">0</div>
|
||
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">MSD</div>
|
||
<div class="tri-stat-v" id="brstat-msd" style="text-align:center;color:var(--violet)">0</div>
|
||
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">Скорость v</div>
|
||
<div class="tri-stat-v" id="brstat-v" style="text-align:center;color:var(--cyan)">0</div>
|
||
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">Шагов</div>
|
||
<div class="tri-stat-v" id="brstat-steps" style="text-align:center;color:#34d399">0</div>
|
||
</div>
|
||
<div style="margin-bottom:10px">
|
||
<button class="proj-preset-chip" onclick="if(brownSim) brownSim.resetOrigin()" style="width:100%">Сбросить отсчёт (Origin)</button>
|
||
</div>
|
||
<div style="font-size:.65rem;color:var(--text-3);text-align:center;line-height:1.6;margin-top:auto">График MSD нарастает линейно — закон диффузии</div>
|
||
</div>
|
||
|
||
<!-- ── States panel ── -->
|
||
<div id="mol-panel-states" style="display:none">
|
||
<div class="gp-section-title" style="margin-bottom:8px">Управление</div>
|
||
<div class="param-block">
|
||
<div class="param-header"><span class="param-name">Температура T</span><span class="param-val" id="st-T">0.15</span></div>
|
||
<input type="range" class="param-slider" id="sl-stT" min="1" max="100" value="15" oninput="statesTChange()">
|
||
</div>
|
||
<div class="param-block">
|
||
<div class="param-header"><span class="param-name">Частиц N</span><span class="param-val" id="st-N">64</span></div>
|
||
<input type="range" class="param-slider" id="sl-stN" min="16" max="100" step="4" value="64" oninput="statesNChange()">
|
||
</div>
|
||
<div style="display:flex;gap:6px;margin-bottom:14px;flex-wrap:wrap">
|
||
<button class="proj-preset-chip" onclick="statesPreset(0.05)">Твёрдое</button>
|
||
<button class="proj-preset-chip" onclick="statesPreset(0.30)">Жидкость</button>
|
||
<button class="proj-preset-chip" onclick="statesPreset(0.75)">Газ</button>
|
||
</div>
|
||
<button id="states-vec-btn" class="proj-preset-chip" style="margin-bottom:10px;width:100%" onclick="statesToggleVectors(this)">Векторы скоростей: Выкл</button>
|
||
<div class="gp-section-title" style="margin-bottom:8px">Фаза и энергия</div>
|
||
<div class="tri-stats-grid" style="grid-template-columns:1fr 1fr;margin-bottom:8px">
|
||
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">Фаза</div>
|
||
<div class="tri-stat-v" id="ststat-phase" style="text-align:center">—</div>
|
||
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">Кин. энергия</div>
|
||
<div class="tri-stat-v" id="ststat-KE" style="text-align:center;color:#FFD166">—</div>
|
||
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">Пот. энергия</div>
|
||
<div class="tri-stat-v" id="ststat-PE" style="text-align:center;color:var(--violet)">—</div>
|
||
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">Давление</div>
|
||
<div class="tri-stat-v" id="ststat-P" style="text-align:center;color:#EF476F">—</div>
|
||
</div>
|
||
<div style="font-size:.65rem;color:var(--text-3);text-align:center;line-height:1.6;margin-top:auto">LJ потенциал · g(r) — структура · цвет = скорость</div>
|
||
</div>
|
||
|
||
<!-- ── Diffusion panel ── -->
|
||
<div id="mol-panel-diffusion" style="display:none">
|
||
<div class="gp-section-title" style="margin-bottom:8px">Параметры</div>
|
||
<div class="param-block">
|
||
<div class="param-header"><span class="param-name">Молекул каждого вида</span><span class="param-val" id="df-N">60</span></div>
|
||
<input type="range" class="param-slider" id="sl-dfN" min="20" max="120" value="60" oninput="diffNChange()">
|
||
</div>
|
||
<div class="param-block">
|
||
<div class="param-header"><span class="param-name">Температура T</span><span class="param-val" id="df-T">1.0 у.е.</span></div>
|
||
<input type="range" class="param-slider" id="sl-dfT" min="2" max="20" value="10" oninput="diffTChange()">
|
||
</div>
|
||
<label class="tri-layer-row active" id="df-part-row" onclick="diffPartitionToggle(this)" style="margin-bottom:6px">
|
||
<span class="tri-dot" style="background:rgba(255,255,255,0.5)"></span>
|
||
<span class="tri-layer-name">Перегородка</span>
|
||
<span class="tri-layer-hint" style="color:rgba(255,255,255,.4)">‖</span>
|
||
<span class="tri-toggle" id="df-part-toggle" style="background:var(--violet)"><span style="display:block;width:12px;height:12px;border-radius:50%;background:#fff;margin:2px;margin-left:14px"></span></span>
|
||
</label>
|
||
<label class="tri-layer-row" id="df-pore-row" onclick="diffPoreToggle(this)" style="margin-bottom:10px">
|
||
<span class="tri-dot" style="background:rgba(255,179,71,0.5)"></span>
|
||
<span class="tri-layer-name">Пора (щель)</span>
|
||
<span class="tri-layer-hint" style="color:rgba(255,255,255,.4)">⊙</span>
|
||
<span class="tri-toggle" id="df-pore-toggle" style="background:rgba(255,255,255,0.15)"><span style="display:block;width:12px;height:12px;border-radius:50%;background:#fff;margin:2px;margin-left:2px"></span></span>
|
||
</label>
|
||
<div class="gp-section-title" style="margin-bottom:8px">Концентрации</div>
|
||
<div class="tri-stats-grid" style="grid-template-columns:1fr 1fr;margin-bottom:8px">
|
||
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--cyan)">Лево A</div>
|
||
<div class="tri-stat-v" id="dfstat-LA" style="text-align:center;color:var(--cyan)">—</div>
|
||
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--pink)">Лево B</div>
|
||
<div class="tri-stat-v" id="dfstat-LB" style="text-align:center;color:var(--pink)">—</div>
|
||
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--cyan)">Право A</div>
|
||
<div class="tri-stat-v" id="dfstat-RA" style="text-align:center;color:var(--cyan)">—</div>
|
||
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--pink)">Право B</div>
|
||
<div class="tri-stat-v" id="dfstat-RB" style="text-align:center;color:var(--pink)">—</div>
|
||
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">Смешивание</div>
|
||
<div class="tri-stat-v" id="dfstat-mix" style="text-align:center;color:#34d399">—</div>
|
||
</div>
|
||
<div style="font-size:.65rem;color:var(--text-3);text-align:center;line-height:1.6;margin-top:auto">A (cyan) — лево · B (розовый) — право</div>
|
||
</div>
|
||
|
||
</div><!-- /.proj-panel -->
|
||
|
||
<div class="proj-canvas-outer">
|
||
<canvas id="gas-canvas" style="display:block;position:absolute;top:0;left:0;width:100%;height:100%"></canvas>
|
||
<canvas id="brownian-canvas" style="display:none;position:absolute;top:0;left:0;width:100%;height:100%"></canvas>
|
||
<canvas id="states-canvas" style="display:none;position:absolute;top:0;left:0;width:100%;height:100%"></canvas>
|
||
<canvas id="diffusion-canvas" style="display:none;position:absolute;top:0;left:0;width:100%;height:100%"></canvas>
|
||
</div>
|
||
|
||
</div><!-- /.sim-body-wrap -->
|
||
|
||
<div class="proj-stats-bar" id="mol-stats-bar">
|
||
<div class="pstat"><div class="pstat-label" id="mpbar-l1">—</div><div class="pstat-val" id="mpbar-v1" style="color:var(--cyan)">—</div></div>
|
||
<div class="pstat"><div class="pstat-label" id="mpbar-l2">—</div><div class="pstat-val" id="mpbar-v2" style="color:#FFD166">—</div></div>
|
||
<div class="pstat"><div class="pstat-label" id="mpbar-l3">—</div><div class="pstat-val" id="mpbar-v3" style="color:var(--violet)">—</div></div>
|
||
<div class="pstat"><div class="pstat-label" id="mpbar-l4">—</div><div class="pstat-val" id="mpbar-v4" style="color:#34d399">—</div></div>
|
||
<div class="pstat"><div class="pstat-label" id="mpbar-l5">—</div><div class="pstat-val" id="mpbar-v5">—</div></div>
|
||
</div>
|
||
</div><!-- /#sim-molphys -->
|
||
|
||
<!-- ══════════════════════════════════════════════
|
||
ЗАКОН КУЛОНА
|
||
══════════════════════════════════════════════ -->
|
||
<!-- sim-coulomb removed: merged into sim-emfield -->
|
||
|
||
<!-- ══════════════════════════════════════════════
|
||
ЭЛЕКТРИЧЕСКИЕ ЦЕПИ
|
||
══════════════════════════════════════════════ -->
|
||
<div id="sim-circuit" class="sim-proj-wrap" style="display:none">
|
||
<div class="sim-body-wrap">
|
||
|
||
<div class="proj-panel" style="width:240px;gap:0">
|
||
|
||
<div class="gp-section-title" style="margin-bottom:8px">Инструмент</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:5px;margin-bottom:10px">
|
||
<button class="proj-preset-chip circ-tool-btn active" id="ptool-wire" onclick="circTool('wire',this)" data-tool="wire">Провод</button>
|
||
<button class="proj-preset-chip circ-tool-btn" id="ptool-resistor" onclick="circTool('resistor',this)" data-tool="resistor">Резистор</button>
|
||
<button class="proj-preset-chip circ-tool-btn" id="ptool-battery" onclick="circTool('battery',this)" data-tool="battery">Батарея</button>
|
||
<button class="proj-preset-chip circ-tool-btn" id="ptool-capacitor" onclick="circTool('capacitor',this)" data-tool="capacitor">Конденсатор</button>
|
||
<button class="proj-preset-chip circ-tool-btn" id="ptool-inductor" onclick="circTool('inductor',this)" data-tool="inductor">Катушка L</button>
|
||
<button class="proj-preset-chip circ-tool-btn" id="ptool-diode" onclick="circTool('diode',this)" data-tool="diode">Диод</button>
|
||
<button class="proj-preset-chip circ-tool-btn" id="ptool-led" onclick="circTool('led',this)" data-tool="led">LED</button>
|
||
<button class="proj-preset-chip circ-tool-btn" id="ptool-ac" onclick="circTool('ac',this)" data-tool="ac">AC источник</button>
|
||
<button class="proj-preset-chip circ-tool-btn" id="ptool-switch" onclick="circTool('switch',this)" data-tool="switch">Выключатель</button>
|
||
<button class="proj-preset-chip circ-tool-btn" id="ptool-lamp" onclick="circTool('lamp',this)" data-tool="lamp">Лампа</button>
|
||
<button class="proj-preset-chip circ-tool-btn" id="ptool-ammeter" onclick="circTool('ammeter',this)" data-tool="ammeter">Амперметр</button>
|
||
<button class="proj-preset-chip circ-tool-btn" id="ptool-voltmeter" onclick="circTool('voltmeter',this)" data-tool="voltmeter">Вольтметр</button>
|
||
<button class="proj-preset-chip circ-tool-btn" id="ptool-erase" onclick="circTool('erase',this)" data-tool="erase">Ластик</button>
|
||
</div>
|
||
|
||
<div class="gp-section-title" style="margin-bottom:8px">Параметры</div>
|
||
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Сопротивление R</span>
|
||
<span class="param-val" id="circ-R-val">10 Ω</span>
|
||
</div>
|
||
<input type="range" class="param-slider" id="sl-circR" min="1" max="100" value="10" oninput="circRChange()">
|
||
</div>
|
||
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Напряжение U</span>
|
||
<span class="param-val" id="circ-U-val">9 В</span>
|
||
</div>
|
||
<input type="range" class="param-slider" id="sl-circU" min="1" max="24" value="9" oninput="circUChange()">
|
||
</div>
|
||
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Ёмкость C</span>
|
||
<span class="param-val" id="circ-C-val">100 µF</span>
|
||
</div>
|
||
<input type="range" class="param-slider" id="sl-circC" min="10" max="1000" value="100" step="10" oninput="circCChange()">
|
||
</div>
|
||
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Индуктивность L</span>
|
||
<span class="param-val" id="circ-L-val">10 мГн</span>
|
||
</div>
|
||
<input type="range" class="param-slider" id="sl-circL" min="1" max="1000" value="10" step="1" oninput="circLChange()">
|
||
</div>
|
||
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Частота AC</span>
|
||
<span class="param-val" id="circ-F-val">2 Гц</span>
|
||
</div>
|
||
<input type="range" class="param-slider" id="sl-circF" min="1" max="20" value="2" oninput="circFChange()">
|
||
</div>
|
||
|
||
<div class="gp-section-title" style="margin-bottom:8px;margin-top:4px">Пресеты</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:5px;margin-bottom:10px">
|
||
<button class="proj-preset-chip" onclick="circPreset('serial')">Последовательное</button>
|
||
<button class="proj-preset-chip" onclick="circPreset('parallel')">Параллельное</button>
|
||
<button class="proj-preset-chip" onclick="circPreset('lamp')">Лампа + выкл</button>
|
||
<button class="proj-preset-chip" onclick="circPreset('divider')">Делитель V</button>
|
||
<button class="proj-preset-chip" onclick="circPreset('bridge')">Мост Уитстона</button>
|
||
<button class="proj-preset-chip" onclick="circPreset('diode')">Диод</button>
|
||
<button class="proj-preset-chip" onclick="circPreset('led')">LED</button>
|
||
<button class="proj-preset-chip" onclick="circPreset('rc')">RC-цепь</button>
|
||
<button class="proj-preset-chip" onclick="circPreset('ac')">AC-цепь</button>
|
||
<button class="proj-preset-chip" onclick="circPreset('rlc')">RLC-резонанс</button>
|
||
</div>
|
||
|
||
<div style="margin-top:auto;font-size:0.68rem;color:var(--text-3);text-align:center;line-height:1.7;padding-top:4px">
|
||
Тяни узлы для рисования · ПКМ — удалить<br>
|
||
2×клик по выключателю — вкл/выкл · Ctrl+Z отмена
|
||
</div>
|
||
|
||
</div><!-- /.proj-panel -->
|
||
|
||
<div class="proj-canvas-outer">
|
||
<canvas id="circuit-canvas" style="display:block;position:absolute;top:0;left:0;width:100%;height:100%;cursor:crosshair"></canvas>
|
||
<div id="osc-panel" style="display:none;position:absolute;bottom:8px;right:8px;z-index:10;background:rgba(6,6,22,0.95);border:1px solid rgba(255,255,255,0.12);border-radius:8px;padding:6px">
|
||
<div style="font-size:0.7rem;color:rgba(255,255,255,0.45);margin-bottom:4px;text-align:center">Осциллограф</div>
|
||
<canvas id="osc-canvas" width="300" height="180" style="display:block;border-radius:4px"></canvas>
|
||
</div>
|
||
</div>
|
||
|
||
</div><!-- /.sim-body-wrap -->
|
||
|
||
<div class="proj-stats-bar">
|
||
<div class="pstat"><div class="pstat-label">Компонентов</div><div class="pstat-val" id="cirbar-comps">0</div></div>
|
||
<div class="pstat"><div class="pstat-label">Напряжение U</div><div class="pstat-val" id="cirbar-U" style="color:#EF476F">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Ток I</div><div class="pstat-val" id="cirbar-I" style="color:#FFD166">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Мощность P</div><div class="pstat-val" id="cirbar-P" style="color:#7BF5A4">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Статус</div><div class="pstat-val" id="cirbar-status">—</div></div>
|
||
</div>
|
||
</div><!-- /#sim-circuit -->
|
||
|
||
<!-- ══════════════════════════════════════════════
|
||
ЛОГИЧЕСКИЕ СХЕМЫ
|
||
══════════════════════════════════════════════ -->
|
||
<div id="sim-logic" class="sim-proj-wrap" style="display:none">
|
||
|
||
<!-- left panel: palette + presets -->
|
||
<div class="sim-body-wrap" style="flex-direction:column">
|
||
|
||
<div style="display:flex;flex:1;min-height:0;overflow:hidden">
|
||
|
||
<div class="proj-panel" style="width:220px;gap:0;overflow-y:auto">
|
||
|
||
<div class="gp-section-title" style="margin-bottom:8px">Инструмент</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:5px;margin-bottom:10px">
|
||
<button class="proj-preset-chip lgc-tool-btn active" data-tool="select" onclick="logicTool('select',this)">Выбор</button>
|
||
<button class="proj-preset-chip lgc-tool-btn" data-tool="INPUT" onclick="logicTool('INPUT',this)">INPUT</button>
|
||
<button class="proj-preset-chip lgc-tool-btn" data-tool="CLOCK" onclick="logicTool('CLOCK',this)">CLOCK</button>
|
||
<button class="proj-preset-chip lgc-tool-btn" data-tool="OUTPUT" onclick="logicTool('OUTPUT',this)">OUTPUT</button>
|
||
<button class="proj-preset-chip lgc-tool-btn" data-tool="AND" onclick="logicTool('AND',this)">AND</button>
|
||
<button class="proj-preset-chip lgc-tool-btn" data-tool="OR" onclick="logicTool('OR',this)">OR</button>
|
||
<button class="proj-preset-chip lgc-tool-btn" data-tool="NOT" onclick="logicTool('NOT',this)">NOT</button>
|
||
<button class="proj-preset-chip lgc-tool-btn" data-tool="XOR" onclick="logicTool('XOR',this)">XOR</button>
|
||
<button class="proj-preset-chip lgc-tool-btn" data-tool="NAND" onclick="logicTool('NAND',this)">NAND</button>
|
||
<button class="proj-preset-chip lgc-tool-btn" data-tool="NOR" onclick="logicTool('NOR',this)">NOR</button>
|
||
<button class="proj-preset-chip lgc-tool-btn" data-tool="XNOR" onclick="logicTool('XNOR',this)">XNOR</button>
|
||
<button class="proj-preset-chip lgc-tool-btn" data-tool="BUFFER" onclick="logicTool('BUFFER',this)">BUF</button>
|
||
</div>
|
||
|
||
<div class="gp-section-title" style="margin-bottom:8px;margin-top:4px">Пресеты</div>
|
||
<div style="display:flex;flex-direction:column;gap:5px;margin-bottom:10px">
|
||
<button class="proj-preset-chip" onclick="logicPreset('half-adder')">Полусумматор</button>
|
||
<button class="proj-preset-chip" onclick="logicPreset('full-adder')">Полный сумматор</button>
|
||
<button class="proj-preset-chip" onclick="logicPreset('rs-latch')">RS-триггер</button>
|
||
<button class="proj-preset-chip" onclick="logicPreset('d-latch')">D-триггер</button>
|
||
<button class="proj-preset-chip" onclick="logicPreset('decoder-2to4')">Декодер 2-в-4</button>
|
||
<button class="proj-preset-chip" onclick="logicPreset('mux-2to1')">Мультиплексор 2-в-1</button>
|
||
<button class="proj-preset-chip" onclick="logicPreset('and-gate')">AND (пример)</button>
|
||
</div>
|
||
|
||
<button class="proj-preset-chip" style="margin-top:auto;background:rgba(239,71,111,0.12);border-color:rgba(239,71,111,0.35);color:#EF476F" onclick="logicClearAll()">Очистить</button>
|
||
|
||
<div style="margin-top:10px;font-size:0.67rem;color:var(--text-3);text-align:center;line-height:1.7;padding-top:4px">
|
||
Клик = добавить элемент<br>
|
||
Перетащи выход (кружок) на вход<br>
|
||
2×клик по INPUT — переключить 0/1<br>
|
||
ПКМ — удалить | Ctrl+Z отмена
|
||
</div>
|
||
|
||
</div><!-- /.proj-panel -->
|
||
|
||
<div class="proj-canvas-outer" style="flex:1;position:relative">
|
||
<canvas id="logic-canvas" style="display:block;position:absolute;top:0;left:0;width:100%;height:100%;cursor:default"></canvas>
|
||
</div>
|
||
|
||
<!-- right: boolean expression panel -->
|
||
<div class="proj-panel" style="width:200px;gap:0;overflow-y:auto">
|
||
<div class="gp-section-title" style="margin-bottom:8px">Выражение</div>
|
||
<div id="logic-expr" style="font-size:0.82rem;color:rgba(255,255,255,0.8);line-height:1.7;word-break:break-all;min-height:40px">
|
||
Добавьте OUTPUT для вывода выражения
|
||
</div>
|
||
</div>
|
||
|
||
</div><!-- /.flex row -->
|
||
|
||
<!-- truth table panel (collapsible) -->
|
||
<div id="logic-tt-panel" style="max-height:200px;overflow:auto;border-top:1px solid rgba(255,255,255,0.08);padding:8px 12px">
|
||
<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px">
|
||
<span style="font-size:0.75rem;font-weight:700;color:rgba(255,255,255,0.55);letter-spacing:.08em;text-transform:uppercase">Таблица истинности</span>
|
||
<button id="btn-logic-tt" class="zoom-btn active" onclick="logicToggleTable()" style="font-size:0.65rem;padding:2px 7px">скрыть</button>
|
||
</div>
|
||
<div id="logic-tt-body" style="font-size:0.78rem">
|
||
<span style="color:rgba(255,255,255,0.35)">Добавьте INPUT и OUTPUT</span>
|
||
</div>
|
||
</div>
|
||
|
||
</div><!-- /.sim-body-wrap -->
|
||
|
||
</div><!-- /#sim-logic -->
|
||
|
||
<!-- ══════════════════════════════════════════════
|
||
КИНЕТИКА РЕАКЦИЙ
|
||
══════════════════════════════════════════════ -->
|
||
<!-- ══════════════════════════════════════════════
|
||
ХИМИЯ (unified: кинетика + колба + ОВР + ионный обмен)
|
||
══════════════════════════════════════════════ -->
|
||
<div id="sim-chemistry" class="sim-proj-wrap" style="display:none">
|
||
<div class="sim-body-wrap">
|
||
|
||
<div class="proj-panel" style="width:248px;gap:0">
|
||
|
||
<!-- Mode selector -->
|
||
<div style="display:flex;gap:3px;margin-bottom:12px;padding:3px;background:rgba(255,255,255,0.04);border-radius:10px;border:1px solid var(--border)">
|
||
<button class="mag-mode-btn chem-mode active" id="chem-mode-kinetics" onclick="chemMode('kinetics',this)" style="flex:1;font-size:.63rem;padding:5px 2px">Кинетика</button>
|
||
<button class="mag-mode-btn chem-mode" id="chem-mode-flask" onclick="chemMode('flask',this)" style="flex:1;font-size:.63rem;padding:5px 2px">Колба</button>
|
||
<button class="mag-mode-btn chem-mode" id="chem-mode-redox" onclick="chemMode('redox',this)" style="flex:1;font-size:.63rem;padding:5px 2px">ОВР</button>
|
||
<button class="mag-mode-btn chem-mode" id="chem-mode-ionex" onclick="chemMode('ionex',this)" style="flex:1;font-size:.63rem;padding:5px 2px">Ионный</button>
|
||
</div>
|
||
|
||
<!-- ── Kinetics panel ── -->
|
||
<div id="chem-panel-kinetics">
|
||
<div class="gp-section-title" style="margin-bottom:6px">Параметры</div>
|
||
|
||
<div class="param-block" style="margin-bottom:7px">
|
||
<div class="param-header"><span class="param-name">Молекул N</span><span class="param-val" id="reac-N-val">28</span></div>
|
||
<input type="range" class="param-slider" id="sl-reacN" min="5" max="60" value="28" oninput="reacNChange()">
|
||
</div>
|
||
<div class="param-block" style="margin-bottom:7px">
|
||
<div class="param-header"><span class="param-name">Температура T</span><span class="param-val" id="reac-T-val">1.2</span></div>
|
||
<input type="range" class="param-slider" id="sl-reacT" min="2" max="40" value="12" oninput="reacTChange()">
|
||
</div>
|
||
<div class="param-block" style="margin-bottom:7px">
|
||
<div class="param-header"><span class="param-name">Энергия активации Ea</span><span class="param-val" id="reac-Ea-val">2.0</span></div>
|
||
<input type="range" class="param-slider" id="sl-reacEa" min="5" max="50" value="20" oninput="reacEaChange()">
|
||
</div>
|
||
|
||
<div class="gp-section-title" style="margin-bottom:6px">Режим</div>
|
||
<div style="display:flex;flex-direction:column;gap:4px;margin-bottom:8px">
|
||
<button class="proj-preset-chip reac-mode-btn active" id="rmode-forward" onclick="reacMode('forward',this)" style="text-align:left"><svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg> Прямая (A+B<svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>C)</button>
|
||
<button class="proj-preset-chip reac-mode-btn" id="rmode-reversible" onclick="reacMode('reversible',this)" style="text-align:left">⇌ Обратимая</button>
|
||
<button class="proj-preset-chip reac-mode-btn" id="rmode-chain" onclick="reacMode('chain',this)" style="text-align:left"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="display:inline-block;vertical-align:middle"><path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/></svg> Цепная</button>
|
||
</div>
|
||
|
||
<div class="gp-section-title" style="margin-bottom:6px">Пресеты</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:5px">
|
||
<button class="proj-preset-chip" onclick="reacPreset('simple')">Простая</button>
|
||
<button class="proj-preset-chip" onclick="reacPreset('reversible')">Равновесие</button>
|
||
<button class="proj-preset-chip" onclick="reacPreset('hot')">Горячая</button>
|
||
<button class="proj-preset-chip" onclick="reacPreset('cold')">Холодная</button>
|
||
<button class="proj-preset-chip" onclick="reacPreset('chain')">Цепная</button>
|
||
</div>
|
||
</div><!-- /chem-panel-kinetics -->
|
||
|
||
<!-- ── Flask panel ── -->
|
||
<div id="chem-panel-flask" style="display:none">
|
||
<div class="gp-section-title" style="margin-bottom:8px">Металл</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:5px;margin-bottom:10px">
|
||
<button class="proj-preset-chip flask-metal-btn active" id="fmetal-Zn" onclick="flaskMetal('Zn',this)">Zn</button>
|
||
<button class="proj-preset-chip flask-metal-btn" id="fmetal-Fe" onclick="flaskMetal('Fe',this)">Fe</button>
|
||
<button class="proj-preset-chip flask-metal-btn" id="fmetal-Mg" onclick="flaskMetal('Mg',this)">Mg</button>
|
||
<button class="proj-preset-chip flask-metal-btn" id="fmetal-Cu" onclick="flaskMetal('Cu',this)">Cu</button>
|
||
<button class="proj-preset-chip flask-metal-btn" id="fmetal-Na" onclick="flaskMetal('Na',this)">Na</button>
|
||
<button class="proj-preset-chip flask-metal-btn" id="fmetal-Al" onclick="flaskMetal('Al',this)">Al</button>
|
||
</div>
|
||
|
||
<div class="gp-section-title" style="margin-bottom:8px">Реагент</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:5px;margin-bottom:10px">
|
||
<button class="proj-preset-chip flask-acid-btn active" id="facid-HCl" onclick="flaskAcid('HCl',this)">HCl</button>
|
||
<button class="proj-preset-chip flask-acid-btn" id="facid-H2SO4" onclick="flaskAcid('H2SO4',this)">H₂SO₄</button>
|
||
<button class="proj-preset-chip flask-acid-btn" id="facid-H2O" onclick="flaskAcid('H2O',this)">H₂O</button>
|
||
</div>
|
||
|
||
<div class="param-block">
|
||
<div class="param-header"><span class="param-name">Концентрация</span><span class="param-val" id="flask-conc-val">35%</span></div>
|
||
<input type="range" class="param-slider" id="sl-flask-conc" min="5" max="98" value="35" oninput="flaskConcChange()">
|
||
</div>
|
||
<div class="param-block">
|
||
<div class="param-header"><span class="param-name">Темп. окружения</span><span class="param-val" id="flask-temp-val">20°C</span></div>
|
||
<input type="range" class="param-slider" id="sl-flask-temp" min="5" max="80" value="20" oninput="flaskTempChange()">
|
||
</div>
|
||
|
||
<div style="display:flex;gap:6px;margin-bottom:10px;margin-top:2px">
|
||
<button class="proj-preset-chip" style="flex:1;background:rgba(239,71,111,0.18);border-color:rgba(239,71,111,0.4)"
|
||
onclick="flaskSim && flaskSim.dropMetal()"><svg class="ic" viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><polyline points="19 12 12 19 5 12"/></svg> Бросить металл</button>
|
||
<button class="proj-preset-chip" id="flask-flame-panel" style="flex:0 0 auto"
|
||
onclick="flaskToggleFlame()"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="display:inline-block;vertical-align:middle"><path d="M12 2c.5 3.5-1.5 6-1.5 6 1 1.5 3 2 3 5a4 4 0 01-8 0c0-2 .5-3 1.5-4.5C8.5 6.5 7 4.5 7 4.5S9.5 2 12 2z"/></svg></button>
|
||
</div>
|
||
|
||
<div style="font-size:.65rem;color:var(--text-3);text-align:center;line-height:1.7;margin-top:auto;padding-top:4px">
|
||
Выбери металл + кислоту<br>H₂ накапливается — поднеси огонь!
|
||
</div>
|
||
</div><!-- /chem-panel-flask -->
|
||
|
||
<!-- ── Redox panel ── -->
|
||
<div id="chem-panel-redox" style="display:none">
|
||
<div class="gp-section-title" style="margin-bottom:8px">Реакция</div>
|
||
<div style="display:flex;flex-direction:column;gap:4px;margin-bottom:12px">
|
||
<button class="proj-preset-chip redox-rxn-btn active" id="rdxrxn-fe_cu" onclick="redoxRxn('fe_cu',this)" style="text-align:left;font-size:.72rem">Fe + CuSO₄ <svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg> FeSO₄ + Cu<svg class="ic" viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><polyline points="19 12 12 19 5 12"/></svg></button>
|
||
<button class="proj-preset-chip redox-rxn-btn" id="rdxrxn-zn_hcl" onclick="redoxRxn('zn_hcl',this)" style="text-align:left;font-size:.72rem">Zn + 2HCl <svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg> ZnCl₂ + H₂<svg class="ic" viewBox="0 0 24 24"><line x1="12" y1="19" x2="12" y2="5"/><polyline points="5 12 12 5 19 12"/></svg></button>
|
||
<button class="proj-preset-chip redox-rxn-btn" id="rdxrxn-cl2_ki" onclick="redoxRxn('cl2_ki',this)" style="text-align:left;font-size:.72rem">Cl₂ + 2KI <svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg> I₂<svg class="ic" viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><polyline points="19 12 12 19 5 12"/></svg> + 2KCl</button>
|
||
<button class="proj-preset-chip redox-rxn-btn" id="rdxrxn-kmno4" onclick="redoxRxn('kmno4',this)" style="text-align:left;font-size:.72rem">KMnO₄ + FeSO₄ (кислая)</button>
|
||
<button class="proj-preset-chip redox-rxn-btn" id="rdxrxn-cu_fecl3" onclick="redoxRxn('cu_fecl3',this)" style="text-align:left;font-size:.72rem">Cu + 2FeCl₃ <svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg> CuCl₂ + 2FeCl₂</button>
|
||
</div>
|
||
<button class="proj-launch-btn" style="margin-bottom:8px" onclick="redoxStart()"><svg class="ic" viewBox="0 0 24 24"><polygon points="5 3 19 12 5 21 5 3"/></svg> Начать реакцию</button>
|
||
<button class="proj-reset-btn" onclick="redoxReset()"><svg class="ic" viewBox="0 0 24 24"><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 .49-4.12"/></svg> Сброс</button>
|
||
<div style="margin-top:auto;padding-top:6px;font-size:.65rem;color:var(--text-3);line-height:1.7;text-align:center">
|
||
Синие e⁻ — перенос электронов<br>Цифры — степень окисления
|
||
</div>
|
||
</div><!-- /chem-panel-redox -->
|
||
|
||
<!-- ── Ion exchange panel ── -->
|
||
<div id="chem-panel-ionex" style="display:none">
|
||
<div class="gp-section-title" style="margin-bottom:8px">Реакция</div>
|
||
<div style="display:flex;flex-direction:column;gap:4px;margin-bottom:12px">
|
||
<button class="proj-preset-chip ionex-rxn-btn active" id="ioxrxn-ba_so4" onclick="ionexRxn('ba_so4',this)" style="text-align:left;font-size:.72rem">BaCl₂ + Na₂SO₄ <svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg> BaSO₄<svg class="ic" viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><polyline points="19 12 12 19 5 12"/></svg></button>
|
||
<button class="proj-preset-chip ionex-rxn-btn" id="ioxrxn-ag_cl" onclick="ionexRxn('ag_cl',this)" style="text-align:left;font-size:.72rem">AgNO₃ + NaCl <svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg> AgCl<svg class="ic" viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><polyline points="19 12 12 19 5 12"/></svg></button>
|
||
<button class="proj-preset-chip ionex-rxn-btn" id="ioxrxn-co3_hcl" onclick="ionexRxn('co3_hcl',this)" style="text-align:left;font-size:.72rem">Na₂CO₃ + 2HCl <svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg> CO₂<svg class="ic" viewBox="0 0 24 24"><line x1="12" y1="19" x2="12" y2="5"/><polyline points="5 12 12 5 19 12"/></svg></button>
|
||
<button class="proj-preset-chip ionex-rxn-btn" id="ioxrxn-pb_i" onclick="ionexRxn('pb_i',this)" style="text-align:left;font-size:.72rem">Pb(NO₃)₂ + 2KI <svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg> PbI₂<svg class="ic" viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><polyline points="19 12 12 19 5 12"/></svg></button>
|
||
<button class="proj-preset-chip ionex-rxn-btn" id="ioxrxn-ca_co3" onclick="ionexRxn('ca_co3',this)" style="text-align:left;font-size:.72rem">CaCl₂ + Na₂CO₃ <svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg> CaCO₃<svg class="ic" viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><polyline points="19 12 12 19 5 12"/></svg></button>
|
||
</div>
|
||
<button class="proj-launch-btn" style="margin-bottom:8px" onclick="ionexStart()"><svg class="ic" viewBox="0 0 24 24"><path d="M9 3h6m-4.5 0v5.5l-4 7.5a1 1 0 0 0 .9 1.5h8.2a1 1 0 0 0 .9-1.5l-4-7.5V3"/></svg> Смешать растворы</button>
|
||
<button class="proj-reset-btn" onclick="ionexReset()"><svg class="ic" viewBox="0 0 24 24"><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 .49-4.12"/></svg> Сброс</button>
|
||
<div style="margin-top:auto;padding-top:6px;font-size:.65rem;color:var(--text-3);line-height:1.7;text-align:center">
|
||
Яркие ионы = реагируют<br>Тусклые = зрители · <svg class="ic" viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><polyline points="19 12 12 19 5 12"/></svg> осадок · <svg class="ic" viewBox="0 0 24 24"><line x1="12" y1="19" x2="12" y2="5"/><polyline points="5 12 12 5 19 12"/></svg> газ
|
||
</div>
|
||
</div><!-- /chem-panel-ionex -->
|
||
|
||
</div><!-- /.proj-panel -->
|
||
|
||
<div class="proj-canvas-outer">
|
||
<canvas id="reactions-canvas" style="display:block;position:absolute;top:0;left:0;width:100%;height:100%"></canvas>
|
||
<canvas id="flask-canvas" style="display:none;position:absolute;top:0;left:0;width:100%;height:100%;cursor:default"></canvas>
|
||
<canvas id="redox-canvas" style="display:none;position:absolute;top:0;left:0;width:100%;height:100%;cursor:default"></canvas>
|
||
<canvas id="ionexchange-canvas" style="display:none;position:absolute;top:0;left:0;width:100%;height:100%;cursor:default"></canvas>
|
||
</div>
|
||
|
||
</div><!-- /.sim-body-wrap -->
|
||
|
||
<div class="proj-stats-bar" id="chem-stats-bar">
|
||
<div class="pstat"><div class="pstat-label" id="chbar-l1">—</div><div class="pstat-val" id="chbar-v1" style="color:var(--cyan)">—</div></div>
|
||
<div class="pstat"><div class="pstat-label" id="chbar-l2">—</div><div class="pstat-val" id="chbar-v2" style="color:#EF476F">—</div></div>
|
||
<div class="pstat"><div class="pstat-label" id="chbar-l3">—</div><div class="pstat-val" id="chbar-v3" style="color:#FFD166">—</div></div>
|
||
<div class="pstat"><div class="pstat-label" id="chbar-l4">—</div><div class="pstat-val" id="chbar-v4">—</div></div>
|
||
<div class="pstat"><div class="pstat-label" id="chbar-l5">—</div><div class="pstat-val" id="chbar-v5" style="color:#7BF5A4">—</div></div>
|
||
</div>
|
||
</div><!-- /#sim-chemistry -->
|
||
|
||
<!-- ── DYNAMICS sim body (Newton + Sandbox unified) ── -->
|
||
<div id="sim-dynamics" class="sim-proj-wrap" style="display:none">
|
||
<div class="sim-body-wrap">
|
||
|
||
<div class="proj-panel dyn-panel-modern" style="width:300px;gap:0">
|
||
|
||
<!-- ══ Mode selector ══ -->
|
||
<div class="dyn-mode-bar">
|
||
<button class="mag-mode-btn dyn-mode active" id="dyn-mode-sandbox" onclick="dynMode('sandbox',this)" title="Песочница — свободный режим">Песочница</button>
|
||
<button class="mag-mode-btn dyn-mode" id="dyn-mode-law4" onclick="dynMode('law4',this)" title="Классические сцены: Атвуд, Наклон, Качение">Классика</button>
|
||
</div>
|
||
<div class="dyn-mode-bar" style="margin-bottom:14px">
|
||
<button class="mag-mode-btn dyn-mode" id="dyn-mode-law1" onclick="dynMode('law1',this)" title="I закон Ньютона — инерция">I закон</button>
|
||
<button class="mag-mode-btn dyn-mode" id="dyn-mode-law2" onclick="dynMode('law2',this)" title="II закон Ньютона — F=ma">II закон</button>
|
||
<button class="mag-mode-btn dyn-mode" id="dyn-mode-law3" onclick="dynMode('law3',this)" title="III закон Ньютона — действие=противодействие">III закон</button>
|
||
</div>
|
||
|
||
<!-- ══ Newton controls (shown in law modes) ══ -->
|
||
<div id="dyn-newton-panel" style="display:none">
|
||
|
||
<!-- Scene selector (standard A/B/C — hidden for law 4) -->
|
||
<div class="gp-section-title" style="margin-bottom:8px" id="newton-scene-title">Сцена</div>
|
||
<div class="dyn-row-4" style="grid-template-columns:1fr 1fr 1fr;margin-bottom:12px" id="newton-scene-row">
|
||
<button class="mag-mode-btn nscene-btn active" id="nscn-panel-A" onclick="newtonScene('A',null,this)">A</button>
|
||
<button class="mag-mode-btn nscene-btn" id="nscn-panel-B" onclick="newtonScene('B',null,this)">B</button>
|
||
<button class="mag-mode-btn nscene-btn" id="nscn-panel-C" onclick="newtonScene('C',null,this)">C</button>
|
||
</div>
|
||
|
||
<!-- Classic scene selector (law 4 only) -->
|
||
<div id="newton-classic-panel" style="display:none">
|
||
<div class="dyn-row-4" style="grid-template-columns:1fr 1fr 1fr;margin-bottom:10px">
|
||
<button class="mag-mode-btn cl-scene-btn active" id="nscn-panel-cl-atwood" data-scene="atwood" onclick="classicScene('atwood')">Атвуд</button>
|
||
<button class="mag-mode-btn cl-scene-btn" id="nscn-panel-cl-ramp" data-scene="ramp" onclick="classicScene('ramp')">Наклон</button>
|
||
<button class="mag-mode-btn cl-scene-btn" id="nscn-panel-cl-roll" data-scene="roll" onclick="classicScene('roll')">Качение</button>
|
||
</div>
|
||
|
||
<!-- Atwood sub-panel -->
|
||
<div id="cl-sub-atwood">
|
||
<div class="param-block">
|
||
<div class="param-header"><span class="param-name">m₁ (кг)</span><span class="param-val" id="atw-m1-val">5 кг</span></div>
|
||
<input type="range" class="param-slider" id="sl-atw-m1" min="1" max="20" value="5" oninput="atwM1Change()">
|
||
</div>
|
||
<div class="param-block">
|
||
<div class="param-header"><span class="param-name">m₂ (кг)</span><span class="param-val" id="atw-m2-val">8 кг</span></div>
|
||
<input type="range" class="param-slider" id="sl-atw-m2" min="1" max="20" value="8" oninput="atwM2Change()">
|
||
</div>
|
||
<div class="gp-section-title" style="margin:4px 0">Блок</div>
|
||
<div class="dyn-row-2">
|
||
<button class="mag-mode-btn atw-massive-btn active" data-val="false" onclick="atwMassiveToggle(false)">Идеальный</button>
|
||
<button class="mag-mode-btn atw-massive-btn" data-val="true" onclick="atwMassiveToggle(true)">Массивный</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Ramp sub-panel -->
|
||
<div id="cl-sub-ramp" style="display:none">
|
||
<div class="param-block">
|
||
<div class="param-header"><span class="param-name">Угол α</span><span class="param-val" id="ramp-alpha-val">30°</span></div>
|
||
<input type="range" class="param-slider" id="sl-ramp-alpha" min="1" max="89" value="30" oninput="rampAlphaChange()">
|
||
</div>
|
||
<div class="param-block">
|
||
<div class="param-header"><span class="param-name">Масса m (кг)</span><span class="param-val" id="newton-m1-ramp-val">5 кг</span></div>
|
||
<input type="range" class="param-slider" id="sl-ramp-mass" min="1" max="20" value="5" oninput="rampMassChange()">
|
||
</div>
|
||
<div class="param-block">
|
||
<div class="param-header"><span class="param-name">Коэфф. трения μ</span><span class="param-val" id="ramp-mu-val">0.20</span></div>
|
||
<input type="range" class="param-slider" id="sl-ramp-mu" min="0" max="1.5" step="0.01" value="0.20" oninput="rampMuChange()">
|
||
</div>
|
||
<div class="param-block">
|
||
<div class="param-header"><span class="param-name">Внеш. сила F (Н)</span><span class="param-val" id="ramp-force-val">0 Н</span></div>
|
||
<input type="range" class="param-slider" id="sl-ramp-force" min="0" max="80" value="0" oninput="rampForceChange()">
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Roll sub-panel -->
|
||
<div id="cl-sub-roll" style="display:none">
|
||
<div class="param-block">
|
||
<div class="param-header"><span class="param-name">Угол α</span><span class="param-val" id="roll-alpha-val">20°</span></div>
|
||
<input type="range" class="param-slider" id="sl-roll-alpha" min="5" max="60" value="20" oninput="rollAlphaChange()">
|
||
</div>
|
||
<div class="gp-section-title" style="margin:4px 0">Режим</div>
|
||
<div class="dyn-row-2">
|
||
<button class="mag-mode-btn roll-friction-btn active" data-val="false" onclick="rollFrictionToggle(false)">Качение</button>
|
||
<button class="mag-mode-btn roll-friction-btn" data-val="true" onclick="rollFrictionToggle(true)">+Трение</button>
|
||
</div>
|
||
<div style="font-size:.78rem;color:var(--text-2);line-height:1.55;padding:7px 10px;background:rgba(255,255,255,0.035);border-radius:8px;border:1px solid var(--border);margin-bottom:8px">
|
||
Шар: a = (5/7)g·sinα<br>
|
||
Цилиндр: a = (2/3)g·sinα<br>
|
||
Обруч: a = (1/2)g·sinα
|
||
</div>
|
||
</div>
|
||
</div><!-- /#newton-classic-panel -->
|
||
|
||
<!-- Scene description -->
|
||
<div id="newton-scene-desc" style="font-size:.82rem;color:var(--text-2);line-height:1.6;margin-bottom:12px;padding:9px 11px;background:rgba(255,255,255,0.04);border-radius:8px;border:1px solid var(--border)">
|
||
Закон инерции: тело движется равномерно при отсутствии сил.
|
||
</div>
|
||
|
||
<!-- Parameter sliders -->
|
||
<div id="newton-mu-block" class="param-block">
|
||
<div class="param-header"><span class="param-name">Коэфф. трения μ</span><span class="param-val" id="newton-mu-val">0.20</span></div>
|
||
<input type="range" class="param-slider" id="sl-newton-mu" min="0" max="1" step="0.01" value="0.20" oninput="newtonMuChange()">
|
||
</div>
|
||
<div id="newton-mass1-block" class="param-block" style="display:none">
|
||
<div class="param-header"><span class="param-name">Масса m₁ (кг)</span><span class="param-val" id="newton-m1-val">5 кг</span></div>
|
||
<input type="range" class="param-slider" id="sl-newton-m1" min="1" max="20" value="5" oninput="newtonMass1Change()">
|
||
</div>
|
||
<div id="newton-mass2-block" class="param-block" style="display:none">
|
||
<div class="param-header"><span class="param-name">Масса m₂ (кг)</span><span class="param-val" id="newton-m2-val">5 кг</span></div>
|
||
<input type="range" class="param-slider" id="sl-newton-m2" min="1" max="20" value="5" oninput="newtonMass2Change()">
|
||
</div>
|
||
<div id="newton-force-block" class="param-block" style="display:none">
|
||
<div class="param-header"><span class="param-name">Сила F (Н)</span><span class="param-val" id="newton-F-val">20 Н</span></div>
|
||
<input type="range" class="param-slider" id="sl-newton-F" min="1" max="60" value="20" oninput="newtonForceChange()">
|
||
</div>
|
||
|
||
<!-- Presets -->
|
||
<div class="gp-section-title" style="margin-top:6px">Пресеты</div>
|
||
<div id="newton-presets" style="display:flex;flex-wrap:wrap;gap:5px;margin-bottom:10px">
|
||
<button class="proj-preset-chip" onclick="newtonPreset('space')">Космос</button>
|
||
<button class="proj-preset-chip" onclick="newtonPreset('ice')">Лёд</button>
|
||
<button class="proj-preset-chip" onclick="newtonPreset('asphalt')">Асфальт</button>
|
||
<button class="proj-preset-chip" onclick="newtonPreset('rubber')">Резина</button>
|
||
</div>
|
||
|
||
<!-- Action -->
|
||
<div style="margin-top:auto;padding-top:10px;display:flex;flex-direction:column;gap:6px">
|
||
<button class="proj-launch-btn" id="newton-action-main" onclick="newtonAction()">
|
||
<span id="newton-action-label"><svg class="ic" viewBox="0 0 24 24"><polygon points="5 3 19 12 5 21 5 3"/></svg> Действие</span>
|
||
</button>
|
||
<button class="proj-reset-btn" onclick="_resetNewtonScene()">
|
||
<svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>
|
||
Сброс сцены
|
||
</button>
|
||
</div>
|
||
|
||
<!-- Newton graphs toggle -->
|
||
<div style="margin-top:12px;padding-top:10px;border-top:1px solid rgba(255,255,255,0.07)">
|
||
<button id="btn-newton-graphs" onclick="newtonToggleGraphs()" style="width:100%;font-size:.82rem;font-weight:700;padding:8px;border-radius:8px;border:1px solid rgba(6,214,224,0.35);background:rgba(6,214,224,0.1);color:#06D6E0;cursor:pointer">Графики x/v/a</button>
|
||
</div>
|
||
|
||
<!-- Energy bars toggle — newton -->
|
||
<div class="gp-section-title" style="margin-top:10px">Закон сохранения энергии</div>
|
||
<button id="nwt-energy-btn" class="proj-preset-chip" onclick="dynToggleEnergy()" style="width:100%;font-size:.82rem;text-align:left;display:flex;align-items:center;gap:7px;padding:8px 11px">
|
||
<svg class="ic" viewBox="0 0 24 24"><path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/></svg>
|
||
<span>Энергия: Выкл</span>
|
||
</button>
|
||
|
||
</div><!-- /#dyn-newton-panel -->
|
||
|
||
<!-- ══ Sandbox controls (shown in sandbox mode) ══ -->
|
||
<div id="dyn-sandbox-panel">
|
||
|
||
<div class="gp-section-title" style="margin-bottom:8px">Инструмент</div>
|
||
<div class="dyn-tool-grid">
|
||
<button class="mag-mode-btn sb-panel-tool active" id="sbpt-box" onclick="sbTool('box',this)"><svg class="ic" viewBox="0 0 24 24"><rect x="3" y="3" width="18" height="18" rx="2"/></svg> Блок</button>
|
||
<button class="mag-mode-btn sb-panel-tool" id="sbpt-ball" onclick="sbTool('ball',this)"><svg class="ic" viewBox="0 0 24 24"><circle cx="12" cy="12" r="8" fill="currentColor" stroke="none"/></svg> Шар</button>
|
||
<button class="mag-mode-btn sb-panel-tool" id="sbpt-erase" onclick="sbTool('erase',this)"><svg class="ic" viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg> Ластик</button>
|
||
<button class="mag-mode-btn sb-panel-tool" id="sbpt-spring" onclick="sbTool('spring',this)"><svg class="ic" viewBox="0 0 24 24" fill="none"><path d="M3 12 L6 8 L9 16 L12 8 L15 16 L18 8 L21 12"/></svg> Пружина</button>
|
||
<button class="mag-mode-btn sb-panel-tool" id="sbpt-rope" onclick="sbTool('rope',this)">— Нить</button>
|
||
<button class="mag-mode-btn sb-panel-tool" id="sbpt-anchor" onclick="sbTool('anchor',this)"><svg class="ic" viewBox="0 0 24 24"><path d="M12 2 2 12 12 22 22 12Z"/></svg> Якорь</button>
|
||
</div>
|
||
|
||
<div class="gp-section-title">Режим силы</div>
|
||
<div class="dyn-row-2">
|
||
<button class="mag-mode-btn sb-fmode active" id="sbfm-constant" onclick="sbForceMode('constant',this)">Постоянная</button>
|
||
<button class="mag-mode-btn sb-fmode" id="sbfm-impulse" onclick="sbForceMode('impulse',this)">Импульс</button>
|
||
</div>
|
||
|
||
<div class="param-block">
|
||
<div class="param-header"><span class="param-name">Масса нового тела</span><span class="param-val" id="sb-mass-val">5 кг</span></div>
|
||
<input type="range" class="param-slider" id="sl-sb-mass" min="1" max="30" value="5" oninput="sbMassChange()">
|
||
</div>
|
||
<div class="param-block">
|
||
<div class="param-header"><span class="param-name">Упругость</span><span class="param-val" id="sb-rest-val">0.65</span></div>
|
||
<input type="range" class="param-slider" id="sl-sb-rest" min="0" max="1" step="0.05" value="0.65" oninput="sbRestChange()">
|
||
</div>
|
||
<div class="param-block" id="sb-spring-block" style="display:none">
|
||
<div class="param-header"><span class="param-name">Жёсткость пружины k</span><span class="param-val" id="sb-springk-val">120 Н/м</span></div>
|
||
<input type="range" class="param-slider" id="sl-sb-springk" min="10" max="600" step="10" value="120" oninput="sbSpringKChange()">
|
||
</div>
|
||
|
||
<details class="dyn-acc" open>
|
||
<summary>Мир</summary>
|
||
<div class="dyn-acc-body">
|
||
<div class="dyn-checks">
|
||
<label><input type="checkbox" id="sb-gravity" checked onchange="sbWorldToggle()"> Гравитация</label>
|
||
<label><input type="checkbox" id="sb-floor" checked onchange="sbWorldToggle()"> Пол</label>
|
||
<label><input type="checkbox" id="sb-walls" checked onchange="sbWorldToggle()"> Стенки</label>
|
||
<label><input type="checkbox" id="sb-airdrag" onchange="sbWorldToggle()"> Сопротивление воздуха</label>
|
||
<label><input type="checkbox" id="sb-ramp" onchange="sbRampToggle()"> Наклонная плоскость</label>
|
||
</div>
|
||
<div id="sb-ramp-block" style="display:none">
|
||
<div class="param-block">
|
||
<div class="param-header"><span class="param-name">Угол α</span><span class="param-val" id="sb-angle-val">30°</span></div>
|
||
<input type="range" class="param-slider" id="sl-sb-angle" min="5" max="75" value="30" oninput="sbAngleChange()">
|
||
</div>
|
||
<div class="param-block">
|
||
<div class="param-header"><span class="param-name">Трение горки μ</span><span class="param-val" id="sb-rampmu-val">0.20</span></div>
|
||
<input type="range" class="param-slider" id="sl-sb-rampmu" min="0" max="1" step="0.01" value="0.20" oninput="sbRampMuChange()">
|
||
</div>
|
||
<label class="dyn-check-inline"><input type="checkbox" id="sb-decomp" checked onchange="sbDecompToggle()"> Разложение сил</label>
|
||
</div>
|
||
<div class="param-block">
|
||
<div class="param-header"><span class="param-name">Трение пола μ</span><span class="param-val" id="sb-floormu-val">0.30</span></div>
|
||
<input type="range" class="param-slider" id="sl-sb-floormu" min="0" max="1" step="0.01" value="0.30" oninput="sbFloorMuChange()">
|
||
</div>
|
||
</div>
|
||
</details>
|
||
|
||
<details class="dyn-acc">
|
||
<summary>Отображение</summary>
|
||
<div class="dyn-acc-body">
|
||
<div class="dyn-checks">
|
||
<label><input type="checkbox" id="sb-forces" checked onchange="sbDisplayToggle()"> Силы</label>
|
||
<label><input type="checkbox" id="sb-vel" checked onchange="sbDisplayToggle()"> Скорости</label>
|
||
<label><input type="checkbox" id="sb-fbd" onchange="sbDisplayToggle()"> FBD-диаграмма</label>
|
||
<label><input type="checkbox" id="sb-energy" checked onchange="sbDisplayToggle()"> Энергия</label>
|
||
<label><input type="checkbox" id="sb-trail" checked onchange="sbDisplayToggle()"> Стробоскоп</label>
|
||
</div>
|
||
</div>
|
||
</details>
|
||
|
||
<details class="dyn-acc">
|
||
<summary>Время</summary>
|
||
<div class="dyn-acc-body">
|
||
<div class="dyn-row-4">
|
||
<button class="mag-mode-btn sb-time" onclick="sbTimeScale(0.25,this)">×0.25</button>
|
||
<button class="mag-mode-btn sb-time" onclick="sbTimeScale(0.5,this)">×0.5</button>
|
||
<button class="mag-mode-btn sb-time active" onclick="sbTimeScale(1,this)">×1</button>
|
||
<button class="mag-mode-btn sb-time" onclick="sbTimeScale(2,this)">×2</button>
|
||
</div>
|
||
</div>
|
||
</details>
|
||
|
||
<details class="dyn-acc" open>
|
||
<summary>Пресеты</summary>
|
||
<div class="dyn-acc-body">
|
||
<div class="dyn-preset-cat">Базовые</div>
|
||
<div class="dyn-preset-grp">
|
||
<button class="proj-preset-chip" onclick="sbPreset('freefall')">Падение</button>
|
||
<button class="proj-preset-chip" onclick="sbPreset('friction')">Трение</button>
|
||
<button class="proj-preset-chip" onclick="sbPreset('balance')">Равновесие</button>
|
||
<button class="proj-preset-chip" onclick="sbPreset('projectile_angle')">Снаряд 45°</button>
|
||
<button class="proj-preset-chip" onclick="sbPreset('circular_motion')">Круговое</button>
|
||
</div>
|
||
<div class="dyn-preset-cat">Столкновения</div>
|
||
<div class="dyn-preset-grp">
|
||
<button class="proj-preset-chip" onclick="sbPreset('collision')">Столкновение</button>
|
||
<button class="proj-preset-chip" onclick="sbPreset('elastic_collision')">Упругий</button>
|
||
<button class="proj-preset-chip" onclick="sbPreset('inelastic_collision')">Неупругий</button>
|
||
<button class="proj-preset-chip" onclick="sbPreset('newton_cradle')">Колыбель Ньютона</button>
|
||
</div>
|
||
<div class="dyn-preset-cat">Пружины и осцилляторы</div>
|
||
<div class="dyn-preset-grp">
|
||
<button class="proj-preset-chip" onclick="sbPreset('spring_bounce')">Пружина</button>
|
||
<button class="proj-preset-chip" onclick="sbPreset('spring_chain')">Цепочка</button>
|
||
<button class="proj-preset-chip" onclick="sbPreset('harmonic_oscillator')">Осциллятор</button>
|
||
<button class="proj-preset-chip" onclick="sbPreset('coupled_oscillators')">Связанные</button>
|
||
</div>
|
||
<div class="dyn-preset-cat">Маятники и блоки</div>
|
||
<div class="dyn-preset-grp">
|
||
<button class="proj-preset-chip" onclick="sbPreset('pendulum')">Маятник</button>
|
||
<button class="proj-preset-chip" onclick="sbPreset('double_pendulum')">Двойной маятник</button>
|
||
<button class="proj-preset-chip" onclick="sbPreset('atwood')">Атвуд</button>
|
||
<button class="proj-preset-chip" onclick="sbPreset('two_body')">Два тела</button>
|
||
<button class="proj-preset-chip" onclick="sbPreset('tug')">Перетягивание</button>
|
||
</div>
|
||
<div class="dyn-preset-cat">Горки и стопки</div>
|
||
<div class="dyn-preset-grp">
|
||
<button class="proj-preset-chip" onclick="sbPreset('ramp_slide')">Горка</button>
|
||
<button class="proj-preset-chip" onclick="sbPreset('ramp_angle')">Крутой спуск</button>
|
||
<button class="proj-preset-chip" onclick="sbPreset('ramp_friction')">Трение на горке</button>
|
||
<button class="proj-preset-chip" onclick="sbPreset('pulley_ramp')">Горка+блок</button>
|
||
<button class="proj-preset-chip" onclick="sbPreset('stacked_boxes')">Стопка</button>
|
||
</div>
|
||
</div>
|
||
</details>
|
||
|
||
<div style="font-size:.78rem;color:var(--text-2);line-height:1.55;margin-top:14px;padding:9px 11px;background:rgba(255,255,255,0.035);border-radius:8px;border:1px solid var(--border)">
|
||
<b style="color:var(--violet);font-size:.78rem;display:block;margin-bottom:4px">Управление</b>
|
||
ЛКМ — создать тело · Drag — сила<br>
|
||
Shift+drag — импульс · ПКМ — удалить<br>
|
||
DblClick — закрепить / открепить<br>
|
||
Пружина / Нить — кликни 2 тела
|
||
</div>
|
||
|
||
<!-- Sandbox graphs toggle -->
|
||
<div style="margin-top:10px">
|
||
<button id="btn-sandbox-graphs" onclick="sandboxToggleGraphs()" style="width:100%;font-size:.82rem;font-weight:700;padding:8px;border-radius:8px;border:1px solid rgba(6,214,224,0.35);background:rgba(6,214,224,0.1);color:#06D6E0;cursor:pointer">Графики тела</button>
|
||
</div>
|
||
|
||
<!-- Energy bars toggle — sandbox -->
|
||
<button id="fsb-energy-btn" class="proj-preset-chip" onclick="fsbToggleEnergy()" style="width:100%;font-size:.82rem;text-align:left;display:flex;align-items:center;gap:7px;margin-top:8px;padding:8px 11px">
|
||
<svg class="ic" viewBox="0 0 24 24"><path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/></svg>
|
||
<span>Энергия+: Выкл</span>
|
||
</button>
|
||
|
||
</div><!-- /#dyn-sandbox-panel -->
|
||
|
||
</div><!-- /.proj-panel -->
|
||
|
||
<div class="proj-canvas-outer">
|
||
<canvas id="newton-canvas" style="display:none;position:absolute;top:0;left:0;width:100%;height:100%;cursor:default"></canvas>
|
||
<canvas id="sandbox-canvas" style="display:block;position:absolute;top:0;left:0;width:100%;height:100%;cursor:crosshair"></canvas>
|
||
</div>
|
||
|
||
</div><!-- /.sim-body-wrap -->
|
||
|
||
<div class="proj-stats-bar" id="dyn-stats-bar">
|
||
<div class="pstat"><div class="pstat-label" id="dbar-l1">Тел</div><div class="pstat-val" id="dbar-v1" style="color:var(--cyan)">0</div></div>
|
||
<div class="pstat"><div class="pstat-label" id="dbar-l2">KE (Дж)</div><div class="pstat-val" id="dbar-v2" style="color:#4CC9F0">0</div></div>
|
||
<div class="pstat"><div class="pstat-label" id="dbar-l3">PE (Дж)</div><div class="pstat-val" id="dbar-v3" style="color:#7BF5A4">0</div></div>
|
||
<div class="pstat"><div class="pstat-label" id="dbar-l4">ΣF</div><div class="pstat-val" id="dbar-v4" style="color:#EF476F">—</div></div>
|
||
<div class="pstat"><div class="pstat-label" id="dbar-l5">Время</div><div class="pstat-val" id="dbar-v5" style="color:#FFD166">0 с</div></div>
|
||
</div>
|
||
</div><!-- /#sim-dynamics -->
|
||
|
||
<!-- ── PROJECTILE sim body ── -->
|
||
<div id="sim-proj" class="sim-proj-wrap" style="display:none">
|
||
<div class="sim-body-wrap">
|
||
|
||
<!-- controls panel -->
|
||
<div class="proj-panel" style="width:240px">
|
||
<div class="gp-section-title">Параметры</div>
|
||
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Скорость v₀</span>
|
||
<span class="param-val" id="p-v0">20 м/с</span>
|
||
</div>
|
||
<input type="range" class="param-slider" id="sl-v0" min="1" max="100" value="20" oninput="projParam()">
|
||
</div>
|
||
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Угол θ</span>
|
||
<span class="param-val" id="p-angle">45°</span>
|
||
</div>
|
||
<input type="range" class="param-slider" id="sl-angle" min="0" max="90" value="45" oninput="projParam()">
|
||
</div>
|
||
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Высота h₀</span>
|
||
<span class="param-val" id="p-h0">2 м</span>
|
||
</div>
|
||
<input type="range" class="param-slider" id="sl-h0" min="0" max="50" value="2" oninput="projParam()">
|
||
</div>
|
||
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Сила тяжести g</span>
|
||
<span class="param-val" id="p-g">9.81 м/с²</span>
|
||
</div>
|
||
<input type="range" class="param-slider" id="sl-g" min="1" max="25" step="0.01" value="9.81" oninput="projParam()">
|
||
</div>
|
||
|
||
<!-- Air resistance -->
|
||
<div class="gp-section-title" style="margin-top:6px">Сопротивление воздуха</div>
|
||
<label class="tri-layer-row" id="drag-row" onclick="projToggleDrag(this)" style="margin-bottom:6px">
|
||
<span class="tri-dot" style="background:rgba(239,71,111,0.5)"></span>
|
||
<span class="tri-layer-name">Воздух</span>
|
||
<span class="tri-toggle" id="drag-toggle" style="background:rgba(255,255,255,0.12)"><span style="display:block;width:12px;height:12px;border-radius:50%;background:#fff;margin:2px;margin-left:2px"></span></span>
|
||
</label>
|
||
<div id="drag-params" style="display:none">
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Коэф. Cd</span>
|
||
<span class="param-val" id="p-cd">0.30</span>
|
||
</div>
|
||
<input type="range" class="param-slider" id="sl-cd" min="1" max="100" value="30" oninput="projCdChange()">
|
||
</div>
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Масса тела m</span>
|
||
<span class="param-val" id="p-mass">1 кг</span>
|
||
</div>
|
||
<input type="range" class="param-slider" id="sl-mass" min="1" max="20" value="1" oninput="projMassChange()">
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Wind -->
|
||
<div class="gp-section-title" style="margin-top:6px">Ветер</div>
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Скорость ветра</span>
|
||
<span class="param-val" id="p-wind">0 м/с</span>
|
||
</div>
|
||
<input type="range" class="param-slider" id="sl-wind" min="-20" max="20" value="0" step="1" oninput="projWindChange()">
|
||
</div>
|
||
|
||
<!-- Bounce -->
|
||
<div class="gp-section-title" style="margin-top:6px">Отскок</div>
|
||
<label class="tri-layer-row" id="bounce-row" onclick="projToggleBounce(this)" style="margin-bottom:6px">
|
||
<span class="tri-dot" style="background:rgba(123,245,164,0.5)"></span>
|
||
<span class="tri-layer-name">Отскок при ударе</span>
|
||
<span class="tri-toggle" id="bounce-toggle" style="background:rgba(255,255,255,0.12)"><span style="display:block;width:12px;height:12px;border-radius:50%;background:#fff;margin:2px;margin-left:2px;transition:margin-left .15s"></span></span>
|
||
</label>
|
||
<div id="bounce-params" style="display:none">
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Коэф. упругости e</span>
|
||
<span class="param-val" id="p-restitution">0.70</span>
|
||
</div>
|
||
<input type="range" class="param-slider" id="sl-restitution" min="0" max="100" value="70" oninput="projRestitutionChange()">
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Parachute -->
|
||
<div class="gp-section-title" style="margin-top:6px">Парашют</div>
|
||
<label class="tri-layer-row" id="chute-row" onclick="projToggleParachute(this)" style="margin-bottom:6px">
|
||
<span class="tri-dot" style="background:rgba(6,214,224,0.5)"></span>
|
||
<span class="tri-layer-name">Парашют</span>
|
||
<span class="tri-toggle" id="chute-toggle" style="background:rgba(255,255,255,0.12)"><span style="display:block;width:12px;height:12px;border-radius:50%;background:#fff;margin:2px;margin-left:2px;transition:margin-left .15s"></span></span>
|
||
</label>
|
||
<div id="chute-params" style="display:none">
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Площадь A</span>
|
||
<span class="param-val" id="p-chute-area">1.0 м²</span>
|
||
</div>
|
||
<input type="range" class="param-slider" id="sl-chute-area" min="1" max="100" value="10" oninput="projChuteAreaChange()">
|
||
</div>
|
||
<div class="param-block" style="margin-bottom:6px">
|
||
<span class="param-name" style="font-size:.68rem">Форма (Cd)</span>
|
||
<select id="sel-chute-cd" onchange="projChuteCdChange()" style="width:100%;margin-top:4px;background:#0d0d2a;color:#fff;border:1px solid rgba(255,255,255,.15);border-radius:6px;padding:4px 6px;font-size:.75rem">
|
||
<option value="1.5" selected>Парашют (1.5)</option>
|
||
<option value="1.05">Куб (1.05)</option>
|
||
<option value="0.47">Сфера (0.47)</option>
|
||
<option value="0.42">Полусфера (0.42)</option>
|
||
<option value="1.17">Плоский диск (1.17)</option>
|
||
</select>
|
||
</div>
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Раскрыть на h</span>
|
||
<span class="param-val" id="p-chute-height">Сразу</span>
|
||
</div>
|
||
<input type="range" class="param-slider" id="sl-chute-height" min="0" max="100" value="0" oninput="projChuteHeightChange()">
|
||
<div style="font-size:.6rem;color:var(--text-3);margin-top:2px">0 = немедленно, >0 = раскрыть на этой высоте</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Ramp -->
|
||
<div class="gp-section-title" style="margin-top:6px">Наклонная горка</div>
|
||
<label class="tri-layer-row" id="ramp-row" onclick="projToggleRamp(this)" style="margin-bottom:6px">
|
||
<span class="tri-dot" style="background:rgba(255,180,50,0.5)"></span>
|
||
<span class="tri-layer-name">Старт с горки</span>
|
||
<span class="tri-toggle" id="ramp-toggle" style="background:rgba(255,255,255,0.12)"><span style="display:block;width:12px;height:12px;border-radius:50%;background:#fff;margin:2px;margin-left:2px;transition:margin-left .15s"></span></span>
|
||
</label>
|
||
<div id="ramp-params" style="display:none">
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Угол горки α</span>
|
||
<span class="param-val" id="p-ramp-angle">30°</span>
|
||
</div>
|
||
<input type="range" class="param-slider" id="sl-ramp-angle" min="5" max="85" value="30" oninput="projRampChange()">
|
||
</div>
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Длина L</span>
|
||
<span class="param-val" id="p-ramp-length">10 м</span>
|
||
</div>
|
||
<input type="range" class="param-slider" id="sl-ramp-length" min="1" max="50" value="10" oninput="projRampChange()">
|
||
</div>
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Трение μ</span>
|
||
<span class="param-val" id="p-ramp-mu">0.10</span>
|
||
</div>
|
||
<input type="range" class="param-slider" id="sl-ramp-mu" min="0" max="80" value="10" oninput="projRampChange()">
|
||
<div style="font-size:.6rem;color:var(--text-3);margin-top:2px">v = sqrt(2gL(sinα − μ cosα))</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Planet -->
|
||
<div class="gp-section-title" style="margin-top:6px">Планета / гравитация</div>
|
||
<div class="param-block" style="margin-bottom:6px">
|
||
<select id="sel-planet" onchange="projPlanetChange()" style="width:100%;background:#0d0d2a;color:#fff;border:1px solid rgba(255,255,255,.15);border-radius:6px;padding:4px 6px;font-size:.75rem">
|
||
<option value="earth" selected>Земля — g=9.81</option>
|
||
<option value="moon">Луна — g=1.62</option>
|
||
<option value="mars">Марс — g=3.71</option>
|
||
<option value="venus">Венера — g=8.87</option>
|
||
<option value="jupiter">Юпитер — g=24.79</option>
|
||
<option value="mercury">Меркурий — g=3.7</option>
|
||
<option value="saturn">Сатурн — g=10.44</option>
|
||
<option value="uranus">Уран — g=8.69</option>
|
||
<option value="neptune">Нептун — g=11.15</option>
|
||
<option value="pluto">Плутон — g=0.62</option>
|
||
</select>
|
||
</div>
|
||
<button id="proj-planet-compare-btn" class="proj-preset-chip" onclick="projTogglePlanetCompare()" style="width:100%;text-align:left;display:flex;align-items:center;gap:6px;margin-bottom:4px">
|
||
<svg class="ic" viewBox="0 0 24 24"><circle cx="5" cy="12" r="3"/><circle cx="12" cy="5" r="3"/><circle cx="19" cy="19" r="3"/><line x1="5" y1="12" x2="12" y2="5"/><line x1="12" y1="5" x2="19" y2="19"/></svg>
|
||
<span>Сравн.планет: Выкл</span>
|
||
</button>
|
||
<div id="proj-planet-compare-panel" style="display:none;font-size:.65rem;color:rgba(255,255,255,.6);margin-bottom:4px">
|
||
<div style="display:flex;gap:4px;flex-direction:column">
|
||
<div style="display:flex;align-items:center;gap:6px">
|
||
<span style="color:#06D6E0;font-weight:700">1:</span>
|
||
<select onchange="projPlanetCompareChange(0,this.value)" style="flex:1;background:#0d0d2a;color:#06D6E0;border:1px solid rgba(6,214,224,.3);border-radius:4px;padding:2px 4px;font-size:.7rem">
|
||
<option value="earth" selected>Земля</option><option value="moon">Луна</option><option value="mars">Марс</option><option value="venus">Венера</option><option value="jupiter">Юпитер</option><option value="mercury">Меркурий</option><option value="saturn">Сатурн</option><option value="uranus">Уран</option><option value="neptune">Нептун</option><option value="pluto">Плутон</option>
|
||
</select>
|
||
</div>
|
||
<div style="display:flex;align-items:center;gap:6px">
|
||
<span style="color:#7BF5A4;font-weight:700">2:</span>
|
||
<select onchange="projPlanetCompareChange(1,this.value)" style="flex:1;background:#0d0d2a;color:#7BF5A4;border:1px solid rgba(123,245,164,.3);border-radius:4px;padding:2px 4px;font-size:.7rem">
|
||
<option value="earth">Земля</option><option value="moon" selected>Луна</option><option value="mars">Марс</option><option value="venus">Венера</option><option value="jupiter">Юпитер</option><option value="mercury">Меркурий</option><option value="saturn">Сатурн</option><option value="uranus">Уран</option><option value="neptune">Нептун</option><option value="pluto">Плутон</option>
|
||
</select>
|
||
</div>
|
||
<div style="display:flex;align-items:center;gap:6px">
|
||
<span style="color:#F15BB5;font-weight:700">3:</span>
|
||
<select onchange="projPlanetCompareChange(2,this.value)" style="flex:1;background:#0d0d2a;color:#F15BB5;border:1px solid rgba(241,91,181,.3);border-radius:4px;padding:2px 4px;font-size:.7rem">
|
||
<option value="earth">Земля</option><option value="moon">Луна</option><option value="mars" selected>Марс</option><option value="venus">Венера</option><option value="jupiter">Юпитер</option><option value="mercury">Меркурий</option><option value="saturn">Сатурн</option><option value="uranus">Уран</option><option value="neptune">Нептун</option><option value="pluto">Плутон</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<div class="gp-section-title" style="margin-top:6px">Пресеты</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:6px">
|
||
<button class="proj-preset-chip" onclick="projPreset(20,45,0,9.81)">Земля 45°</button>
|
||
<button class="proj-preset-chip" onclick="projPreset(20,30,0,9.81)">30°</button>
|
||
<button class="proj-preset-chip" onclick="projPreset(20,60,0,9.81)">60°</button>
|
||
<button class="proj-preset-chip" onclick="projPreset(20,45,15,9.81)">С высоты</button>
|
||
<button class="proj-preset-chip" onclick="projPreset(30,45,0,1.62)">Луна</button>
|
||
<button class="proj-preset-chip" onclick="projPreset(30,45,0,3.72)">Марс</button>
|
||
<button class="proj-preset-chip" onclick="projPreset(50,45,0,9.81)">Дальний</button>
|
||
<button class="proj-preset-chip" onclick="projPreset(20,90,0,9.81)">Вверх</button>
|
||
</div>
|
||
|
||
<!-- Speed -->
|
||
<div class="gp-section-title" style="margin-top:8px">Скорость симуляции</div>
|
||
<div style="display:flex;gap:5px;margin-bottom:8px">
|
||
<button class="mag-mode-btn proj-speed" onclick="projSetSpeed(0.25,this)" style="flex:1;font-size:.68rem">×0.25</button>
|
||
<button class="mag-mode-btn proj-speed" onclick="projSetSpeed(0.5,this)" style="flex:1;font-size:.68rem">×0.5</button>
|
||
<button class="mag-mode-btn proj-speed active" onclick="projSetSpeed(1,this)" style="flex:1;font-size:.68rem">×1</button>
|
||
<button class="mag-mode-btn proj-speed" onclick="projSetSpeed(2,this)" style="flex:1;font-size:.68rem">×2</button>
|
||
<button class="mag-mode-btn proj-speed" onclick="projSetSpeed(4,this)" style="flex:1;font-size:.68rem">×4</button>
|
||
</div>
|
||
|
||
<!-- Ghost trails -->
|
||
<div class="gp-section-title" style="margin-top:10px">Сравнение</div>
|
||
<div style="display:flex;gap:6px;flex-wrap:wrap">
|
||
<button class="proj-preset-chip" onclick="projSaveGhost()" style="border-color:rgba(255,214,102,.4);color:#FFD166">Зафиксировать</button>
|
||
<button class="proj-preset-chip" onclick="projClearGhosts()" style="border-color:rgba(255,255,255,.15)"><svg class="ic" viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg> Очистить следы</button>
|
||
</div>
|
||
<div style="font-size:.6rem;color:var(--text-3);margin-top:4px">Сохрани траекторию, измени параметры и сравни</div>
|
||
|
||
<!-- Feature 1: Target mode -->
|
||
<div class="gp-section-title" style="margin-top:10px">Режим целей</div>
|
||
<button id="proj-target-btn" class="proj-preset-chip" onclick="projToggleTargetMode()" style="width:100%;text-align:left;display:flex;align-items:center;gap:6px">
|
||
<svg class="ic" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="6"/><circle cx="12" cy="12" r="2"/></svg>
|
||
<span>Режим целей: Выкл</span>
|
||
</button>
|
||
<div id="proj-target-panel" style="display:none;margin-top:6px">
|
||
<button class="proj-preset-chip" onclick="projGenTargets()" style="width:100%;text-align:center">
|
||
<svg class="ic" viewBox="0 0 24 24"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>
|
||
Новые цели
|
||
</button>
|
||
<div id="proj-target-hud" style="font-size:.72rem;font-weight:700;color:#FFD166;margin-top:6px;text-align:center">Цели: 0/3 Попыток: 0</div>
|
||
</div>
|
||
|
||
<!-- Energy bars toggle -->
|
||
<div class="gp-section-title" style="margin-top:10px">Закон сохранения энергии</div>
|
||
<button id="proj-energy-btn" class="proj-preset-chip" onclick="projToggleEnergy()" style="width:100%;text-align:left;display:flex;align-items:center;gap:6px">
|
||
<svg class="ic" viewBox="0 0 24 24"><path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/></svg>
|
||
<span>Энергия: Выкл</span>
|
||
</button>
|
||
|
||
<!-- Feature 2: Graphs toggle -->
|
||
<div class="gp-section-title" style="margin-top:10px">Графики</div>
|
||
<button id="proj-graphs-btn" class="proj-preset-chip" onclick="projToggleGraphs()" style="width:100%;text-align:left;display:flex;align-items:center;gap:6px">
|
||
<svg class="ic" viewBox="0 0 24 24"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>
|
||
<span>x(t), y(t), vx(t), vy(t)</span>
|
||
</button>
|
||
|
||
<!-- Feature 3: Dual throw -->
|
||
<div class="gp-section-title" style="margin-top:10px">Двойной бросок</div>
|
||
<button id="proj-dual-btn" class="proj-preset-chip" onclick="projToggleDual()" style="width:100%;text-align:left;display:flex;align-items:center;gap:6px">
|
||
<svg class="ic" viewBox="0 0 24 24"><circle cx="8" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M8 15V9l10-6"/></svg>
|
||
<span>Двойной: Выкл</span>
|
||
</button>
|
||
<div id="proj-dual-panel" style="display:none;margin-top:6px">
|
||
<div style="font-size:.65rem;color:rgba(0,230,255,.8);font-weight:700;margin-bottom:4px">Тело 2 (cyan)</div>
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Скорость v₀₂</span>
|
||
<span class="param-val" id="p2-v0" style="color:#00E6FF">25 м/с</span>
|
||
</div>
|
||
<input type="range" class="param-slider proj-dual-slider" id="sl-p2-v0" min="1" max="100" value="25" oninput="projP2Param()">
|
||
</div>
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Угол θ₂</span>
|
||
<span class="param-val" id="p2-angle" style="color:#00E6FF">30°</span>
|
||
</div>
|
||
<input type="range" class="param-slider proj-dual-slider" id="sl-p2-angle" min="0" max="90" value="30" oninput="projP2Param()">
|
||
</div>
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Высота h₀₂</span>
|
||
<span class="param-val" id="p2-h0" style="color:#00E6FF">0 м</span>
|
||
</div>
|
||
<input type="range" class="param-slider proj-dual-slider" id="sl-p2-h0" min="0" max="50" value="0" oninput="projP2Param()">
|
||
</div>
|
||
</div>
|
||
|
||
<!-- LAUNCH BUTTON -->
|
||
<div style="margin-top:auto; padding-top:16px; display:flex; flex-direction:column; gap:8px;">
|
||
<button class="proj-launch-btn" id="proj-launch-main" onclick="projPlayPause()">
|
||
<svg id="proj-launch-icon" viewBox="0 0 24 24" width="20" height="20" fill="currentColor">
|
||
<polygon points="5 3 19 12 5 21 5 3"/>
|
||
</svg>
|
||
<span id="proj-launch-label">Запустить</span>
|
||
</button>
|
||
<button class="proj-reset-btn" onclick="pSim && pSim.reset(); _projSyncPlayBtn()">
|
||
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.2">
|
||
<path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/>
|
||
</svg>
|
||
Сброс
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- canvas -->
|
||
<div class="proj-canvas-outer">
|
||
<canvas id="proj-canvas"></canvas>
|
||
</div>
|
||
|
||
</div><!-- /.sim-body-wrap -->
|
||
|
||
<!-- graphs panel (Feature 2) -->
|
||
<div id="proj-graphs-panel" style="display:none;background:#05050e;border-top:1px solid rgba(255,255,255,.07)">
|
||
<canvas id="proj-graphs-canvas" class="proj-graphs-canvas"></canvas>
|
||
</div>
|
||
|
||
<!-- stats bar -->
|
||
<div class="proj-stats-bar">
|
||
<div class="pstat">
|
||
<div class="pstat-label">Дальность</div>
|
||
<div class="pstat-val" id="ps-range">—</div>
|
||
</div>
|
||
<div class="pstat">
|
||
<div class="pstat-label">Макс. высота</div>
|
||
<div class="pstat-val" id="ps-hmax">—</div>
|
||
</div>
|
||
<div class="pstat">
|
||
<div class="pstat-label">Время полёта</div>
|
||
<div class="pstat-val" id="ps-tf">—</div>
|
||
</div>
|
||
<div class="pstat">
|
||
<div class="pstat-label">Скор. удара</div>
|
||
<div class="pstat-val" id="ps-vland">—</div>
|
||
</div>
|
||
<div class="pstat">
|
||
<div class="pstat-label">Текущее t</div>
|
||
<div class="pstat-val" id="ps-t">0.00 с</div>
|
||
</div>
|
||
<div class="pstat">
|
||
<div class="pstat-label">Угол посадки</div>
|
||
<div class="pstat-val" id="ps-land-angle">—</div>
|
||
</div>
|
||
<div class="pstat" id="ps-loss-wrap" style="display:none">
|
||
<div class="pstat-label">Δ дальность</div>
|
||
<div class="pstat-val" id="ps-loss">—</div>
|
||
</div>
|
||
<!-- dual throw stats (Feature 3) -->
|
||
<div class="pstat" id="ps-p2-wrap" style="display:none">
|
||
<div class="pstat-label" style="color:rgba(0,230,255,.7)">Дальн. 2</div>
|
||
<div class="pstat-val" id="ps-p2-range" style="color:#00E6FF">—</div>
|
||
</div>
|
||
<div class="pstat" id="ps-p2-tf-wrap" style="display:none">
|
||
<div class="pstat-label" style="color:rgba(0,230,255,.7)">Время 2</div>
|
||
<div class="pstat-val" id="ps-p2-tf" style="color:#00E6FF">—</div>
|
||
</div>
|
||
</div>
|
||
</div><!-- /#sim-proj -->
|
||
|
||
<!-- ── COLLISION sim body ── -->
|
||
<div id="sim-coll" class="sim-proj-wrap" style="display:none">
|
||
<div class="sim-body-wrap">
|
||
|
||
<!-- controls panel -->
|
||
<div class="proj-panel" style="width:240px">
|
||
<div class="gp-section-title">Параметры</div>
|
||
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name" style="color:var(--violet)">Масса m₁</span>
|
||
<span class="param-val" id="c-m1">4 кг</span>
|
||
</div>
|
||
<input type="range" class="param-slider" id="sl-m1" min="1" max="20" value="4" oninput="collParam()">
|
||
</div>
|
||
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name" style="color:var(--cyan)">Масса m₂</span>
|
||
<span class="param-val" id="c-m2">4 кг</span>
|
||
</div>
|
||
<input type="range" class="param-slider" id="sl-m2" min="1" max="20" value="4" oninput="collParam()">
|
||
</div>
|
||
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name" style="color:var(--violet)">Скорость v₁</span>
|
||
<span class="param-val" id="c-v1">8 м/с</span>
|
||
</div>
|
||
<input type="range" class="param-slider" id="sl-cv1" min="0" max="30" value="8" oninput="collParam()">
|
||
</div>
|
||
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name" style="color:var(--cyan)">Скорость v₂</span>
|
||
<span class="param-val" id="c-v2">8 м/с</span>
|
||
</div>
|
||
<input type="range" class="param-slider" id="sl-cv2" min="0" max="30" value="8" oninput="collParam()">
|
||
</div>
|
||
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Угол v₂</span>
|
||
<span class="param-val" id="c-angle">0°</span>
|
||
</div>
|
||
<input type="range" class="param-slider" id="sl-cangle" min="-60" max="60" value="0" oninput="collParam()">
|
||
</div>
|
||
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Упругость e</span>
|
||
<span class="param-val" id="c-e">1.00</span>
|
||
</div>
|
||
<input type="range" class="param-slider" id="sl-e" min="0" max="1" step="0.01" value="1" oninput="collParam()">
|
||
</div>
|
||
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name"><svg class="ic" viewBox="0 0 24 24"><polygon points="13 19 22 12 13 5 13 19"/><polygon points="2 19 11 12 2 5 2 19"/></svg> Скорость</span>
|
||
<span class="param-val" id="c-speed" style="color:var(--cyan)">1.00×</span>
|
||
</div>
|
||
<input type="range" class="param-slider" id="sl-speed" min="0.1" max="4" step="0.05" value="1"
|
||
oninput="collParam()" style="--track-color:#06D6E0">
|
||
</div>
|
||
|
||
<div class="gp-section-title" style="margin-top:6px">Пресеты</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:6px">
|
||
<button class="proj-preset-chip" onclick="collPreset(4,4,8,8,0,1)">Упругий 1:1</button>
|
||
<button class="proj-preset-chip" onclick="collPreset(4,4,8,8,0,0)">Абс. неупругий</button>
|
||
<button class="proj-preset-chip" onclick="collPreset(4,4,8,8,0,0.5)">e = 0.5</button>
|
||
<button class="proj-preset-chip" onclick="collPreset(4,4,12,0,0,1)">Бильярд</button>
|
||
<button class="proj-preset-chip" onclick="collPreset(2,8,14,0,0,1)">Лёгкий<svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>тяжёлый</button>
|
||
<button class="proj-preset-chip" onclick="collPreset(8,2,6,0,0,1)">Тяжёлый<svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>лёгкий</button>
|
||
<button class="proj-preset-chip" onclick="collPreset(2,14,18,0,0,1)">Большая разница</button>
|
||
<button class="proj-preset-chip" onclick="collPreset(5,5,8,8,30,1)">Косой 30°</button>
|
||
<button class="proj-preset-chip" onclick="collPreset(5,5,8,8,50,0.8)">Скользящий</button>
|
||
<button class="proj-preset-chip" onclick="collPreset(6,6,10,10,0,0)">Слипание</button>
|
||
</div>
|
||
|
||
<!-- graphs toggle -->
|
||
<div style="margin-top:10px">
|
||
<button id="btn-coll-graphs" onclick="collToggleGraphs()" style="width:100%;font-size:.75rem;padding:5px;border-radius:8px;border:1px solid rgba(6,214,224,0.3);background:rgba(6,214,224,0.08);color:#06D6E0;cursor:pointer">Графики скоростей</button>
|
||
</div>
|
||
|
||
<!-- Energy bars toggle -->
|
||
<div class="gp-section-title" style="margin-top:10px">Закон сохранения энергии</div>
|
||
<button id="coll-energy-btn" class="proj-preset-chip" onclick="collToggleEnergy()" style="width:100%;text-align:left;display:flex;align-items:center;gap:6px">
|
||
<svg class="ic" viewBox="0 0 24 24"><path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/></svg>
|
||
<span>Энергия: Выкл</span>
|
||
</button>
|
||
|
||
<!-- launch button -->
|
||
<div style="margin-top:auto; padding-top:16px; display:flex; flex-direction:column; gap:8px;">
|
||
<button class="proj-launch-btn" id="coll-launch-main" onclick="collPlayPause()">
|
||
<svg id="coll-launch-icon" viewBox="0 0 24 24" width="20" height="20" fill="currentColor">
|
||
<polygon points="5 3 19 12 5 21 5 3"/>
|
||
</svg>
|
||
<span id="coll-launch-label">Запустить</span>
|
||
</button>
|
||
<button class="proj-reset-btn" onclick="var _rs=_activeSim&&_activeSim();if(_rs)_rs.reset();_collSyncBtn()">
|
||
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.2">
|
||
<path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/>
|
||
</svg>
|
||
Сброс
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- canvas -->
|
||
<div class="proj-canvas-outer">
|
||
<canvas id="coll-canvas"></canvas>
|
||
</div>
|
||
|
||
</div><!-- /.sim-body-wrap -->
|
||
|
||
<!-- stats bar -->
|
||
<div class="proj-stats-bar">
|
||
<div class="pstat">
|
||
<div class="pstat-label">Импульс до</div>
|
||
<div class="pstat-val" id="cs-pbefore">—</div>
|
||
</div>
|
||
<div class="pstat">
|
||
<div class="pstat-label">Импульс после</div>
|
||
<div class="pstat-val" id="cs-pafter">—</div>
|
||
</div>
|
||
<div class="pstat">
|
||
<div class="pstat-label">КЭ до</div>
|
||
<div class="pstat-val" id="cs-kebefore">—</div>
|
||
</div>
|
||
<div class="pstat">
|
||
<div class="pstat-label">КЭ после</div>
|
||
<div class="pstat-val" id="cs-keafter">—</div>
|
||
</div>
|
||
<div class="pstat">
|
||
<div class="pstat-label">Столкновений</div>
|
||
<div class="pstat-val" id="cs-count">0</div>
|
||
</div>
|
||
</div>
|
||
</div><!-- /#sim-coll -->
|
||
|
||
<!-- ── CRYSTAL sim body ── -->
|
||
<div id="sim-crystal" class="sim-body-wrap" style="display:none">
|
||
<div class="graph-panel">
|
||
<div class="gp-section-title">Тип решётки</div>
|
||
<button class="gp-btn crystal-type-btn active" id="crys-nacl" onclick="setCrystal('nacl',this)" style="margin-bottom:6px"><svg class="ic" viewBox="0 0 24 24"><path d="M3 18a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V7H3z"/><path d="M3 7V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2v2"/><path d="M12 11v4M10 13h4"/></svg> NaCl (ионная)</button>
|
||
<button class="gp-btn crystal-type-btn" id="crys-diamond" onclick="setCrystal('diamond',this)" style="margin-bottom:6px"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="display:inline-block;vertical-align:middle"><path d="M6 3l-3 7 9 11 9-11-3-7H6z"/><path d="M3 10h18"/><path d="M12 21L6 3"/><path d="M12 21l6-18"/></svg> Алмаз (ковалентная)</button>
|
||
<button class="gp-btn crystal-type-btn" id="crys-bcc" onclick="setCrystal('bcc',this)" style="margin-bottom:6px">ОЦК (металл)</button>
|
||
<button class="gp-btn crystal-type-btn" id="crys-fcc" onclick="setCrystal('fcc',this)" style="margin-bottom:6px">ГЦК (металл)</button>
|
||
<div class="gp-section-title" style="margin-top:12px">Управление</div>
|
||
<div class="tp-text" style="font-size:0.72rem">Вращение: зажмите и тяните<br>Зум: колёсико мыши</div>
|
||
</div>
|
||
<div class="graph-canvas-outer">
|
||
<div class="graph-canvas-wrap" id="crystal-container"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── ORBITALS sim body ── -->
|
||
<div id="sim-orbitals" class="sim-body-wrap" style="display:none">
|
||
<div class="graph-panel">
|
||
<div class="gp-section-title">Орбиталь</div>
|
||
<button class="gp-btn orbital-mode-btn active" id="orb-s" onclick="setOrbital('s',this)" style="margin-bottom:6px"<span style="display:inline-block;width:10px;height:10px;border-radius:50%;background:#4CC9F0;margin-right:4px"></span>s-орбиталь</button>
|
||
<button class="gp-btn orbital-mode-btn" id="orb-p" onclick="setOrbital('p',this)" style="margin-bottom:6px"<span style="display:inline-block;width:10px;height:10px;border-radius:50%;background:#06D6A0;margin-right:4px"></span>p-орбитали</button>
|
||
<button class="gp-btn orbital-mode-btn" id="orb-d" onclick="setOrbital('d',this)" style="margin-bottom:6px"<span style="display:inline-block;width:10px;height:10px;border-radius:50%;background:#FFD166;margin-right:4px"></span>d-орбитали</button>
|
||
<div class="gp-section-title" style="margin-top:12px">Молекулы</div>
|
||
<button class="gp-btn orbital-mode-btn" id="orb-h2" onclick="setOrbital('h2',this)" style="margin-bottom:6px">H₂ (σ-связь)</button>
|
||
<button class="gp-btn orbital-mode-btn" id="orb-h2o" onclick="setOrbital('h2o',this)" style="margin-bottom:6px">H₂O (угловая)</button>
|
||
<div class="gp-section-title" style="margin-top:12px">Управление</div>
|
||
<div class="tp-text" style="font-size:0.72rem">Вращение: зажмите и тяните<br>Зум: колёсико мыши</div>
|
||
</div>
|
||
<div class="graph-canvas-outer">
|
||
<div class="graph-canvas-wrap" id="orbitals-container"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── CHEM SANDBOX sim body ── -->
|
||
<div id="sim-chemsandbox" class="sim-proj-wrap" style="display:none">
|
||
<div class="sim-body-wrap">
|
||
<div class="proj-panel" style="width:220px;gap:0">
|
||
<!-- Category filter -->
|
||
<div class="gp-section-title" style="margin-bottom:6px">Реагенты</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:3px;margin-bottom:10px">
|
||
<button class="proj-preset-chip reac-mode-btn chemsand-cat active" onclick="chemSandCat('all',this)">Все</button>
|
||
<button class="proj-preset-chip reac-mode-btn chemsand-cat" onclick="chemSandCat('acid',this)">Кислоты</button>
|
||
<button class="proj-preset-chip reac-mode-btn chemsand-cat" onclick="chemSandCat('base',this)">Основания</button>
|
||
<button class="proj-preset-chip reac-mode-btn chemsand-cat" onclick="chemSandCat('salt',this)">Соли</button>
|
||
<button class="proj-preset-chip reac-mode-btn chemsand-cat" onclick="chemSandCat('metal',this)">Металлы</button>
|
||
<button class="proj-preset-chip reac-mode-btn chemsand-cat" onclick="chemSandCat('indicator',this)">Индикаторы</button>
|
||
<button class="proj-preset-chip reac-mode-btn chemsand-cat" onclick="chemSandCat('other',this)">Другое</button>
|
||
</div>
|
||
<!-- Reagent list -->
|
||
<div id="chemsand-reagents" style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:12px;max-height:180px;overflow-y:auto"></div>
|
||
<!-- Presets -->
|
||
<div class="gp-section-title" style="margin-bottom:6px">Пресеты</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:10px">
|
||
<button class="proj-preset-chip" onclick="chemSandPreset('neutralization')">Нейтрализация</button>
|
||
<button class="proj-preset-chip" onclick="chemSandPreset('gas_evolution')">Газ CO₂</button>
|
||
<button class="proj-preset-chip" onclick="chemSandPreset('precipitate')">Осадок AgCl</button>
|
||
<button class="proj-preset-chip" onclick="chemSandPreset('displacement')">Замещение Cu</button>
|
||
<button class="proj-preset-chip" onclick="chemSandPreset('indicator')">Индикатор</button>
|
||
<button class="proj-preset-chip" onclick="chemSandPreset('violent')">Na + H₂O</button>
|
||
<button class="proj-preset-chip" onclick="chemSandPreset('yellow_precip')">PbCrO₄<svg class="ic" viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><polyline points="19 12 12 19 5 12"/></svg></button>
|
||
<button class="proj-preset-chip" onclick="chemSandPreset('blue_precip')">Cu(OH)₂<svg class="ic" viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><polyline points="19 12 12 19 5 12"/></svg></button>
|
||
</div>
|
||
<!-- Sliders -->
|
||
<div class="gp-section-title" style="margin-bottom:4px;margin-top:4px">Условия</div>
|
||
<div class="param-block" style="margin-bottom:5px">
|
||
<div class="param-header"><span class="param-name" style="font-size:.7rem">Концентрация</span><span class="param-val" id="csand-conc-val" style="font-size:.7rem;min-width:40px">35%</span></div>
|
||
<input type="range" class="param-slider" id="sl-csand-conc" min="5" max="95" value="35" oninput="chemSandConcChange()">
|
||
</div>
|
||
<div class="param-block" style="margin-bottom:5px">
|
||
<div class="param-header"><span class="param-name" style="font-size:.7rem">Температура</span><span class="param-val" id="csand-temp-val" style="font-size:.7rem;min-width:40px">20°C</span></div>
|
||
<input type="range" class="param-slider" id="sl-csand-temp" min="0" max="100" value="20" oninput="chemSandTempChange()">
|
||
</div>
|
||
<!-- Quiz mode -->
|
||
<div class="pp-group" style="margin-top:8px">
|
||
<div class="pp-label" style="font-size:.65rem">Режим</div>
|
||
<div style="display:flex;gap:6px;align-items:center">
|
||
<button class="proj-preset-chip reac-mode-btn chemsand-mode active" id="csand-mode-free" onclick="chemSandSetMode('free',this)">Свободный</button>
|
||
<button class="proj-preset-chip reac-mode-btn chemsand-mode" id="csand-mode-quiz" onclick="chemSandSetMode('quiz',this)">Задания</button>
|
||
<span id="csand-quiz-score" style="font-size:.7rem;color:rgba(255,255,255,.4);margin-left:8px"></span>
|
||
</div>
|
||
<div id="csand-quiz-question" style="display:none;margin-top:6px;padding:6px 10px;border-radius:8px;background:rgba(155,93,229,.10);border:1px solid rgba(155,93,229,.25);font-size:.72rem;color:#C9A0FF;line-height:1.3"></div>
|
||
<div id="csand-quiz-result" style="display:none;margin-top:4px;font-size:.72rem;font-weight:700"></div>
|
||
<button id="csand-quiz-next" style="display:none;margin-top:4px" class="proj-preset-chip" onclick="chemSandQuizNext()">Следующее задание</button>
|
||
</div>
|
||
<!-- Hint -->
|
||
<div class="tp-text" style="font-size:.65rem;opacity:.4;line-height:1.3">Клик на панели — добавить/убрать · Drag с полки в колбу · ПКМ — сбросить</div>
|
||
</div>
|
||
<div class="proj-canvas-outer">
|
||
<canvas id="chemsandbox-canvas" style="display:block;position:absolute;top:0;left:0;width:100%;height:100%;cursor:default"></canvas>
|
||
<!-- equation overlay: shown when reaction fires -->
|
||
<div id="chemsand-eq-overlay" class="chemsand-eq-overlay">
|
||
<div id="chemsand-eq-type" class="chemsand-eq-type"></div>
|
||
<div class="chemsand-eq-row chemsand-eq-row--mol">
|
||
<span class="chemsand-eq-label">Молекулярное</span>
|
||
<span id="chemsand-eq-mol" class="chemsand-eq-text chemsand-eq-text--mol"></span>
|
||
</div>
|
||
<div class="chemsand-eq-row chemsand-eq-row--full">
|
||
<span class="chemsand-eq-label">Полное ионное</span>
|
||
<span id="chemsand-eq-full" class="chemsand-eq-text chemsand-eq-text--full"></span>
|
||
</div>
|
||
<div class="chemsand-eq-row chemsand-eq-row--net">
|
||
<span class="chemsand-eq-label">Сокращённое ионное</span>
|
||
<span id="chemsand-eq-net" class="chemsand-eq-text chemsand-eq-text--net"></span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!-- Stats bar -->
|
||
<div class="proj-stats-bar" id="chemsand-stats-bar">
|
||
<div class="pstat"><div class="pstat-label">В зоне</div><div class="pstat-val" id="csbar-v1" style="color:var(--cyan)">0</div></div>
|
||
<div class="pstat"><div class="pstat-label">Тип</div><div class="pstat-val" id="csbar-v3" style="color:#7BF5A4">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Уравнение</div><div class="pstat-val" id="csbar-v4" style="color:#EF476F">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Сокр. ионное</div><div class="pstat-val" id="csbar-v6" style="color:#9BD4FF">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Продукты</div><div class="pstat-val" id="csbar-v5" style="color:#4CC9F0">—</div></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── CELL DIVISION sim body ── -->
|
||
<div id="sim-celldivision" class="sim-proj-wrap" style="display:none">
|
||
<div class="sim-body-wrap">
|
||
<div class="proj-panel" style="width:200px;gap:0">
|
||
<div class="gp-section-title" style="margin-bottom:6px">Режим</div>
|
||
<div style="display:flex;gap:4px;margin-bottom:12px">
|
||
<button class="proj-preset-chip reac-mode-btn cd-mode-btn active" onclick="cdSetMode('mitosis',this)">Митоз</button>
|
||
<button class="proj-preset-chip reac-mode-btn cd-mode-btn" onclick="cdSetMode('meiosis',this)">Мейоз</button>
|
||
</div>
|
||
<div class="gp-section-title" style="margin-bottom:6px">Фазы</div>
|
||
<div id="cd-phase-dots" style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:12px"></div>
|
||
<div style="display:flex;gap:4px;margin-bottom:12px">
|
||
<button class="gp-btn" onclick="cdPrevPhase()" style="flex:1"><svg class="ic" viewBox="0 0 24 24"><polygon points="19 20 9 12 19 4 19 20"/></svg> Назад</button>
|
||
<button class="gp-btn" onclick="cdNextPhase()" style="flex:1">Далее <svg class="ic" viewBox="0 0 24 24"><polygon points="5 3 19 12 5 21 5 3"/></svg></button>
|
||
</div>
|
||
<button class="gp-btn" id="cd-auto-btn" onclick="cdAutoPlay(this)" style="width:100%;margin-bottom:10px"><svg class="ic" viewBox="0 0 24 24"><polygon points="5 3 19 12 5 21 5 3"/></svg> Авто</button>
|
||
<div class="pp-hint">Нажми фазу или используй кнопки для пошагового просмотра</div>
|
||
</div>
|
||
<div class="proj-canvas-outer">
|
||
<canvas id="celldiv-canvas" style="display:block;position:absolute;top:0;left:0;width:100%;height:100%"></canvas>
|
||
</div>
|
||
</div>
|
||
<div class="proj-stats-bar" id="cdbar">
|
||
<div class="pstat"><div class="pstat-label">Фаза</div><div class="pstat-val" id="cdbar-v1" style="color:#7BF5A4">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Хромосомы</div><div class="pstat-val" id="cdbar-v2" style="color:var(--cyan)">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">ДНК</div><div class="pstat-val" id="cdbar-v3" style="color:#FFD166">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Шаг</div><div class="pstat-val" id="cdbar-v4" style="color:#EF476F">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Режим</div><div class="pstat-val" id="cdbar-v5" style="color:var(--violet)">—</div></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── PHOTOSYNTHESIS sim body ── -->
|
||
<div id="sim-photosynthesis" class="sim-proj-wrap" style="display:none">
|
||
<div class="sim-body-wrap">
|
||
<div class="proj-panel" style="width:200px;gap:0">
|
||
<div class="gp-section-title" style="margin-bottom:6px">Процесс</div>
|
||
<div style="display:flex;gap:4px;margin-bottom:12px">
|
||
<button class="proj-preset-chip reac-mode-btn ps-mode-btn active" onclick="psSetMode('photo',this)">Фотосинтез</button>
|
||
<button class="proj-preset-chip reac-mode-btn ps-mode-btn" onclick="psSetMode('resp',this)">Дыхание</button>
|
||
</div>
|
||
<div class="gp-section-title" style="margin-bottom:4px">Интенсивность света</div>
|
||
<div class="sl-row" style="margin-bottom:10px">
|
||
<input type="range" id="sl-ps-light" min="0" max="100" value="70" oninput="psLightChange()" style="flex:1">
|
||
<span class="sl-val" id="ps-light-val">70%</span>
|
||
</div>
|
||
<div class="gp-section-title" style="margin-bottom:4px">Концентрация CO₂</div>
|
||
<div class="sl-row" style="margin-bottom:10px">
|
||
<input type="range" id="sl-ps-co2" min="0" max="100" value="50" oninput="psCO2Change()" style="flex:1">
|
||
<span class="sl-val" id="ps-co2-val">50%</span>
|
||
</div>
|
||
<button class="gp-btn" onclick="psReset()" style="width:100%;margin-top:4px"><svg class="ic" viewBox="0 0 24 24"><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 .49-4.12"/></svg> Сброс</button>
|
||
<div class="pp-hint" style="margin-top:10px">Меняй параметры и наблюдай за скоростью реакций</div>
|
||
</div>
|
||
<div class="proj-canvas-outer">
|
||
<canvas id="photosyn-canvas" style="display:block;position:absolute;top:0;left:0;width:100%;height:100%"></canvas>
|
||
</div>
|
||
</div>
|
||
<div class="proj-stats-bar" id="psbar">
|
||
<div class="pstat"><div class="pstat-label">АТФ/с</div><div class="pstat-val" id="psbar-v1" style="color:#FFD166">0</div></div>
|
||
<div class="pstat"><div class="pstat-label">O₂ выд.</div><div class="pstat-val" id="psbar-v2" style="color:#7BF5A4">0</div></div>
|
||
<div class="pstat"><div class="pstat-label">CO₂ усв.</div><div class="pstat-val" id="psbar-v3" style="color:var(--cyan)">0</div></div>
|
||
<div class="pstat"><div class="pstat-label">КПД</div><div class="pstat-val" id="psbar-v4" style="color:#EF476F">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Режим</div><div class="pstat-val" id="psbar-v5" style="color:var(--violet)">—</div></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── ANGRY BIRDS sim body ── -->
|
||
<div id="sim-angrybirds" class="sim-proj-wrap" style="display:none">
|
||
<div class="sim-body-wrap">
|
||
<div class="proj-panel" style="width:200px;gap:0">
|
||
<div class="gp-section-title" style="margin-bottom:6px">Уровень</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:6px" id="ab-level-btns">
|
||
<button class="proj-preset-chip reac-mode-btn ab-lvl-btn active" onclick="abLevel(0,this)">1</button>
|
||
<button class="proj-preset-chip reac-mode-btn ab-lvl-btn" onclick="abLevel(1,this)">2</button>
|
||
<button class="proj-preset-chip reac-mode-btn ab-lvl-btn" onclick="abLevel(2,this)">3</button>
|
||
<button class="proj-preset-chip reac-mode-btn ab-lvl-btn" onclick="abLevel(3,this)">4</button>
|
||
<button class="proj-preset-chip reac-mode-btn ab-lvl-btn" onclick="abLevel(4,this)">5</button>
|
||
<button class="proj-preset-chip reac-mode-btn ab-lvl-btn" onclick="abLevel(5,this)">6</button>
|
||
</div>
|
||
<button onclick="angryBirdsRestart()" style="width:100%;padding:6px 10px;border-radius:8px;border:1.5px solid rgba(255,255,255,.15);background:rgba(255,255,255,.06);color:#e0e0e0;font-size:.76rem;font-weight:700;cursor:pointer;margin-bottom:12px" title="Начать уровень заново"><svg class="ic" viewBox="0 0 24 24"><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 .49-4.12"/></svg> Сначала</button>
|
||
<div class="gp-section-title" style="margin-bottom:6px">Планеты</div>
|
||
<div style="display:flex;flex-direction:column;gap:5px;margin-bottom:14px">
|
||
<div style="display:flex;justify-content:space-between;align-items:center;padding:4px 8px;border-radius:7px;background:rgba(255,255,255,.06)">
|
||
<span style="font-size:.75rem;color:#e0e0e0"><svg class="ic" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg> Земля</span><span style="font-size:.72rem;color:var(--cyan);font-weight:700">9.81 м/с²</span>
|
||
</div>
|
||
<div style="display:flex;justify-content:space-between;align-items:center;padding:4px 8px;border-radius:7px;background:rgba(255,255,255,.06)">
|
||
<span style="font-size:.75rem;color:#e0e0e0"><svg class="ic" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10" fill="currentColor" stroke="none"/></svg> Луна</span><span style="font-size:.72rem;color:var(--cyan);font-weight:700">1.62 м/с²</span>
|
||
</div>
|
||
<div style="display:flex;justify-content:space-between;align-items:center;padding:4px 8px;border-radius:7px;background:rgba(255,255,255,.06)">
|
||
<span style="font-size:.75rem;color:#e0e0e0"><svg class="ic" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10" fill="currentColor" stroke="none"/></svg> Марс</span><span style="font-size:.72rem;color:var(--cyan);font-weight:700">3.71 м/с²</span>
|
||
</div>
|
||
<div style="display:flex;justify-content:space-between;align-items:center;padding:4px 8px;border-radius:7px;background:rgba(255,255,255,.06)">
|
||
<span style="font-size:.75rem;color:#e0e0e0"><svg class="ic" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10" fill="currentColor" stroke="none"/></svg> Юпитер</span><span style="font-size:.72rem;color:var(--cyan);font-weight:700">24.8 м/с²</span>
|
||
</div>
|
||
</div>
|
||
<div class="gp-section-title" style="margin-bottom:6px">Птицы</div>
|
||
<div style="display:flex;flex-direction:column;gap:5px;margin-bottom:14px">
|
||
<div style="display:flex;align-items:center;gap:8px;padding:4px 8px;border-radius:7px;background:rgba(255,255,255,.06)">
|
||
<span style="width:14px;height:14px;border-radius:50%;background:#e63946;flex-shrink:0;display:inline-block"></span>
|
||
<span style="font-size:.73rem;color:#e0e0e0">Красная — обычная</span>
|
||
</div>
|
||
<div style="display:flex;align-items:center;gap:8px;padding:4px 8px;border-radius:7px;background:rgba(255,255,255,.06)">
|
||
<span style="width:14px;height:14px;border-radius:50%;background:#888;flex-shrink:0;display:inline-block"></span>
|
||
<span style="font-size:.73rem;color:#e0e0e0">Тяжёлая — высокий урон</span>
|
||
</div>
|
||
<div style="display:flex;align-items:center;gap:8px;padding:4px 8px;border-radius:7px;background:rgba(255,255,255,.06)">
|
||
<span style="width:14px;height:14px;border-radius:50%;background:#ffd166;flex-shrink:0;display:inline-block"></span>
|
||
<span style="font-size:.73rem;color:#e0e0e0">Жёлтая — быстрая</span>
|
||
</div>
|
||
</div>
|
||
<div class="pp-hint">Тяни птицу мышью · отпусти — выстрел</div>
|
||
</div>
|
||
<div class="proj-canvas-outer">
|
||
<canvas id="angrybirds-canvas" style="display:block;position:absolute;top:0;left:0;width:100%;height:100%;cursor:crosshair"></canvas>
|
||
</div>
|
||
</div>
|
||
<div class="proj-stats-bar" id="abbar">
|
||
<div class="pstat"><div class="pstat-label">Уровень</div><div class="pstat-val" id="abbar-v1" style="color:var(--cyan)">1</div></div>
|
||
<div class="pstat"><div class="pstat-label">Птиц</div><div class="pstat-val" id="abbar-v2" style="color:#ffd166">3</div></div>
|
||
<div class="pstat"><div class="pstat-label">Свиней</div><div class="pstat-val" id="abbar-v3" style="color:#7bf5a4">1</div></div>
|
||
<div class="pstat"><div class="pstat-label">Очки</div><div class="pstat-val" id="abbar-v4" style="color:#ef476f">0</div></div>
|
||
<div class="pstat"><div class="pstat-label">Планета</div><div class="pstat-val" id="abbar-v5" style="color:var(--violet)">Земля <svg class="ic" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg></div></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── QUADRATIC sim body ── -->
|
||
<div id="sim-quadratic" class="sim-proj-wrap" style="display:none">
|
||
<div class="sim-body-wrap">
|
||
<div class="proj-panel" style="width:220px;gap:0">
|
||
<div class="gp-section-title" style="margin-bottom:8px">Коэффициенты</div>
|
||
<div class="proj-slider-row" style="margin-bottom:10px">
|
||
<label style="font-size:.78rem;color:#ccc;width:60px">a = <span id="quad-a-val" style="color:var(--violet);font-weight:700">1</span></label>
|
||
<input type="range" id="sl-quad-a" min="-5" max="5" step="0.1" value="1" oninput="quadParam('a',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:10px">
|
||
<label style="font-size:.78rem;color:#ccc;width:60px">b = <span id="quad-b-val" style="color:var(--cyan);font-weight:700">0</span></label>
|
||
<input type="range" id="sl-quad-b" min="-10" max="10" step="0.1" value="0" oninput="quadParam('b',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:10px">
|
||
<label style="font-size:.78rem;color:#ccc;width:60px">c = <span id="quad-c-val" style="color:var(--pink);font-weight:700">-1</span></label>
|
||
<input type="range" id="sl-quad-c" min="-10" max="10" step="0.1" value="-1" oninput="quadParam('c',this.value)" style="flex:1">
|
||
</div>
|
||
<div style="margin-top:8px"></div>
|
||
<div class="gp-section-title" style="margin-bottom:6px">Примеры</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:10px">
|
||
<button class="preset-btn" onclick="quadPreset(1,0,-4)">x²−4</button>
|
||
<button class="preset-btn" onclick="quadPreset(1,-2,1)">(x−1)²</button>
|
||
<button class="preset-btn" onclick="quadPreset(1,0,1)">x²+1</button>
|
||
<button class="preset-btn" onclick="quadPreset(-1,0,4)">−x²+4</button>
|
||
<button class="preset-btn" onclick="quadPreset(2,-3,-2)">2x²−3x−2</button>
|
||
<button class="preset-btn" onclick="quadPreset(0.5,1,-3)">½x²+x−3</button>
|
||
</div>
|
||
<div class="pp-hint">Скролл — зум · Тащи — панорама</div>
|
||
</div>
|
||
<div class="proj-canvas-outer">
|
||
<canvas id="quadratic-canvas"></canvas>
|
||
</div>
|
||
</div>
|
||
<div class="proj-stats-bar" id="quadbar">
|
||
<div class="pstat"><div class="pstat-label">Дискриминант</div><div class="pstat-val" id="qbar-v1" style="color:#FFD166">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Корни</div><div class="pstat-val" id="qbar-v2" style="color:#EF476F">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Вершина</div><div class="pstat-val" id="qbar-v3" style="color:var(--cyan)">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Уравнение</div><div class="pstat-val" id="qbar-v4" style="color:var(--violet)">—</div></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── NORMAL DISTRIBUTION sim body ── -->
|
||
<div id="sim-normaldist" class="sim-proj-wrap" style="display:none">
|
||
<div class="sim-body-wrap">
|
||
<div class="proj-panel" style="width:220px;gap:0">
|
||
<div class="gp-section-title" style="margin-bottom:8px">Параметры</div>
|
||
<div class="proj-slider-row" style="margin-bottom:10px">
|
||
<label style="font-size:.78rem;color:#ccc;width:60px">μ = <span id="nd-mu-val" style="color:var(--cyan);font-weight:700">0</span></label>
|
||
<input type="range" id="sl-nd-mu" min="-5" max="5" step="0.1" value="0" oninput="ndParam('mu',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:10px">
|
||
<label style="font-size:.78rem;color:#ccc;width:60px">σ = <span id="nd-sigma-val" style="color:var(--violet);font-weight:700">1</span></label>
|
||
<input type="range" id="sl-nd-sigma" min="0.2" max="4" step="0.1" value="1" oninput="ndParam('sigma',this.value)" style="flex:1">
|
||
</div>
|
||
<div style="margin-top:8px"></div>
|
||
<div class="gp-section-title" style="margin-bottom:6px">Закрасить область</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:10px">
|
||
<button class="preset-btn nd-shade-btn active" onclick="ndShade('1s',this)">μ ± 1σ</button>
|
||
<button class="preset-btn nd-shade-btn" onclick="ndShade('2s',this)">μ ± 2σ</button>
|
||
<button class="preset-btn nd-shade-btn" onclick="ndShade('3s',this)">μ ± 3σ</button>
|
||
<button class="preset-btn nd-shade-btn" onclick="ndShade('none',this)">Нет</button>
|
||
</div>
|
||
<div style="margin-top:8px"></div>
|
||
<div class="gp-section-title" style="margin-bottom:6px">Пресеты</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:10px">
|
||
<button class="preset-btn" onclick="ndPreset(0,1)">Стандартное</button>
|
||
<button class="preset-btn" onclick="ndPreset(0,0.5)">Узкое σ=0.5</button>
|
||
<button class="preset-btn" onclick="ndPreset(0,2)">Широкое σ=2</button>
|
||
<button class="preset-btn" onclick="ndPreset(3,1)">Сдвиг μ=3</button>
|
||
</div>
|
||
<div class="pp-hint">Наведи курсор — Z-score и плотность</div>
|
||
</div>
|
||
<div class="proj-canvas-outer">
|
||
<canvas id="normaldist-canvas"></canvas>
|
||
</div>
|
||
</div>
|
||
<div class="proj-stats-bar" id="ndbar">
|
||
<div class="pstat"><div class="pstat-label">μ</div><div class="pstat-val" id="ndbar-v1" style="color:var(--cyan)">0</div></div>
|
||
<div class="pstat"><div class="pstat-label">σ</div><div class="pstat-val" id="ndbar-v2" style="color:var(--violet)">1</div></div>
|
||
<div class="pstat"><div class="pstat-label">Пик f(μ)</div><div class="pstat-val" id="ndbar-v3" style="color:#FFD166">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Область</div><div class="pstat-val" id="ndbar-v4" style="color:#7BF5A4">—</div></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── GRAPH TRANSFORM sim body ── -->
|
||
<div id="sim-graphtransform" class="sim-proj-wrap" style="display:none">
|
||
<div class="sim-body-wrap">
|
||
<div class="proj-panel" style="width:230px;gap:0">
|
||
<div class="gp-section-title" style="margin-bottom:6px">Базовая функция f(x)</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:12px">
|
||
<button class="preset-btn gt-base-btn active" onclick="gtBase('sin',this)">sin x</button>
|
||
<button class="preset-btn gt-base-btn" onclick="gtBase('cos',this)">cos x</button>
|
||
<button class="preset-btn gt-base-btn" onclick="gtBase('x^2',this)">x²</button>
|
||
<button class="preset-btn gt-base-btn" onclick="gtBase('x^3',this)">x³</button>
|
||
<button class="preset-btn gt-base-btn" onclick="gtBase('sqrt',this)">√x</button>
|
||
<button class="preset-btn gt-base-btn" onclick="gtBase('|x|',this)">|x|</button>
|
||
<button class="preset-btn gt-base-btn" onclick="gtBase('1/x',this)">1/x</button>
|
||
</div>
|
||
<div class="gp-section-title" style="margin-bottom:6px">y = a · f(k·x + b) + c</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:55px">a = <span id="gt-a-val" style="color:var(--violet);font-weight:700">1</span></label>
|
||
<input type="range" id="sl-gt-a" min="-3" max="3" step="0.1" value="1" oninput="gtParam('a',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:55px">k = <span id="gt-k-val" style="color:var(--cyan);font-weight:700">1</span></label>
|
||
<input type="range" id="sl-gt-k" min="-3" max="3" step="0.1" value="1" oninput="gtParam('k',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:55px">b = <span id="gt-b-val" style="color:#FFD166;font-weight:700">0</span></label>
|
||
<input type="range" id="sl-gt-b" min="-5" max="5" step="0.1" value="0" oninput="gtParam('b',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:55px">c = <span id="gt-c-val" style="color:#EF476F;font-weight:700">0</span></label>
|
||
<input type="range" id="sl-gt-c" min="-5" max="5" step="0.1" value="0" oninput="gtParam('c',this.value)" style="flex:1">
|
||
</div>
|
||
<div style="margin-top:8px"></div>
|
||
<div class="gp-section-title" style="margin-bottom:6px">Эффекты</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:8px">
|
||
<button class="preset-btn" onclick="gtEffect(2,1,0,0)">Растяжение <svg class="ic" viewBox="0 0 24 24"><line x1="12" y1="21" x2="12" y2="3"/><polyline points="7 8 12 3 17 8"/><polyline points="17 16 12 21 7 16"/></svg></button>
|
||
<button class="preset-btn" onclick="gtEffect(1,2,0,0)">Сжатие <svg class="ic" viewBox="0 0 24 24"><line x1="3" y1="12" x2="21" y2="12"/><polyline points="8 17 3 12 8 7"/><polyline points="16 7 21 12 16 17"/></svg></button>
|
||
<button class="preset-btn" onclick="gtEffect(-1,1,0,0)">Отражение <svg class="ic" viewBox="0 0 24 24"><line x1="12" y1="21" x2="12" y2="3"/><polyline points="7 8 12 3 17 8"/><polyline points="17 16 12 21 7 16"/></svg></button>
|
||
<button class="preset-btn" onclick="gtEffect(1,-1,0,0)">Отражение <svg class="ic" viewBox="0 0 24 24"><line x1="3" y1="12" x2="21" y2="12"/><polyline points="8 17 3 12 8 7"/><polyline points="16 7 21 12 16 17"/></svg></button>
|
||
<button class="preset-btn" onclick="gtEffect(1,1,2,0)">Сдвиг <svg class="ic" viewBox="0 0 24 24"><line x1="19" y1="12" x2="5" y2="12"/><polyline points="12 19 5 12 12 5"/></svg></button>
|
||
<button class="preset-btn" onclick="gtEffect(1,1,0,3)">Сдвиг <svg class="ic" viewBox="0 0 24 24"><line x1="12" y1="19" x2="12" y2="5"/><polyline points="5 12 12 5 19 12"/></svg></button>
|
||
</div>
|
||
<button class="preset-btn" onclick="gtEffect(1,1,0,0)" style="width:100%;margin-top:4px">Сброс</button>
|
||
<div class="pp-hint">Скролл — зум · Тащи — панорама</div>
|
||
</div>
|
||
<div class="proj-canvas-outer">
|
||
<canvas id="graphtransform-canvas"></canvas>
|
||
</div>
|
||
</div>
|
||
<div class="proj-stats-bar" id="gtbar">
|
||
<div class="pstat"><div class="pstat-label">f(x)</div><div class="pstat-val" id="gtbar-v1" style="color:var(--cyan)">sin(x)</div></div>
|
||
<div class="pstat"><div class="pstat-label">a</div><div class="pstat-val" id="gtbar-v2" style="color:var(--violet)">1</div></div>
|
||
<div class="pstat"><div class="pstat-label">k</div><div class="pstat-val" id="gtbar-v3" style="color:var(--cyan)">1</div></div>
|
||
<div class="pstat"><div class="pstat-label">b</div><div class="pstat-val" id="gtbar-v4" style="color:#FFD166">0</div></div>
|
||
<div class="pstat"><div class="pstat-label">c</div><div class="pstat-val" id="gtbar-v5" style="color:#EF476F">0</div></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── PENDULUM sim body ── -->
|
||
<div id="sim-pendulum" class="sim-proj-wrap" style="display:none">
|
||
<!-- mode bar -->
|
||
<div style="display:flex;gap:4px;padding:6px 12px;background:rgba(22,22,38,0.8);flex-wrap:wrap;border-bottom:1px solid rgba(255,255,255,0.07)">
|
||
<button class="pend-mode-btn active" data-mode="math" onclick="pendSetMode('math')" style="font-size:.72rem;padding:3px 10px;border-radius:14px;border:1px solid rgba(255,255,255,0.15);background:rgba(155,93,229,0.2);color:#ccc;cursor:pointer">Математ.</button>
|
||
<button class="pend-mode-btn" data-mode="double" onclick="pendSetMode('double')" style="font-size:.72rem;padding:3px 10px;border-radius:14px;border:1px solid rgba(255,255,255,0.15);background:rgba(22,22,38,0.6);color:#ccc;cursor:pointer">Двойной</button>
|
||
<button class="pend-mode-btn" data-mode="coupled" onclick="pendSetMode('coupled')" style="font-size:.72rem;padding:3px 10px;border-radius:14px;border:1px solid rgba(255,255,255,0.15);background:rgba(22,22,38,0.6);color:#ccc;cursor:pointer">Связанные</button>
|
||
<button class="pend-mode-btn" data-mode="spring" onclick="pendSetMode('spring')" style="font-size:.72rem;padding:3px 10px;border-radius:14px;border:1px solid rgba(255,255,255,0.15);background:rgba(22,22,38,0.6);color:#ccc;cursor:pointer">Пружинный</button>
|
||
<button class="pend-mode-btn" data-mode="physical" onclick="pendSetMode('physical')" style="font-size:.72rem;padding:3px 10px;border-radius:14px;border:1px solid rgba(255,255,255,0.15);background:rgba(22,22,38,0.6);color:#ccc;cursor:pointer">Физич.</button>
|
||
<button class="pend-mode-btn" data-mode="foucault" onclick="pendSetMode('foucault')" style="font-size:.72rem;padding:3px 10px;border-radius:14px;border:1px solid rgba(255,255,255,0.15);background:rgba(22,22,38,0.6);color:#ccc;cursor:pointer">Фуко</button>
|
||
<button class="pend-mode-btn" data-mode="resonance" onclick="pendSetMode('resonance')" style="font-size:.72rem;padding:3px 10px;border-radius:14px;border:1px solid rgba(255,255,255,0.15);background:rgba(22,22,38,0.6);color:#ccc;cursor:pointer">Резонанс</button>
|
||
<button id="btn-pend-phase" onclick="pendTogglePhase()" style="font-size:.72rem;padding:3px 10px;border-radius:14px;border:1px solid rgba(255,255,255,0.15);background:rgba(22,22,38,0.6);color:#ccc;cursor:pointer;margin-left:auto">Фаз. портрет</button>
|
||
<button id="btn-pend-graphs" onclick="pendToggleGraphs()" style="font-size:.72rem;padding:3px 10px;border-radius:14px;border:1px solid rgba(6,214,224,0.3);background:rgba(6,214,224,0.08);color:#06D6E0;cursor:pointer">Графики</button>
|
||
</div>
|
||
<div class="sim-body-wrap">
|
||
<div class="proj-panel" style="width:230px;gap:0;overflow-y:auto;max-height:100%">
|
||
|
||
<!-- MATH params -->
|
||
<div class="pend-params" data-mode="math">
|
||
<div class="gp-section-title" style="margin-bottom:8px">Математич. маятник</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:55px">θ = <span id="pend-theta-val" style="color:var(--violet);font-weight:700">45</span>°</label>
|
||
<input type="range" id="sl-pend-theta" min="5" max="170" step="1" value="45" oninput="pendParam('theta',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:55px">L = <span id="pend-L-val" style="color:var(--cyan);font-weight:700">200</span></label>
|
||
<input type="range" id="sl-pend-L" min="60" max="300" step="5" value="200" oninput="pendParam('L',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:55px">g = <span id="pend-g-val" style="color:#FFD166;font-weight:700">9.81</span></label>
|
||
<input type="range" id="sl-pend-g" min="1" max="25" step="0.1" value="9.81" oninput="pendParam('g',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:70px">Затух. <span id="pend-damp-val" style="color:#EF476F;font-weight:700">0</span></label>
|
||
<input type="range" id="sl-pend-damp" min="0" max="2" step="0.05" value="0" oninput="pendParam('damping',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="gp-section-title" style="margin-bottom:6px;margin-top:8px">Пресеты</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:8px">
|
||
<button class="preset-btn" onclick="pendPreset(45,200,9.81,0)">Земля</button>
|
||
<button class="preset-btn" onclick="pendPreset(45,200,1.62,0)">Луна</button>
|
||
<button class="preset-btn" onclick="pendPreset(170,200,9.81,0)">Большой θ</button>
|
||
<button class="preset-btn" onclick="pendPreset(45,200,9.81,0.5)">Затухание</button>
|
||
</div>
|
||
<div class="pp-hint">Тащи грузик мышью для установки угла</div>
|
||
</div>
|
||
|
||
<!-- DOUBLE params -->
|
||
<div class="pend-params" data-mode="double" style="display:none">
|
||
<div class="gp-section-title" style="margin-bottom:8px">Двойной маятник</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:65px">L1 = <span id="pend-d-L1-val" style="color:var(--cyan);font-weight:700">130</span></label>
|
||
<input type="range" min="50" max="200" step="5" value="130" oninput="pendDoubleParam('L1',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:65px">L2 = <span id="pend-d-L2-val" style="color:var(--cyan);font-weight:700">100</span></label>
|
||
<input type="range" min="50" max="200" step="5" value="100" oninput="pendDoubleParam('L2',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:65px">m1 = <span id="pend-d-m1-val" style="color:#FFD166;font-weight:700">1.5</span></label>
|
||
<input type="range" min="0.5" max="4" step="0.1" value="1.5" oninput="pendDoubleParam('m1',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:65px">m2 = <span id="pend-d-m2-val" style="color:#FFD166;font-weight:700">1.0</span></label>
|
||
<input type="range" min="0.5" max="4" step="0.1" value="1.0" oninput="pendDoubleParam('m2',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:65px">θ1 = <span id="pend-d-th1-val" style="color:var(--violet);font-weight:700">108</span>°</label>
|
||
<input type="range" min="10" max="170" step="1" value="108" oninput="pendDoubleParam('th1',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:65px">θ2 = <span id="pend-d-th2-val" style="color:var(--violet);font-weight:700">72</span>°</label>
|
||
<input type="range" min="10" max="170" step="1" value="72" oninput="pendDoubleParam('th2',this.value)" style="flex:1">
|
||
</div>
|
||
<button id="btn-pend-ghost" onclick="pendToggleGhost()" style="width:100%;margin-top:6px;font-size:.75rem;padding:5px;border-radius:8px;border:1px solid rgba(239,71,111,0.4);background:rgba(239,71,111,0.1);color:#EF476F;cursor:pointer">Сравнить траектории (хаос)</button>
|
||
<div class="pp-hint" style="margin-top:6px">Чувствительность к нач. условиям (+0.001 рад)</div>
|
||
</div>
|
||
|
||
<!-- COUPLED params -->
|
||
<div class="pend-params" data-mode="coupled" style="display:none">
|
||
<div class="gp-section-title" style="margin-bottom:8px">Связанные маятники</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:65px">L = <span id="pend-cp-L-val" style="color:var(--cyan);font-weight:700">160</span></label>
|
||
<input type="range" min="80" max="260" step="5" value="160" oninput="pendCoupledParam('L',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:65px">k = <span id="pend-cp-k-val" style="color:#FFD166;font-weight:700">0.30</span></label>
|
||
<input type="range" min="0.01" max="2" step="0.01" value="0.3" oninput="pendCoupledParam('k',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:65px">θ1 = <span id="pend-cp-th1-val" style="color:var(--violet);font-weight:700">36</span>°</label>
|
||
<input type="range" min="5" max="90" step="1" value="36" oninput="pendCoupledParam('th1',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="pp-hint">θ2=0: энергия перекачивается от маятника 1 к маятнику 2 и обратно</div>
|
||
</div>
|
||
|
||
<!-- SPRING params -->
|
||
<div class="pend-params" data-mode="spring" style="display:none">
|
||
<div class="gp-section-title" style="margin-bottom:8px">Пружинный маятник</div>
|
||
<div style="display:flex;gap:4px;margin-bottom:10px">
|
||
<button class="sp-mode-btn active" data-m="vert" onclick="pendSpringMode('vert')" style="flex:1;font-size:.72rem;padding:4px;border-radius:8px;border:1px solid rgba(255,255,255,0.15);background:rgba(6,214,224,0.15);color:#06D6E0;cursor:pointer">Вертик.</button>
|
||
<button class="sp-mode-btn" data-m="horiz" onclick="pendSpringMode('horiz')" style="flex:1;font-size:.72rem;padding:4px;border-radius:8px;border:1px solid rgba(255,255,255,0.15);background:rgba(22,22,38,0.6);color:#ccc;cursor:pointer">Горизонт.</button>
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:65px">k = <span id="pend-sp-k-val" style="color:#FFD166;font-weight:700">20</span></label>
|
||
<input type="range" min="1" max="100" step="1" value="20" oninput="pendSpringParam('k',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:65px">m = <span id="pend-sp-m-val" style="color:var(--violet);font-weight:700">1</span> кг</label>
|
||
<input type="range" min="0.1" max="5" step="0.1" value="1" oninput="pendSpringParam('m',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:65px">x0 = <span id="pend-sp-x0-val" style="color:#EF476F;font-weight:700">8</span> см</label>
|
||
<input type="range" min="1" max="20" step="0.5" value="8" oninput="pendSpringParam('x0',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="pp-hint">T = 2π√(m/k) не зависит от g (горизонт.)</div>
|
||
</div>
|
||
|
||
<!-- PHYSICAL params -->
|
||
<div class="pend-params" data-mode="physical" style="display:none">
|
||
<div class="gp-section-title" style="margin-bottom:8px">Физический маятник</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:3px;margin-bottom:10px">
|
||
<button class="ph-shape-btn active" data-s="rod" onclick="pendPhysShape('rod')" style="font-size:.72rem;padding:3px 8px;border-radius:8px;border:1px solid rgba(155,93,229,0.4);background:rgba(155,93,229,0.15);color:#9B5DE5;cursor:pointer">Стержень</button>
|
||
<button class="ph-shape-btn" data-s="hoop" onclick="pendPhysShape('hoop')" style="font-size:.72rem;padding:3px 8px;border-radius:8px;border:1px solid rgba(255,255,255,0.15);background:rgba(22,22,38,0.6);color:#ccc;cursor:pointer">Обруч</button>
|
||
<button class="ph-shape-btn" data-s="disk" onclick="pendPhysShape('disk')" style="font-size:.72rem;padding:3px 8px;border-radius:8px;border:1px solid rgba(255,255,255,0.15);background:rgba(22,22,38,0.6);color:#ccc;cursor:pointer">Диск</button>
|
||
<button class="ph-shape-btn" data-s="rect" onclick="pendPhysShape('rect')" style="font-size:.72rem;padding:3px 8px;border-radius:8px;border:1px solid rgba(255,255,255,0.15);background:rgba(22,22,38,0.6);color:#ccc;cursor:pointer">Прямоуг.</button>
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:65px">L = <span id="pend-ph-L-val" style="color:var(--cyan);font-weight:700">200</span></label>
|
||
<input type="range" min="60" max="260" step="5" value="200" oninput="pendPhysParam('L',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:65px">θ = <span id="pend-ph-theta-val" style="color:var(--violet);font-weight:700">36</span>°</label>
|
||
<input type="range" min="5" max="120" step="1" value="36" oninput="pendPhysParam('theta',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:65px">Затух. <span id="pend-ph-damping-val" style="color:#EF476F;font-weight:700">0</span></label>
|
||
<input type="range" min="0" max="1" step="0.02" value="0" oninput="pendPhysParam('damping',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="pp-hint">T зависит от момента инерции I и расст. до ц.т. d</div>
|
||
</div>
|
||
|
||
<!-- FOUCAULT params -->
|
||
<div class="pend-params" data-mode="foucault" style="display:none">
|
||
<div class="gp-section-title" style="margin-bottom:8px">Маятник Фуко</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:65px">φ = <span id="pend-fc-phi-val" style="color:#FFD166;font-weight:700">45</span>°</label>
|
||
<input type="range" min="1" max="90" step="1" value="45" oninput="pendFoucaultParam('phi',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="pp-hint">Вид сверху. Плоскость качаний вращаетс�; из-за вращения Земли. T = 24 ч / sin(φ)</div>
|
||
<div class="pp-hint" style="color:#FFD166;margin-top:4px">Полюс (90°): оборот за 24 ч. Экватор: почти не вращается.</div>
|
||
</div>
|
||
|
||
<!-- RESONANCE params -->
|
||
<div class="pend-params" data-mode="resonance" style="display:none">
|
||
<div class="gp-section-title" style="margin-bottom:8px">Резонанс</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:70px">ω = <span id="pend-rs-dOmega-val" style="color:#EF476F;font-weight:700">1.50</span></label>
|
||
<input type="range" min="0.1" max="6" step="0.05" value="1.5" oninput="pendResonanceParam('dOmega',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:70px">F0 = <span id="pend-rs-F0-val" style="color:#FFD166;font-weight:700">0.80</span></label>
|
||
<input type="range" min="0.1" max="3" step="0.05" value="0.8" oninput="pendResonanceParam('F0',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:70px">γ = <span id="pend-rs-gamma-val" style="color:var(--cyan);font-weight:700">0.30</span></label>
|
||
<input type="range" min="0.01" max="2" step="0.01" value="0.3" oninput="pendResonanceParam('gamma',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:70px">L = <span id="pend-rs-L-val" style="color:var(--violet);font-weight:700">180</span></label>
|
||
<input type="range" min="60" max="300" step="5" value="180" oninput="pendResonanceParam('L',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="pp-hint">Красная стрелка — вынуждающая сила. Пик при ω ≈ ω₀.</div>
|
||
</div>
|
||
|
||
<!-- Energy bars toggle (shared across all pendulum modes) -->
|
||
<div class="gp-section-title" style="margin-top:10px">Закон сохранения энергии</div>
|
||
<button id="pend-energy-btn" class="proj-preset-chip" onclick="pendToggleEnergy()" style="width:100%;text-align:left;display:flex;align-items:center;gap:6px">
|
||
<svg class="ic" viewBox="0 0 24 24"><path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/></svg>
|
||
<span>Энергия: Выкл</span>
|
||
</button>
|
||
|
||
</div>
|
||
<div class="proj-canvas-outer">
|
||
<canvas id="pendulum-canvas"></canvas>
|
||
</div>
|
||
</div>
|
||
<div class="proj-stats-bar" id="pendbar">
|
||
<div class="pstat"><div class="pstat-label">Угол / коорд.</div><div class="pstat-val" id="pendbar-v1" style="color:var(--violet)">45°</div></div>
|
||
<div class="pstat"><div class="pstat-label">ω</div><div class="pstat-val" id="pendbar-v2" style="color:var(--cyan)">0</div></div>
|
||
<div class="pstat"><div class="pstat-label">Период T</div><div class="pstat-val" id="pendbar-v3" style="color:#FFD166">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Режим</div><div class="pstat-val" id="pendbar-v4" style="color:#EF476F">—</div></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── EQUILIBRIUM sim body ── -->
|
||
<div id="sim-equilibrium" class="sim-proj-wrap" style="display:none">
|
||
<div class="sim-body-wrap">
|
||
<div class="proj-panel" style="width:220px;gap:0">
|
||
<div class="gp-section-title" style="margin-bottom:8px">Параметры</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:55px">T = <span id="eq-T-val" style="color:#FFD166;font-weight:700">300</span> K</label>
|
||
<input type="range" id="sl-eq-T" min="200" max="500" step="10" value="300" oninput="eqParam('T',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:55px">Ea<svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg> <span id="eq-Eaf-val" style="color:#7BF5A4;font-weight:700">50</span></label>
|
||
<input type="range" id="sl-eq-Eaf" min="20" max="80" step="1" value="50" oninput="eqParam('Ea_f',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:55px">Ea<svg class="ic" viewBox="0 0 24 24"><line x1="19" y1="12" x2="5" y2="12"/><polyline points="12 19 5 12 12 5"/></svg> <span id="eq-Ear-val" style="color:#EF476F;font-weight:700">55</span></label>
|
||
<input type="range" id="sl-eq-Ear" min="20" max="80" step="1" value="55" oninput="eqParam('Ea_r',this.value)" style="flex:1">
|
||
</div>
|
||
<div style="margin-top:8px"></div>
|
||
<div class="gp-section-title" style="margin-bottom:6px">Пресеты</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:8px">
|
||
<button class="preset-btn" onclick="eqPreset('default')">По умолч.</button>
|
||
<button class="preset-btn" onclick="eqPreset('exothermic')">Экзо</button>
|
||
<button class="preset-btn" onclick="eqPreset('endothermic')">Эндо</button>
|
||
<button class="preset-btn" onclick="eqPreset('excess_A')">Избыток A</button>
|
||
</div>
|
||
<div class="pp-hint">A + B ⇌ C + D — принцип Ле Шателье</div>
|
||
</div>
|
||
<div class="proj-canvas-outer">
|
||
<canvas id="equilibrium-canvas"></canvas>
|
||
</div>
|
||
</div>
|
||
<div class="proj-stats-bar" id="eqbar">
|
||
<div class="pstat"><div class="pstat-label">Keq</div><div class="pstat-val" id="eqbar-v1" style="color:#7BF5A4">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Q</div><div class="pstat-val" id="eqbar-v2" style="color:#FFD166">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Направление</div><div class="pstat-val" id="eqbar-v3" style="color:var(--cyan)">⇌</div></div>
|
||
<div class="pstat"><div class="pstat-label">A|B|C|D</div><div class="pstat-val" id="eqbar-v4" style="color:var(--violet)">—</div></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── OPTICSBENCH sim body ── -->
|
||
<div id="sim-opticsbench" class="sim-proj-wrap" style="display:none;flex-direction:column">
|
||
<!-- Tab bar -->
|
||
<div style="display:flex;gap:0;border-bottom:1px solid #2a2a3e;background:#12121e;flex-shrink:0">
|
||
<button id="ob-tab-lens" onclick="obSwitchMode('lens')" class="ob-tab active" style="flex:1;padding:8px 0;border:none;background:transparent;color:#ccc;font-size:.78rem;font-weight:600;cursor:pointer;border-bottom:2px solid transparent;transition:all .15s">Тонкая линза</button>
|
||
<button id="ob-tab-mirror" onclick="obSwitchMode('mirror')" class="ob-tab" style="flex:1;padding:8px 0;border:none;background:transparent;color:#ccc;font-size:.78rem;font-weight:600;cursor:pointer;border-bottom:2px solid transparent;transition:all .15s">Зеркала</button>
|
||
<button id="ob-tab-refraction" onclick="obSwitchMode('refraction')" class="ob-tab" style="flex:1;padding:8px 0;border:none;background:transparent;color:#ccc;font-size:.78rem;font-weight:600;cursor:pointer;border-bottom:2px solid transparent;transition:all .15s">Преломление</button>
|
||
<button id="ob-tab-freebuild" onclick="obSwitchMode('freebuild')" class="ob-tab" style="flex:1;padding:8px 0;border:none;background:transparent;color:#ccc;font-size:.78rem;font-weight:600;cursor:pointer;border-bottom:2px solid transparent;transition:all .15s">Цепочка линз</button>
|
||
<button id="ob-tab-prism" onclick="obSwitchMode('prism')" class="ob-tab" style="flex:1;padding:8px 0;border:none;background:transparent;color:#ccc;font-size:.78rem;font-weight:600;cursor:pointer;border-bottom:2px solid transparent;transition:all .15s">Призма</button>
|
||
<button id="ob-tab-interf" onclick="obSwitchMode('interf')" class="ob-tab" style="flex:1;padding:8px 0;border:none;background:transparent;color:#ccc;font-size:.78rem;font-weight:600;cursor:pointer;border-bottom:2px solid transparent;transition:all .15s">Интерференция</button>
|
||
<button id="ob-tab-waves" onclick="obSwitchMode('waves')" class="ob-tab" style="flex:1;padding:8px 0;border:none;background:transparent;color:#ccc;font-size:.78rem;font-weight:600;cursor:pointer;border-bottom:2px solid transparent;transition:all .15s">Волны</button>
|
||
</div>
|
||
<!-- ── Wavelength slider bar (global) ── -->
|
||
<div id="ob-wavelength-bar" style="display:flex;align-items:center;gap:8px;padding:5px 10px;background:#0c0c1a;border-bottom:1px solid #1a1a30;flex-shrink:0">
|
||
<span style="font-size:.72rem;color:#aaa;font-weight:600;white-space:nowrap;flex-shrink:0">λ =</span>
|
||
<div id="ob-wl-slider-row" style="display:flex;align-items:center;gap:6px;flex:1;max-width:280px">
|
||
<span style="font-size:.68rem;color:#8080ff">380</span>
|
||
<input type="range" id="sl-ob-wavelength" min="380" max="780" step="5" value="550"
|
||
oninput="obSetWavelength(this.value)"
|
||
style="flex:1;accent-color:var(--violet)">
|
||
<span style="font-size:.68rem;color:#ff6060">780</span>
|
||
</div>
|
||
<span id="ob-wl-val" style="font-size:.75rem;font-weight:700;min-width:52px;color:#FFFFFF">550 нм</span>
|
||
<label style="display:flex;align-items:center;gap:4px;font-size:.72rem;color:#ccc;cursor:pointer;flex-shrink:0;white-space:nowrap">
|
||
<input type="checkbox" id="ob-white-toggle" onchange="obToggleWhiteLight(this.checked)">
|
||
Белый свет
|
||
</label>
|
||
</div>
|
||
<!-- ── Готовые сцены / Instruments preset bar ── -->
|
||
<div id="ob-presets-bar" style="display:flex;align-items:center;gap:6px;padding:6px 10px;background:#0f0f1c;border-bottom:1px solid #1e1e32;flex-shrink:0;flex-wrap:wrap">
|
||
<span style="font-size:.72rem;color:#666;font-weight:600;white-space:nowrap;flex-shrink:0">Приборы:</span>
|
||
<button class="ob-preset-chip" data-preset="magnifier" onclick="obLoadPreset('magnifier')" title="Лупа: d < f, мнимое увеличение">Лупа</button>
|
||
<button class="ob-preset-chip" data-preset="microscope" onclick="obLoadPreset('microscope')" title="Микроскоп: объектив f=10, d=14">Микроскоп</button>
|
||
<button class="ob-preset-chip" data-preset="keplerian" onclick="obLoadPreset('keplerian')" title="Телескоп Кеплера: fуб=200, fок=30">Тел. Кеплера</button>
|
||
<button class="ob-preset-chip" data-preset="galilean" onclick="obLoadPreset('galilean')" title="Телескоп Галилея: fок=-40">Тел. Галилея</button>
|
||
<button class="ob-preset-chip" data-preset="camera" onclick="obLoadPreset('camera')" title="Камера/Глаз: f=40, d=120">Камера</button>
|
||
<button class="ob-preset-chip" data-preset="periscope" onclick="obLoadPreset('periscope')" title="Перископ: плоское зеркало 45°">Перископ</button>
|
||
<button class="ob-preset-chip" data-preset="projector" onclick="obLoadPreset('projector')" title="Слайд-проектор: f=80, d=100">Проектор</button>
|
||
<button class="ob-preset-chip" data-preset="fiber" onclick="obLoadPreset('fiber')" title="Световод: ПВО, n=1.5 → n=1">Световод</button>
|
||
<button class="ob-preset-chip" data-preset="spoon" onclick="obLoadPreset('spoon')" title="Ложка в воде: преломление на границе">Ложка в воде</button>
|
||
<button class="ob-preset-chip ob-preset-clear" onclick="obClearPreset()" title="Вернуть начальные настройки" style="margin-left:auto">Очистить</button>
|
||
</div>
|
||
<!-- ── Эффекты panel (collapsible) ── -->
|
||
<details id="ob-fx-panel" class="ob-fx-panel">
|
||
<summary class="ob-fx-summary">
|
||
<svg class="ic" viewBox="0 0 16 16" width="12" height="12"><path d="M8 1a7 7 0 1 0 0 14A7 7 0 0 0 8 1zm0 2a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3zm0 4.5c1.7 0 3.2.85 4.1 2.15a5 5 0 0 1-8.2 0C4.8 8.35 6.3 7.5 8 7.5z"/></svg>
|
||
Эффекты
|
||
</summary>
|
||
<div class="ob-fx-row">
|
||
<label class="ob-fx-label">
|
||
<input type="checkbox" id="obfx-wavefronts" onchange="obFXToggle('wavefronts',this.checked)">
|
||
Волновые фронты вдоль лучей
|
||
</label>
|
||
<label class="ob-fx-label">
|
||
<input type="checkbox" id="obfx-mist" onchange="obFXToggle('mist',this.checked)">
|
||
Туман
|
||
</label>
|
||
<label class="ob-fx-label">
|
||
<input type="checkbox" id="obfx-flare" onchange="obFXToggle('flare',this.checked)">
|
||
Lens flare
|
||
</label>
|
||
<label class="ob-fx-label">
|
||
<input type="checkbox" id="obfx-huygens" onchange="obFXToggle('huygens',this.checked)">
|
||
Конструкция Гюйгенса
|
||
</label>
|
||
<label class="ob-fx-label">
|
||
<input type="checkbox" id="obfx-caustics" onchange="obFXToggle('caustics',this.checked)">
|
||
Каустики
|
||
</label>
|
||
</div>
|
||
</details>
|
||
<!-- Body row: control panels + shared canvas -->
|
||
<div style="display:flex;flex:1;min-height:0;overflow:hidden">
|
||
<!-- ── Lens control panel ── -->
|
||
<div id="ob-ctrl-lens" class="proj-panel" style="width:220px;gap:0;flex-shrink:0">
|
||
<div class="gp-section-title" style="margin-bottom:8px">Параметры</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:55px">f = <span id="lens-f-val" style="color:var(--cyan);font-weight:700">100</span></label>
|
||
<input type="range" id="sl-lens-f" min="-200" max="200" step="5" value="100" oninput="lensParam('f',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:55px">d = <span id="lens-d-val" style="color:var(--violet);font-weight:700">200</span></label>
|
||
<input type="range" id="sl-lens-d" min="30" max="400" step="5" value="200" oninput="lensParam('d',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:55px">h = <span id="lens-h-val" style="color:#EF476F;font-weight:700">50</span></label>
|
||
<input type="range" id="sl-lens-h" min="20" max="80" step="2" value="50" oninput="lensParam('h',this.value)" style="flex:1">
|
||
</div>
|
||
<div style="margin-top:8px"></div>
|
||
<div class="gp-section-title" style="margin-bottom:6px">Пресеты</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:8px">
|
||
<button class="preset-btn" onclick="lensPreset(100,200,50)">Собирающая</button>
|
||
<button class="preset-btn" onclick="lensPreset(-100,200,50)">Рассеивающая</button>
|
||
<button class="preset-btn" onclick="lensPreset(100,100,50)">d = f</button>
|
||
<button class="preset-btn" onclick="lensPreset(100,60,50)">d < f</button>
|
||
</div>
|
||
<div class="pp-hint">Тащи стрелку-предмет или фокус мышью</div>
|
||
<div style="margin-top:8px"></div>
|
||
<!-- Feature 1: animated ray buttons -->
|
||
<div style="display:flex;gap:4px;margin-bottom:8px">
|
||
<button onclick="if(lensSim)lensSim.buildRays()" style="flex:1;padding:5px 0;border-radius:6px;border:none;background:linear-gradient(135deg,#06D6E0,#9B5DE5);color:#fff;font-size:.72rem;font-weight:700;cursor:pointer">Построить лучи</button>
|
||
<button onclick="if(lensSim)lensSim.resetRays()" style="padding:5px 9px;border-radius:6px;border:1px solid #333;background:#1a1a2e;color:#888;font-size:.78rem;cursor:pointer" title="Сбросить лучи">↺</button>
|
||
</div>
|
||
<!-- Feature 3: lens-maker toggle -->
|
||
<div style="margin-bottom:6px">
|
||
<label style="display:flex;align-items:center;gap:6px;font-size:.72rem;color:#ccc;cursor:pointer">
|
||
<input type="checkbox" id="ltog-lensmaker" onchange="lensToggleLM(this.checked)">
|
||
Подробный (R1/R2/n)
|
||
</label>
|
||
</div>
|
||
<!-- LM sliders (hidden by default) -->
|
||
<div id="ob-lm-sliders" style="display:none">
|
||
<div class="proj-slider-row" style="margin-bottom:6px">
|
||
<label style="font-size:.72rem;color:#ccc;width:60px">R1 = <span id="lm-r1-val" style="color:#FFD166;font-weight:700">200</span></label>
|
||
<input type="range" id="sl-lm-r1" min="-300" max="300" step="5" value="200" oninput="lensLMParam('R1',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:6px">
|
||
<label style="font-size:.72rem;color:#ccc;width:60px">R2 = <span id="lm-r2-val" style="color:#FFD166;font-weight:700">-200</span></label>
|
||
<input type="range" id="sl-lm-r2" min="-300" max="300" step="5" value="-200" oninput="lensLMParam('R2',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.72rem;color:#ccc;width:60px">n = <span id="lm-n-val" style="color:#9B5DE5;font-weight:700">1.50</span></label>
|
||
<input type="range" id="sl-lm-n" min="1.3" max="2.4" step="0.05" value="1.5" oninput="lensLMParam('n',this.value)" style="flex:1">
|
||
</div>
|
||
<div style="font-size:.68rem;color:#888;margin-bottom:6px">f = 1/((n-1)*(1/R1 - 1/R2))</div>
|
||
</div>
|
||
<div style="margin-top:0"></div>
|
||
<div class="gp-section-title" style="margin-bottom:6px">Аберрации</div>
|
||
<div style="display:flex;flex-direction:column;gap:4px;margin-bottom:8px">
|
||
<label style="display:flex;align-items:center;gap:4px;font-size:.72rem;color:#ccc;cursor:pointer"><input type="checkbox" id="ltog-spherical" onchange="lensAberration('spherical',this.checked)"> Сферическая</label>
|
||
<label style="display:flex;align-items:center;gap:4px;font-size:.72rem;color:#ccc;cursor:pointer"><input type="checkbox" id="ltog-chromatic" onchange="lensAberration('chromatic',this.checked)"> Хроматическая</label>
|
||
</div>
|
||
</div>
|
||
<!-- ── Mirror control panel ── -->
|
||
<div id="ob-ctrl-mirror" class="proj-panel" style="width:264px;gap:0;flex-shrink:0;display:none">
|
||
<div class="gp-section-title" style="margin-bottom:8px">Тип зеркала</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:10px">
|
||
<button class="preset-btn mirror-type-btn" id="mtype-flat" onclick="mirrorType('flat',this)" style="font-size:.72rem">Плоское</button>
|
||
<button class="preset-btn mirror-type-btn active" id="mtype-concave" onclick="mirrorType('concave',this)" style="font-size:.72rem">Вогнутое</button>
|
||
<button class="preset-btn mirror-type-btn" id="mtype-convex" onclick="mirrorType('convex',this)" style="font-size:.72rem">Выпуклое</button>
|
||
</div>
|
||
<div class="gp-section-title" style="margin-bottom:8px">Параметры</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px" id="mirror-f-row">
|
||
<label style="font-size:.78rem;color:#ccc;width:60px">f = <span id="mirror-f-val" style="color:var(--cyan);font-weight:700">120</span></label>
|
||
<input type="range" id="sl-mirror-f" min="30" max="300" step="5" value="120" oninput="mirrorParam('f',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:60px">d = <span id="mirror-d-val" style="color:var(--violet);font-weight:700">240</span></label>
|
||
<input type="range" id="sl-mirror-d" min="30" max="500" step="5" value="240" oninput="mirrorParam('d',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:60px">h = <span id="mirror-h-val" style="color:#EF476F;font-weight:700">60</span></label>
|
||
<input type="range" id="sl-mirror-h" min="20" max="80" step="2" value="60" oninput="mirrorParam('h',this.value)" style="flex:1">
|
||
</div>
|
||
<div style="display:flex;gap:6px;margin-top:8px;margin-bottom:8px;align-items:center">
|
||
<button id="mirror-play-btn" onclick="mirrorTogglePlay(this)" style="flex:1;padding:6px 0;border-radius:8px;border:none;background:linear-gradient(135deg,var(--cyan),var(--violet));color:#fff;font-size:.78rem;font-weight:700;cursor:pointer">▶ Анимация</button>
|
||
<div style="display:flex;flex-direction:column;align-items:center;gap:2px">
|
||
<span style="font-size:.62rem;color:#888">скорость</span>
|
||
<select id="mirror-speed-sel" onchange="mirrorSetSpeed(this.value)" style="background:#1a1a2e;color:#ccc;border:1px solid #333;border-radius:4px;font-size:.7rem;padding:2px 4px">
|
||
<option value="0.25">×¼</option><option value="0.5">×½</option>
|
||
<option value="1" selected>×1</option><option value="2">×2</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div style="display:flex;gap:4px;margin-bottom:10px">
|
||
<button onclick="mirrorStepNext()" style="flex:1;padding:5px 0;border-radius:6px;border:1px solid #333;background:#1a1a2e;color:#7BF5A4;font-size:.73rem;cursor:pointer" title="Показать следующий луч">① Пошагово</button>
|
||
<button onclick="mirrorStepReset()" style="padding:5px 9px;border-radius:6px;border:1px solid #333;background:#1a1a2e;color:#888;font-size:.78rem;cursor:pointer" title="Показать все лучи">↺</button>
|
||
</div>
|
||
<!-- Feature 2: R-slider + parabolic toggle -->
|
||
<div style="margin-bottom:6px">
|
||
<label style="display:flex;align-items:center;gap:6px;font-size:.72rem;color:#ccc;cursor:pointer">
|
||
<input type="checkbox" id="mtog-useR" onchange="mirrorToggleR(this.checked)">
|
||
Радиус R (непрерывный)
|
||
</label>
|
||
</div>
|
||
<div id="ob-mirror-R-row" class="proj-slider-row" style="margin-bottom:6px;display:none">
|
||
<label style="font-size:.72rem;color:#ccc;width:60px">R = <span id="mirror-R-val" style="color:var(--cyan);font-weight:700">240</span></label>
|
||
<input type="range" id="sl-mirror-R" min="-250" max="250" step="5" value="240" oninput="mirrorRParam(this.value)" style="flex:1">
|
||
</div>
|
||
<div style="display:flex;gap:4px;margin-bottom:8px">
|
||
<button id="mirror-parab-btn" onclick="mirrorToggleParabolic(this)" style="flex:1;padding:5px 0;border-radius:6px;border:1px solid #333;background:#1a1a2e;color:#888;font-size:.72rem;cursor:pointer">Сферическое</button>
|
||
</div>
|
||
<div class="gp-section-title" style="margin-bottom:6px">Отображение</div>
|
||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:3px 10px;margin-bottom:10px">
|
||
<label style="display:flex;align-items:center;gap:4px;font-size:.72rem;color:#ccc;cursor:pointer"><input type="checkbox" id="mtog-normals" checked onchange="mirrorToggle('normals',this.checked)"> Нормали</label>
|
||
<label style="display:flex;align-items:center;gap:4px;font-size:.72rem;color:#ccc;cursor:pointer"><input type="checkbox" id="mtog-dims" checked onchange="mirrorToggle('dims',this.checked)"> Размеры</label>
|
||
<label style="display:flex;align-items:center;gap:4px;font-size:.72rem;color:#ccc;cursor:pointer"><input type="checkbox" id="mtog-angles" checked onchange="mirrorToggle('angles',this.checked)"> Углы θ</label>
|
||
<label style="display:flex;align-items:center;gap:4px;font-size:.72rem;color:#ccc;cursor:pointer"><input type="checkbox" id="mtog-photons" checked onchange="mirrorToggle('photons',this.checked)"> Фотоны</label>
|
||
<label style="display:flex;align-items:center;gap:4px;font-size:.72rem;color:#ccc;cursor:pointer"><input type="checkbox" id="mtog-grid" onchange="mirrorToggle('grid',this.checked)"> Сетка</label>
|
||
<label style="display:flex;align-items:center;gap:4px;font-size:.72rem;color:#ccc;cursor:pointer"><input type="checkbox" id="mtog-zones" checked onchange="mirrorToggle('zones',this.checked)"> Зоны</label>
|
||
<label style="display:flex;align-items:center;gap:4px;font-size:.72rem;color:#ccc;cursor:pointer;grid-column:span 2"><input type="checkbox" id="mtog-point" onchange="mirrorSetPointMode(this.checked)"> Точечный объект</label>
|
||
<label style="display:flex;align-items:center;gap:4px;font-size:.72rem;color:#FF6B6B;cursor:pointer;grid-column:span 2"><input type="checkbox" id="mtog-spherical" onchange="mirrorAberration(this.checked)"> Сферич. аберрация</label>
|
||
</div>
|
||
<button onclick="if(mirrorSim)mirrorSim.exportPng()" style="width:100%;padding:5px 0;border-radius:6px;border:1px solid #333;background:#1a1a2e;color:#888;font-size:.72rem;cursor:pointer;margin-bottom:8px"><svg class="ic" viewBox="0 0 24 24"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg> Экспорт PNG</button>
|
||
<div class="gp-section-title" style="margin-bottom:6px">Пресеты</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:8px">
|
||
<button class="preset-btn" onclick="mirrorPreset('flat')">Плоское</button>
|
||
<button class="preset-btn" onclick="mirrorPreset('far')">d > 2f</button>
|
||
<button class="preset-btn" onclick="mirrorPreset('2f')">d = 2f</button>
|
||
<button class="preset-btn" onclick="mirrorPreset('between')">f < d < 2f</button>
|
||
<button class="preset-btn" onclick="mirrorPreset('near')">d < f</button>
|
||
<button class="preset-btn" onclick="mirrorPreset('convex')">Выпуклое</button>
|
||
</div>
|
||
<div class="pp-hint">Тащи предмет, фокус или изображение мышью</div>
|
||
</div>
|
||
<!-- ── Refraction control panel ── -->
|
||
<div id="ob-ctrl-refraction" class="proj-panel" style="width:220px;gap:0;flex-shrink:0;display:none">
|
||
<div class="gp-section-title" style="margin-bottom:8px">Параметры</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:55px">n₁ = <span id="refr-n1-val" style="color:var(--violet);font-weight:700">1.00</span></label>
|
||
<input type="range" id="sl-refr-n1" min="1" max="2.5" step="0.01" value="1" oninput="refrParam('n1',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:55px">n₂ = <span id="refr-n2-val" style="color:var(--cyan);font-weight:700">1.50</span></label>
|
||
<input type="range" id="sl-refr-n2" min="1" max="2.5" step="0.01" value="1.5" oninput="refrParam('n2',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:55px">θ = <span id="refr-angle-val" style="color:#FFD166;font-weight:700">30</span>°</label>
|
||
<input type="range" id="sl-refr-angle" min="0" max="89" step="1" value="30" oninput="refrParam('angle',this.value)" style="flex:1">
|
||
</div>
|
||
<div style="margin-top:8px"></div>
|
||
<label style="display:flex;align-items:center;gap:6px;font-size:.72rem;color:#ccc;cursor:pointer;margin-bottom:8px">
|
||
<input type="checkbox" id="refr-dispersion-toggle" onchange="refrDispersion(this.checked)">
|
||
Дисперсия (7 цветов)
|
||
</label>
|
||
<div class="gp-section-title" style="margin-bottom:6px">Пресеты</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:8px">
|
||
<button class="preset-btn" onclick="refrPreset(1,1.5,30)">Воздух→Стекло</button>
|
||
<button class="preset-btn" onclick="refrPreset(1.5,1,30)">Стекло→Воздух</button>
|
||
<button class="preset-btn" onclick="refrPreset(1.33,1.5,30)">Вода→Стекло</button>
|
||
<button class="preset-btn" onclick="refrPreset(1,2.42,45)">Алмаз</button>
|
||
</div>
|
||
<div class="pp-hint">Тащи луч мышью для изменения угла</div>
|
||
</div>
|
||
<!-- ── Prism control panel ── -->
|
||
<div id="ob-ctrl-prism" class="proj-panel" style="width:220px;gap:0;flex-shrink:0;display:none">
|
||
<div class="gp-section-title" style="margin-bottom:8px">Параметры призмы</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:55px">n = <span id="prism-n0-val" style="color:#64b4ff;font-weight:700">1.50</span></label>
|
||
<input type="range" id="sl-prism-n0" min="1.3" max="2.4" step="0.01" value="1.5" oninput="prismParam('n0',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:65px">θвх = <span id="prism-inc-val" style="color:#FFD166;font-weight:700">30</span>°</label>
|
||
<input type="range" id="sl-prism-inc" min="0" max="75" step="1" value="30" oninput="prismParam('incAngle',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="pp-hint" style="margin-bottom:8px">Тащи призму мышью: ← → вращение, ↕ угол луча</div>
|
||
<div class="gp-section-title" style="margin-bottom:6px">Свет</div>
|
||
<div style="display:flex;gap:5px;margin-bottom:10px">
|
||
<button class="preset-btn active" id="ob-prism-white-btn" onclick="prismToggleWhite(true,this)" style="flex:1">Белый</button>
|
||
<button class="preset-btn" id="ob-prism-mono-btn" onclick="prismToggleWhite(false,this)" style="flex:1">Моно</button>
|
||
</div>
|
||
<div class="gp-section-title" style="margin-bottom:6px">Пресеты</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:8px">
|
||
<button class="preset-btn" onclick="prismPreset(1.5,30)">Стекло (n=1.5)</button>
|
||
<button class="preset-btn" onclick="prismPreset(1.7,40)">Флинт (n=1.7)</button>
|
||
<button class="preset-btn" onclick="prismPreset(2.42,45)">Алмаз (n=2.42)</button>
|
||
</div>
|
||
</div>
|
||
<!-- ── Free-build multi-lens control panel (Agent OB-A3) ── -->
|
||
<div id="ob-ctrl-freebuild" class="proj-panel" style="width:220px;gap:0;flex-shrink:0;display:none">
|
||
<div class="gp-section-title" style="margin-bottom:8px">Цепочка линз</div>
|
||
<div style="display:flex;gap:4px;margin-bottom:10px">
|
||
<button class="preset-btn" onclick="freeAddLens()" style="flex:1">+ Линза</button>
|
||
<button class="preset-btn" onclick="freeRemoveLens()" style="flex:1">− Линза</button>
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:6px">
|
||
<label style="font-size:.78rem;color:#ccc;width:72px">Лин.1 f=<span id="free-lens0-fval" style="color:var(--cyan);font-weight:700">120</span></label>
|
||
<input type="range" id="sl-free-f0" min="-300" max="300" step="5" value="120" oninput="freeLensF(0,this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:6px">
|
||
<label style="font-size:.78rem;color:#ccc;width:72px">Лин.2 f=<span id="free-lens1-fval" style="color:var(--cyan);font-weight:700">90</span></label>
|
||
<input type="range" id="sl-free-f1" min="-300" max="300" step="5" value="90" oninput="freeLensF(1,this.value)" style="flex:1">
|
||
</div>
|
||
<div style="margin-top:8px"></div>
|
||
<div class="gp-section-title" style="margin-bottom:6px">Пресеты</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:8px">
|
||
<button class="preset-btn" onclick="freePreset('microscope')">Микроскоп</button>
|
||
<button class="preset-btn" onclick="freePreset('telescope')">Телескоп</button>
|
||
<button class="preset-btn" onclick="freePreset('relay')">Рел. цепочка</button>
|
||
</div>
|
||
<div class="pp-hint">Тащи линзы или предмет по оси мышью</div>
|
||
</div>
|
||
<!-- ── Interference control panel (Agent C) ── -->
|
||
<div id="ob-ctrl-interf" class="proj-panel" style="width:240px;gap:0;flex-shrink:0;display:none">
|
||
<!-- Sub-mode buttons -->
|
||
<div class="gp-section-title" style="margin-bottom:6px">Эксперимент</div>
|
||
<div style="display:flex;gap:3px;margin-bottom:10px;flex-wrap:wrap">
|
||
<button id="if-sub-newton" class="preset-btn active" onclick="ifSwitchSub('newton')" style="font-size:.7rem;flex:1">Кольца Ньютона</button>
|
||
<button id="if-sub-thinfilm" class="preset-btn" onclick="ifSwitchSub('thinfilm')" style="font-size:.7rem;flex:1">Тонкая плёнка</button>
|
||
<button id="if-sub-polarization" class="preset-btn" onclick="ifSwitchSub('polarization')" style="font-size:.7rem;flex:1">Поляризация</button>
|
||
</div>
|
||
<!-- Newton rings controls -->
|
||
<div id="if-ctrl-newton">
|
||
<div class="gp-section-title" style="margin-bottom:6px">Кольца Ньютона</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:65px">R = <span id="if-newton-r-val" style="color:var(--cyan);font-weight:700">200</span> мм</label>
|
||
<input type="range" id="sl-if-newton-r" min="50" max="500" step="10" value="200" oninput="ifNewtParam('R',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:65px">n = <span id="if-newton-n-val" style="color:#FFD166;font-weight:700">12</span></label>
|
||
<input type="range" id="sl-if-newton-n" min="4" max="20" step="1" value="12" oninput="ifNewtParam('nmax',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="pp-hint">r_n(dark) = sqrt(n*lambda*R)</div>
|
||
</div>
|
||
<!-- Thin film controls -->
|
||
<div id="if-ctrl-thinfilm" style="display:none">
|
||
<div class="gp-section-title" style="margin-bottom:6px">Тонкая плёнка</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:60px">t = <span id="if-tf-t-val" style="color:var(--cyan);font-weight:700">400</span></label>
|
||
<input type="range" id="sl-if-tf-t" min="50" max="2000" step="10" value="400" oninput="ifThinFilmParam('t',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:60px">n = <span id="if-tf-n-val" style="color:#FFD166;font-weight:700">1.33</span></label>
|
||
<input type="range" id="sl-if-tf-n" min="1.0" max="2.5" step="0.01" value="1.33" oninput="ifThinFilmParam('n',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:60px">θ = <span id="if-tf-th-val" style="color:#EF476F;font-weight:700">0</span>°</label>
|
||
<input type="range" id="sl-if-tf-th" min="0" max="60" step="1" value="0" oninput="ifThinFilmParam('theta',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="gp-section-title" style="margin-bottom:4px">Пресет</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:3px;margin-bottom:6px">
|
||
<button class="preset-btn" onclick="ifThinFilmPreset('soap')" style="font-size:.68rem">Мыльная n=1.33</button>
|
||
<button class="preset-btn" onclick="ifThinFilmPreset('oil')" style="font-size:.68rem">Масло n=1.50</button>
|
||
<button class="preset-btn" onclick="ifThinFilmPreset('coating')" style="font-size:.68rem">Покрытие n=1.38</button>
|
||
</div>
|
||
<div class="pp-hint">2nt·cosθr = (m+0.5)λ — максимум</div>
|
||
</div>
|
||
<!-- Polarization controls -->
|
||
<div id="if-ctrl-polarization" style="display:none">
|
||
<div class="gp-section-title" style="margin-bottom:6px">Поляризация (Малюс)</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:60px">θ = <span id="if-pol-th-val" style="color:var(--cyan);font-weight:700">45</span>°</label>
|
||
<input type="range" id="sl-if-pol-th" min="0" max="90" step="1" value="45" oninput="ifPolParam('theta',this.value)" style="flex:1">
|
||
</div>
|
||
<div style="margin-bottom:8px">
|
||
<label style="font-size:.72rem;color:#ccc;display:flex;align-items:center;gap:6px;cursor:pointer">
|
||
<input type="radio" name="if-pol-src" value="unpolarized" checked onchange="ifPolSrc(this.value)" style="accent-color:var(--violet)">
|
||
Неполяризованный
|
||
</label>
|
||
<label style="font-size:.72rem;color:#ccc;display:flex;align-items:center;gap:6px;cursor:pointer;margin-top:4px">
|
||
<input type="radio" name="if-pol-src" value="polarized" onchange="ifPolSrc(this.value)" style="accent-color:var(--violet)">
|
||
Поляризованный
|
||
</label>
|
||
</div>
|
||
<div class="pp-hint">I = I₀·cos²(θ)</div>
|
||
</div>
|
||
</div>
|
||
<!-- ── Waves (diffraction) control panel (Agent B1) ── -->
|
||
<div id="ob-ctrl-waves" class="proj-panel" style="width:230px;gap:0;flex-shrink:0;display:none">
|
||
<div class="gp-section-title" style="margin-bottom:8px">Опыт</div>
|
||
<div style="display:flex;gap:3px;margin-bottom:10px">
|
||
<button id="diffr-sub-young" onclick="diffrSwitchSub('young')" class="preset-btn active" style="flex:1;font-size:.7rem">Юнг</button>
|
||
<button id="diffr-sub-single" onclick="diffrSwitchSub('single')" class="preset-btn" style="flex:1;font-size:.7rem">Однощелевая</button>
|
||
<button id="diffr-sub-grating" onclick="diffrSwitchSub('grating')" class="preset-btn" style="flex:1;font-size:.7rem">Решётка</button>
|
||
</div>
|
||
<!-- Young sliders -->
|
||
<div id="ob-diffr-young-params">
|
||
<div class="gp-section-title" style="margin-bottom:6px">Параметры (Юнг)</div>
|
||
<div class="proj-slider-row" style="margin-bottom:6px">
|
||
<label style="font-size:.75rem;color:#ccc;width:72px">d = <span id="diffr-d-young-val" style="color:var(--cyan);font-weight:700">40</span> мкм</label>
|
||
<input type="range" id="sl-diffr-d-young" min="10" max="100" step="1" value="40"
|
||
oninput="diffrParam('d_young',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.75rem;color:#ccc;width:72px">L = <span id="diffr-L-young-val" style="color:var(--violet);font-weight:700">1.0</span> м</label>
|
||
<input type="range" id="sl-diffr-L-young" min="5" max="20" step="1" value="10"
|
||
oninput="diffrParam('L_young',this.value/10)" style="flex:1">
|
||
</div>
|
||
</div>
|
||
<!-- Single-slit sliders -->
|
||
<div id="ob-diffr-single-params" style="display:none">
|
||
<div class="gp-section-title" style="margin-bottom:6px">Параметры (Однощелевая)</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.75rem;color:#ccc;width:72px">a = <span id="diffr-a-single-val" style="color:#FFD166;font-weight:700">80</span> мкм</label>
|
||
<input type="range" id="sl-diffr-a-single" min="10" max="200" step="5" value="80"
|
||
oninput="diffrParam('a_single',this.value)" style="flex:1">
|
||
</div>
|
||
</div>
|
||
<!-- Grating sliders -->
|
||
<div id="ob-diffr-grating-params" style="display:none">
|
||
<div class="gp-section-title" style="margin-bottom:6px">Параметры (Решётка)</div>
|
||
<div class="proj-slider-row" style="margin-bottom:6px">
|
||
<label style="font-size:.75rem;color:#ccc;width:72px">N = <span id="diffr-N-grating-val" style="color:#7BF5A4;font-weight:700">10</span></label>
|
||
<input type="range" id="sl-diffr-N-grating" min="2" max="100" step="1" value="10"
|
||
oninput="diffrParam('N_grating',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:6px">
|
||
<label style="font-size:.75rem;color:#ccc;width:72px">d = <span id="diffr-d-grating-val" style="color:var(--cyan);font-weight:700">2.0</span> мкм</label>
|
||
<input type="range" id="sl-diffr-d-grating" min="5" max="50" step="1" value="20"
|
||
oninput="diffrParam('d_grating',this.value/10)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.75rem;color:#ccc;width:72px">a = <span id="diffr-a-grating-val" style="color:#FFD166;font-weight:700">0.5</span> мкм</label>
|
||
<input type="range" id="sl-diffr-a-grating" min="1" max="30" step="1" value="5"
|
||
oninput="diffrParam('a_grating',this.value/10)" style="flex:1">
|
||
</div>
|
||
</div>
|
||
<div style="margin-top:4px"></div>
|
||
<button onclick="diffrReset()" style="width:100%;padding:5px 0;border-radius:6px;border:1px solid #333;background:#1a1a2e;color:#888;font-size:.72rem;cursor:pointer;margin-bottom:8px">Сброс</button>
|
||
<div class="pp-hint">λ берётся из глобального ползунка</div>
|
||
</div>
|
||
<!-- ── Shared canvas area (all 6 canvases stacked) ── -->
|
||
<div class="proj-canvas-outer" style="position:relative;flex:1;min-width:0">
|
||
<canvas id="ob-lens-canvas" style="position:absolute;top:0;left:0;width:100%;height:100%"></canvas>
|
||
<canvas id="ob-mirror-canvas" style="position:absolute;top:0;left:0;width:100%;height:100%;display:none"></canvas>
|
||
<canvas id="ob-refr-canvas" style="position:absolute;top:0;left:0;width:100%;height:100%;display:none"></canvas>
|
||
<canvas id="ob-prism-canvas" style="position:absolute;top:0;left:0;width:100%;height:100%;display:none"></canvas>
|
||
<canvas id="ob-free-canvas" style="position:absolute;top:0;left:0;width:100%;height:100%;display:none"></canvas>
|
||
<canvas id="ob-waves-canvas" style="position:absolute;top:0;left:0;width:100%;height:100%;display:none"></canvas>
|
||
<canvas id="ob-interf-canvas" style="position:absolute;top:0;left:0;width:100%;height:100%;display:none"></canvas>
|
||
</div>
|
||
</div>
|
||
<!-- Spectrometer panel (shown only in prism mode) -->
|
||
<div id="ob-spectrometer-panel" style="display:none;flex-shrink:0;padding:6px 10px 4px;background:#0a0a16;border-top:1px solid #1a1a30">
|
||
<div style="display:flex;align-items:center;gap:8px;margin-bottom:4px">
|
||
<span style="font-size:.72rem;color:#888;font-weight:600">Спектрометр</span>
|
||
<span style="font-size:.68rem;color:#555">380–780 нм</span>
|
||
</div>
|
||
<canvas id="ob-spectrometer-canvas" style="width:100%;height:56px;display:block;border-radius:4px"></canvas>
|
||
</div>
|
||
<!-- Stats bar -->
|
||
<div class="proj-stats-bar" id="ob-statsbar" style="padding:0">
|
||
<div id="ob-stats-lens" style="display:flex;flex:1;gap:0">
|
||
<div class="pstat"><div class="pstat-label">f</div><div class="pstat-val" id="lensbar-v1" style="color:var(--cyan)">100</div></div>
|
||
<div class="pstat"><div class="pstat-label">d’</div><div class="pstat-val" id="lensbar-v2" style="color:#EF476F">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">M</div><div class="pstat-val" id="lensbar-v3" style="color:#FFD166">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Тип</div><div class="pstat-val" id="lensbar-v4" style="color:var(--violet)">—</div></div>
|
||
</div>
|
||
<div id="ob-stats-mirror" style="display:none;flex:1;gap:0">
|
||
<div class="pstat"><div class="pstat-label">f</div><div class="pstat-val" id="mirrorbar-v1" style="color:var(--cyan)">120</div></div>
|
||
<div class="pstat"><div class="pstat-label">d</div><div class="pstat-val" id="mirrorbar-v5" style="color:var(--violet)">240</div></div>
|
||
<div class="pstat"><div class="pstat-label">d’</div><div class="pstat-val" id="mirrorbar-v2" style="color:#EF476F">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">M</div><div class="pstat-val" id="mirrorbar-v3" style="color:#FFD166">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Тип изобр.</div><div class="pstat-val" id="mirrorbar-v4" style="color:var(--violet)">—</div></div>
|
||
</div>
|
||
<div id="ob-stats-refr" style="display:none;flex:1;gap:0">
|
||
<div class="pstat"><div class="pstat-label">θ₁</div><div class="pstat-val" id="refrbar-v1" style="color:var(--violet)">30°</div></div>
|
||
<div class="pstat"><div class="pstat-label">θ₂</div><div class="pstat-val" id="refrbar-v2" style="color:var(--cyan)">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Крит. угол</div><div class="pstat-val" id="refrbar-v3" style="color:#FFD166">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">ПВО</div><div class="pstat-val" id="refrbar-v4" style="color:#EF476F">Нет</div></div>
|
||
</div>
|
||
<div id="ob-stats-freebuild" style="display:none;flex:1;gap:0">
|
||
<div class="pstat"><div class="pstat-label">Γ общ.</div><div class="pstat-val" id="freebar-mag" style="color:#FFD166">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">F сист.</div><div class="pstat-val" id="freebar-sys" style="color:var(--cyan)">—</div></div>
|
||
</div>
|
||
<div id="ob-stats-prism" style="display:none;flex:1;gap:0">
|
||
<div class="pstat"><div class="pstat-label">A</div><div class="pstat-val" style="color:#64b4ff">60°</div></div>
|
||
<div class="pstat"><div class="pstat-label">n(550)</div><div class="pstat-val" id="prismbar-n" style="color:#64b4ff">1.50</div></div>
|
||
<div class="pstat"><div class="pstat-label">λ</div><div class="pstat-val" id="prismbar-wl" style="color:#FFFFFF">550 нм</div></div>
|
||
<div class="pstat"><div class="pstat-label">Режим</div><div class="pstat-val" id="prismbar-mode" style="color:#aaa">Моно</div></div>
|
||
</div>
|
||
<div id="ob-stats-interf" style="display:none;flex:1;gap:0">
|
||
<div class="pstat"><div class="pstat-label">Режим</div><div class="pstat-val" id="ifbar-sub" style="color:var(--cyan)">Кольца</div></div>
|
||
<div class="pstat"><div class="pstat-label">λ</div><div class="pstat-val" id="ifbar-wl" style="color:#FFFFFF">550 нм</div></div>
|
||
</div>
|
||
<div id="ob-stats-waves" style="display:none;flex:1;gap:0">
|
||
<div class="pstat"><div class="pstat-label">Опыт</div><div class="pstat-val" id="diffbar-sub" style="color:var(--cyan)">Юнг</div></div>
|
||
<div class="pstat"><div class="pstat-label">λ</div><div class="pstat-val" id="diffbar-wl" style="color:#FFFFFF">550 нм</div></div>
|
||
<div class="pstat" style="flex:2"><div class="pstat-label">Результат</div><div class="pstat-val" id="diffbar-info" style="color:#FFD166;font-size:.72rem">—</div></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── ISOPROCESS sim body ── -->
|
||
<div id="sim-isoprocess" class="sim-proj-wrap" style="display:none">
|
||
<div class="sim-body-wrap">
|
||
<div class="proj-panel" style="width:220px;gap:0">
|
||
<div class="gp-section-title" style="margin-bottom:8px">Процесс</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:10px">
|
||
<button class="preset-btn iso-proc-btn active" id="iproc-isothermal" onclick="isoProc('isothermal',this)" style="font-size:.72rem">Изотерма</button>
|
||
<button class="preset-btn iso-proc-btn" id="iproc-isochoric" onclick="isoProc('isochoric',this)" style="font-size:.72rem">Изохора</button>
|
||
<button class="preset-btn iso-proc-btn" id="iproc-isobaric" onclick="isoProc('isobaric',this)" style="font-size:.72rem">Изобара</button>
|
||
<button class="preset-btn iso-proc-btn" id="iproc-adiabatic" onclick="isoProc('adiabatic',this)" style="font-size:.72rem">Адиабата</button>
|
||
</div>
|
||
<div class="gp-section-title" style="margin-bottom:6px">Газ γ</div>
|
||
<div style="display:flex;gap:4px;margin-bottom:10px">
|
||
<button class="preset-btn iso-gamma-btn" id="igamma-14" onclick="isoGamma(1.4,this)" style="font-size:.72rem">Двухат. 1.4</button>
|
||
<button class="preset-btn iso-gamma-btn active" id="igamma-167" onclick="isoGamma(1.667,this)" style="font-size:.72rem">Одноат. 5/3</button>
|
||
</div>
|
||
<div class="gp-section-title" style="margin-bottom:8px">Начальное состояние</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:70px">P₁ = <span id="iso-p1-val" style="color:var(--violet);font-weight:700">3.0</span></label>
|
||
<input type="range" id="sl-iso-p1" min="0.5" max="8" step="0.1" value="3.0" oninput="isoParam('P1',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:70px">V₁ = <span id="iso-v1-val" style="color:var(--violet);font-weight:700">10</span></label>
|
||
<input type="range" id="sl-iso-v1" min="2" max="28" step="1" value="10" oninput="isoParam('V1',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="gp-section-title" style="margin-bottom:8px">Конечное состояние</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:70px;white-space:nowrap">Сжат./расш.</label>
|
||
<input type="range" id="sl-iso-ratio" min="0.01" max="0.99" step="0.01" value="0.5" oninput="isoRatio(this.value)" style="flex:1">
|
||
</div>
|
||
<div style="margin-top:6px"></div>
|
||
<div class="gp-section-title" style="margin-bottom:6px">Пресеты</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:8px">
|
||
<button class="preset-btn" onclick="isoPreset('iso_expand')">Изотерма расш.</button>
|
||
<button class="preset-btn" onclick="isoPreset('iso_comp')">Изотерма сжат.</button>
|
||
<button class="preset-btn" onclick="isoPreset('heat_iso')">Изохора нагрев</button>
|
||
<button class="preset-btn" onclick="isoPreset('adiab_exp')">Адиабата расш.</button>
|
||
</div>
|
||
<div class="pp-hint">Тащи точки 1 и 2 по диаграмме</div>
|
||
</div>
|
||
<div class="proj-canvas-outer">
|
||
<canvas id="isoprocess-canvas"></canvas>
|
||
</div>
|
||
</div>
|
||
<div class="proj-stats-bar" id="isobar">
|
||
<div class="pstat"><div class="pstat-label">T₁, K</div><div class="pstat-val" id="isobar-t1" style="color:var(--violet)">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">T₂, K</div><div class="pstat-val" id="isobar-t2" style="color:var(--cyan)">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">W, Дж</div><div class="pstat-val" id="isobar-w" style="color:#7BF5A4">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Q, Дж</div><div class="pstat-val" id="isobar-q" style="color:#FFD166">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">ΔU, Дж</div><div class="pstat-val" id="isobar-du" style="color:#EF476F">—</div></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── TITRATION sim body ── -->
|
||
<div id="sim-titration" class="sim-proj-wrap" style="display:none">
|
||
<div class="sim-body-wrap">
|
||
<div class="proj-panel" style="width:220px;gap:0">
|
||
<div class="gp-section-title" style="margin-bottom:8px">Параметры</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:75px">C(кисл) <span id="titr-ac-val" style="color:#EF476F;font-weight:700">0.10</span> М</label>
|
||
<input type="range" id="sl-titr-ac" min="0.05" max="1" step="0.05" value="0.1" oninput="titrParam('acidConc',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:75px">C(осн) <span id="titr-bc-val" style="color:var(--violet);font-weight:700">0.10</span> М</label>
|
||
<input type="range" id="sl-titr-bc" min="0.05" max="1" step="0.05" value="0.1" oninput="titrParam('baseConc',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" style="margin-bottom:8px">
|
||
<label style="font-size:.78rem;color:#ccc;width:75px">V(кисл) <span id="titr-vol-val" style="color:var(--cyan);font-weight:700">50</span> мл</label>
|
||
<input type="range" id="sl-titr-vol" min="25" max="100" step="5" value="50" oninput="titrParam('acidVol',this.value)" style="flex:1">
|
||
</div>
|
||
<div style="margin-top:4px;margin-bottom:8px">
|
||
<div class="gp-section-title" style="margin-bottom:4px">Индикатор</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:4px">
|
||
<button class="preset-btn titr-ind-btn active" onclick="titrIndicator('phenolphthalein',this)" style="font-size:.72rem">Фенолф.</button>
|
||
<button class="preset-btn titr-ind-btn" onclick="titrIndicator('methyl_orange',this)" style="font-size:.72rem">Метилор.</button>
|
||
<button class="preset-btn titr-ind-btn" onclick="titrIndicator('litmus',this)" style="font-size:.72rem">Лакмус</button>
|
||
</div>
|
||
</div>
|
||
<div class="gp-section-title" style="margin-bottom:6px">Пресеты</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:8px">
|
||
<button class="preset-btn" onclick="titrPreset('strong_strong')">HCl+NaOH</button>
|
||
<button class="preset-btn" onclick="titrPreset('weak_strong')">CH₃COOH</button>
|
||
<button class="preset-btn" onclick="titrPreset('concentrated')">Конц.</button>
|
||
</div>
|
||
<div class="pp-hint">Нажми <svg class="ic" viewBox="0 0 24 24"><polygon points="5 3 19 12 5 21 5 3"/></svg> — основание добавляется каплями</div>
|
||
</div>
|
||
<div class="proj-canvas-outer">
|
||
<canvas id="titration-canvas"></canvas>
|
||
</div>
|
||
</div>
|
||
<div class="proj-stats-bar" id="titrbar">
|
||
<div class="pstat"><div class="pstat-label">pH</div><div class="pstat-val" id="titrbar-v1" style="color:#EF476F">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Добавлено</div><div class="pstat-val" id="titrbar-v2" style="color:var(--violet)">0.0 мл</div></div>
|
||
<div class="pstat"><div class="pstat-label">Точка экв.</div><div class="pstat-val" id="titrbar-v3" style="color:var(--cyan)">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Тип</div><div class="pstat-val" id="titrbar-v4" style="color:#FFD166">—</div></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── PROBABILITY sim body ── -->
|
||
<div id="sim-probability" class="sim-proj-wrap" style="display:none">
|
||
<div class="sim-body-wrap">
|
||
<div class="proj-panel" style="width:220px;gap:0">
|
||
<div class="gp-section-title" style="margin-bottom:8px">Режим</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:10px">
|
||
<button class="preset-btn prob-mode-btn active" onclick="probMode('coin',this)">Монета</button>
|
||
<button class="preset-btn prob-mode-btn" onclick="probMode('dice',this)">Кубик</button>
|
||
<button class="preset-btn prob-mode-btn" onclick="probMode('dice2',this)">2 кубика</button>
|
||
</div>
|
||
<div class="gp-section-title" style="margin-bottom:6px">Пресеты</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:8px">
|
||
<button class="preset-btn" onclick="probPreset('coin',100)">100 бросков</button>
|
||
<button class="preset-btn" onclick="probPreset('coin',1000)">1000</button>
|
||
<button class="preset-btn" onclick="probPreset('dice',100)">Кубик ×100</button>
|
||
<button class="preset-btn" onclick="probPreset('dice2',500)">2 куб. ×500</button>
|
||
</div>
|
||
<div class="pp-hint">Нажми <svg class="ic" viewBox="0 0 24 24"><polygon points="5 3 19 12 5 21 5 3"/></svg> — броски идут автоматически</div>
|
||
</div>
|
||
<div class="proj-canvas-outer">
|
||
<canvas id="probability-canvas"></canvas>
|
||
</div>
|
||
</div>
|
||
<div class="proj-stats-bar" id="probbar">
|
||
<div class="pstat"><div class="pstat-label">Бросков</div><div class="pstat-val" id="probbar-v1" style="color:var(--violet)">0</div></div>
|
||
<div class="pstat"><div class="pstat-label">Макс. отклон.</div><div class="pstat-val" id="probbar-v2" style="color:#EF476F">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">χ²</div><div class="pstat-val" id="probbar-v3" style="color:var(--cyan)">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Режим</div><div class="pstat-val" id="probbar-v4" style="color:#FFD166">Монета</div></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── BOHR ATOM sim body ── -->
|
||
<div id="sim-bohratom" class="sim-proj-wrap" style="display:none">
|
||
<div class="sim-body-wrap">
|
||
<div class="proj-panel" style="width:220px;gap:0">
|
||
<div class="gp-section-title" style="margin-bottom:8px">Уровень</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:10px">
|
||
<button class="preset-btn" onclick="bohrLevel(1)">n=1</button>
|
||
<button class="preset-btn" onclick="bohrLevel(2)">n=2</button>
|
||
<button class="preset-btn" onclick="bohrLevel(3)">n=3</button>
|
||
<button class="preset-btn" onclick="bohrLevel(4)">n=4</button>
|
||
<button class="preset-btn" onclick="bohrLevel(5)">n=5</button>
|
||
<button class="preset-btn" onclick="bohrLevel(6)">n=6</button>
|
||
</div>
|
||
<div class="gp-section-title" style="margin-bottom:6px">Переходы</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:8px">
|
||
<button class="preset-btn" onclick="bohrTransition(2,1)">2<svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>1 (УФ)</button>
|
||
<button class="preset-btn" onclick="bohrTransition(3,2)">3<svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>2 (красн.)</button>
|
||
<button class="preset-btn" onclick="bohrTransition(4,2)">4<svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>2 (голуб.)</button>
|
||
<button class="preset-btn" onclick="bohrTransition(4,3)">4<svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>3 (ИК)</button>
|
||
<button class="preset-btn" onclick="bohrTransition(1,3)">1<svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>3 (поглощ.)</button>
|
||
</div>
|
||
<div class="pp-hint">Кликни на уровень для перехода электрона</div>
|
||
</div>
|
||
<div class="proj-canvas-outer">
|
||
<canvas id="bohratom-canvas"></canvas>
|
||
</div>
|
||
</div>
|
||
<div class="proj-stats-bar" id="bohrbar">
|
||
<div class="pstat"><div class="pstat-label">Уровень n</div><div class="pstat-val" id="bohrbar-v1" style="color:var(--violet)">1</div></div>
|
||
<div class="pstat"><div class="pstat-label">E (эВ)</div><div class="pstat-val" id="bohrbar-v2" style="color:var(--cyan)">-13.6</div></div>
|
||
<div class="pstat"><div class="pstat-label">λ (нм)</div><div class="pstat-val" id="bohrbar-v3" style="color:#FFD166">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Серия</div><div class="pstat-val" id="bohrbar-v4" style="color:#EF476F">—</div></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── ELECTROLYSIS sim body ── -->
|
||
<div id="sim-electrolysis" class="sim-proj-wrap" style="display:none">
|
||
<div class="sim-body-wrap">
|
||
<div class="proj-panel elec-panel-modern" style="width:280px;gap:0;overflow-y:auto">
|
||
|
||
<!-- Квик-бар -->
|
||
<div class="elec-quick-bar">
|
||
<button class="mag-mode-btn" onclick="elecSim?.playing ? elecSim.pause() : elecSim?.play(); this.textContent=elecSim?.playing?'Пауза':'Старт'">Старт</button>
|
||
<button class="mag-mode-btn" onclick="elecSim?.reset(); document.querySelector('.elec-quick-bar .mag-mode-btn').textContent='Старт'">Сброс</button>
|
||
</div>
|
||
|
||
<!-- Напряжение — всегда видно -->
|
||
<div class="param-block" style="margin:8px 0 4px">
|
||
<div class="param-header">
|
||
<span class="param-name">U (В)</span>
|
||
<span class="param-val" id="elec-V-val" style="color:#FFD166;font-weight:700">6.0</span>
|
||
</div>
|
||
<input type="range" id="sl-elec-V" class="param-slider" min="1" max="12" step="0.5" value="6" oninput="elecParam('voltage',this.value)">
|
||
</div>
|
||
|
||
<!-- Электролиты -->
|
||
<details class="elec-acc" open>
|
||
<summary>Электролит</summary>
|
||
<div class="elec-acc-body">
|
||
<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:5px">
|
||
<button class="mag-mode-btn elec-type-btn active" onclick="elecPreset('nacl',this)">NaCl</button>
|
||
<button class="mag-mode-btn elec-type-btn" onclick="elecPreset('cuso4',this)">CuSO₄</button>
|
||
<button class="mag-mode-btn elec-type-btn" onclick="elecPreset('h2so4',this)">H₂SO₄</button>
|
||
<button class="mag-mode-btn elec-type-btn" onclick="elecPreset('ki',this)">KI</button>
|
||
<button class="mag-mode-btn elec-type-btn" onclick="elecPreset('znso4',this)">ZnSO₄</button>
|
||
<button class="mag-mode-btn elec-type-btn" onclick="elecPreset('agno3',this)">AgNO₃</button>
|
||
</div>
|
||
</div>
|
||
</details>
|
||
|
||
<!-- Скорость -->
|
||
<details class="elec-acc">
|
||
<summary>Скорость</summary>
|
||
<div class="elec-acc-body">
|
||
<div style="display:grid;grid-template-columns:1fr 1fr 1fr 1fr;gap:5px">
|
||
<button class="mag-mode-btn elec-speed-btn" onclick="elecSpeed(0.5,this)">×0.5</button>
|
||
<button class="mag-mode-btn elec-speed-btn active" onclick="elecSpeed(1,this)">×1</button>
|
||
<button class="mag-mode-btn elec-speed-btn" onclick="elecSpeed(2,this)">×2</button>
|
||
<button class="mag-mode-btn elec-speed-btn" onclick="elecSpeed(5,this)">×5</button>
|
||
</div>
|
||
</div>
|
||
</details>
|
||
|
||
<!-- Отображение -->
|
||
<details class="elec-acc">
|
||
<summary>Отображение</summary>
|
||
<div class="elec-acc-body">
|
||
<div class="dyn-checks">
|
||
<label>
|
||
<input type="checkbox" id="elec-chk-electrons" checked onchange="elecToggle('electrons',this.checked)">
|
||
Электроны в цепи
|
||
</label>
|
||
<label>
|
||
<input type="checkbox" id="elec-chk-ions" checked onchange="elecToggle('ions',this.checked)">
|
||
Ионы
|
||
</label>
|
||
<label>
|
||
<input type="checkbox" id="elec-chk-bubbles" checked onchange="elecToggle('bubbles',this.checked)">
|
||
Пузыри
|
||
</label>
|
||
<label>
|
||
<input type="checkbox" id="elec-chk-graphs" onchange="elecToggle('graphs',this.checked)">
|
||
Графики m(t) / V(t)
|
||
</label>
|
||
</div>
|
||
</div>
|
||
</details>
|
||
|
||
<!-- Уравнения -->
|
||
<details class="elec-acc" open>
|
||
<summary>Уравнения</summary>
|
||
<div class="elec-acc-body">
|
||
<div style="margin-bottom:5px">
|
||
<div style="font-size:.72rem;color:rgba(6,214,224,0.7);margin-bottom:3px">Катод (−):</div>
|
||
<div id="elec-eq-cathode" style="font-size:.80rem;color:rgba(255,255,255,0.88);line-height:1.4">2H₂O + 2e⁻ → H₂ + 2OH⁻</div>
|
||
</div>
|
||
<div>
|
||
<div style="font-size:.72rem;color:rgba(239,71,111,0.7);margin-bottom:3px">Анод (+):</div>
|
||
<div id="elec-eq-anode" style="font-size:.80rem;color:rgba(255,255,255,0.88);line-height:1.4">2Cl⁻ − 2e⁻ → Cl₂</div>
|
||
</div>
|
||
</div>
|
||
</details>
|
||
|
||
</div>
|
||
<div class="proj-canvas-outer">
|
||
<canvas id="electrolysis-canvas"></canvas>
|
||
</div>
|
||
</div>
|
||
<div class="proj-stats-bar" id="elecbar">
|
||
<div class="pstat"><div class="pstat-label">I (А)</div><div class="pstat-val" id="elecbar-v1" style="color:#FFD166">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Масса</div><div class="pstat-val" id="elecbar-v2" style="color:var(--violet)">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Газ (мл)</div><div class="pstat-val" id="elecbar-v3" style="color:var(--cyan)">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Время</div><div class="pstat-val" id="elecbar-v4" style="color:#EF476F">0 с</div></div>
|
||
<div class="pstat"><div class="pstat-label">Q (Кл)</div><div class="pstat-val" id="elecbar-v5" style="color:#9B5DE5">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">e⁻ (шт)</div><div class="pstat-val" id="elecbar-v6" style="color:rgba(200,220,255,0.8)">—</div></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── WAVES sim body ── -->
|
||
<div id="sim-waves" class="sim-proj-wrap" style="display:none">
|
||
<div class="sim-body-wrap">
|
||
<div class="proj-panel" style="width:228px;gap:0;overflow-y:auto">
|
||
|
||
<!-- Mode selector -->
|
||
<div class="gp-section-title" style="margin-bottom:6px">Режим</div>
|
||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:4px;margin-bottom:12px">
|
||
<button class="wave-mode-btn active" onclick="wavesMode('transverse',this)">Поперечная</button>
|
||
<button class="wave-mode-btn" onclick="wavesMode('longitudinal',this)">Продольная</button>
|
||
<button class="wave-mode-btn" onclick="wavesMode('superposition',this)">Суперпозиция</button>
|
||
<button class="wave-mode-btn" onclick="wavesMode('standing',this)">Стоячая</button>
|
||
<button class="wave-mode-btn" onclick="wavesMode('doppler',this)">Доплер</button>
|
||
<button class="wave-mode-btn" onclick="wavesMode('beats',this)">Биения</button>
|
||
<button class="wave-mode-btn" onclick="wavesMode('spectrum',this)" style="grid-column:span 2">Спектр (ДПФ)</button>
|
||
</div>
|
||
|
||
<!-- Wave 1 -->
|
||
<div class="gp-section-title" style="margin-bottom:6px">Волна 1</div>
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Амплитуда A₁</span>
|
||
<span class="param-val" id="waves-A1-val" style="color:var(--violet)">50</span>
|
||
</div>
|
||
<input type="range" id="sl-waves-A1" class="param-slider" min="10" max="90" step="2" value="50" oninput="wavesParam('A1',this.value)">
|
||
</div>
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Частота f₁</span>
|
||
<span class="param-val" id="waves-f1-val" style="color:var(--violet)">1.0 Гц</span>
|
||
</div>
|
||
<input type="range" id="sl-waves-f1" class="param-slider" min="0.3" max="4" step="0.1" value="1.0" oninput="wavesParam('f1',this.value)">
|
||
</div>
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Фаза φ₁</span>
|
||
<span class="param-val" id="waves-phi1-val" style="color:var(--violet)">0</span>
|
||
</div>
|
||
<input type="range" id="sl-waves-phi1" class="param-slider" min="0" max="6.28" step="0.1" value="0" oninput="wavesParam('phi1',this.value)">
|
||
</div>
|
||
|
||
<!-- Wave 2 (superposition only) -->
|
||
<div id="waves-w2-section" style="display:none">
|
||
<div class="gp-section-title" style="margin-top:4px;margin-bottom:6px">Волна 2</div>
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Амплитуда A₂</span>
|
||
<span class="param-val" id="waves-A2-val" style="color:var(--cyan)">40</span>
|
||
</div>
|
||
<input type="range" id="sl-waves-A2" class="param-slider" min="10" max="90" step="2" value="40" oninput="wavesParam('A2',this.value)">
|
||
</div>
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Частота f₂</span>
|
||
<span class="param-val" id="waves-f2-val" style="color:var(--cyan)">1.5 Гц</span>
|
||
</div>
|
||
<input type="range" id="sl-waves-f2" class="param-slider" min="0.3" max="4" step="0.1" value="1.5" oninput="wavesParam('f2',this.value)">
|
||
</div>
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Фаза φ₂</span>
|
||
<span class="param-val" id="waves-phi2-val" style="color:var(--cyan)">0</span>
|
||
</div>
|
||
<input type="range" id="sl-waves-phi2" class="param-slider" min="0" max="6.28" step="0.1" value="0" oninput="wavesParam('phi2',this.value)">
|
||
</div>
|
||
<div class="pp-hint" style="margin-bottom:8px">φ₂=0: конструктивная · φ₂=π: деструктивная интерференция</div>
|
||
</div>
|
||
|
||
<!-- Standing wave harmonics -->
|
||
<div id="waves-n-section" style="display:none">
|
||
<div class="gp-section-title" style="margin-top:4px;margin-bottom:6px">Гармоника n</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:10px">
|
||
<button class="preset-btn wave-n-btn active" onclick="wavesN(1,this)">n=1</button>
|
||
<button class="preset-btn wave-n-btn" onclick="wavesN(2,this)">n=2</button>
|
||
<button class="preset-btn wave-n-btn" onclick="wavesN(3,this)">n=3</button>
|
||
<button class="preset-btn wave-n-btn" onclick="wavesN(4,this)">n=4</button>
|
||
<button class="preset-btn wave-n-btn" onclick="wavesN(5,this)">n=5</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Doppler controls -->
|
||
<div id="waves-doppler-section" style="display:none">
|
||
<div class="gp-section-title" style="margin-top:4px;margin-bottom:6px">Эффект Доплера</div>
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Скорость источника v<sub>s</sub></span>
|
||
<span class="param-val" id="waves-dopVs-val" style="color:var(--gold)">0.35c</span>
|
||
</div>
|
||
<input type="range" id="sl-waves-dopVs" class="param-slider" min="0" max="1.8" step="0.05" value="0.35" oninput="wavesParam('dopVs',this.value)" style="accent-color:#FFD166">
|
||
</div>
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Частота источника f₀</span>
|
||
<span class="param-val" id="waves-f1-dop-val" style="color:var(--violet)"></span>
|
||
</div>
|
||
<input type="range" id="sl-waves-f1-dop" class="param-slider" min="0.3" max="4" step="0.1" value="1.0" oninput="wavesParam('f1',this.value)">
|
||
</div>
|
||
<div class="pp-hint" style="margin-bottom:8px">S — источник (перетащи), O — наблюдатель (перетащи)</div>
|
||
</div>
|
||
|
||
<!-- Beats controls -->
|
||
<div id="waves-beats-section" style="display:none">
|
||
<div class="gp-section-title" style="margin-top:4px;margin-bottom:6px">Биения</div>
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Частота f₁</span>
|
||
<span class="param-val" id="waves-beatsF1-val" style="color:var(--violet)">440 Гц</span>
|
||
</div>
|
||
<input type="range" id="sl-waves-beatsF1" class="param-slider" min="100" max="1000" step="1" value="440" oninput="wavesParam('beatsF1',this.value)">
|
||
</div>
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Частота f₂</span>
|
||
<span class="param-val" id="waves-beatsF2-val" style="color:var(--cyan)">444 Гц</span>
|
||
</div>
|
||
<input type="range" id="sl-waves-beatsF2" class="param-slider" min="100" max="1000" step="1" value="444" oninput="wavesParam('beatsF2',this.value)">
|
||
</div>
|
||
<div class="pp-hint" style="margin-bottom:8px">f<sub>бие</sub> = |f₁ − f₂|, огибающая — золотая кривая</div>
|
||
</div>
|
||
|
||
<!-- Spectrum controls -->
|
||
<div id="waves-spectrum-section" style="display:none">
|
||
<div class="gp-section-title" style="margin-top:4px;margin-bottom:6px">Спектр (ДПФ)</div>
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Гармоника для добавления</span>
|
||
<span class="param-val" id="waves-specNewF-val" style="color:var(--pink)">5 Гц</span>
|
||
</div>
|
||
<input type="range" id="sl-waves-specNewF" class="param-slider" min="1" max="50" step="1" value="5" oninput="wavesParam('specNewF',this.value)" style="accent-color:var(--pink)">
|
||
</div>
|
||
<div style="display:flex;gap:6px;margin-bottom:8px">
|
||
<button class="preset-btn" onclick="wavesSpecAdd()" style="flex:1">Добавить гармонику</button>
|
||
<button class="preset-btn" onclick="wavesSpecClear()" style="flex:1;color:var(--pink)">Очистить</button>
|
||
</div>
|
||
<div class="pp-hint" style="margin-bottom:8px">ДПФ N=256, fs=100 Гц. Пики подписаны в Гц.</div>
|
||
</div>
|
||
|
||
<!-- Presets -->
|
||
<div class="gp-section-title" style="margin-top:4px;margin-bottom:6px">Пресеты</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:10px">
|
||
<button class="preset-btn" onclick="wavesPreset('constructive')">Конструктивная</button>
|
||
<button class="preset-btn" onclick="wavesPreset('destructive')">Деструктивная</button>
|
||
<button class="preset-btn" onclick="wavesPreset('beats')">Биения</button>
|
||
</div>
|
||
|
||
<!-- Speed -->
|
||
<div class="param-block" style="margin-top:4px">
|
||
<div class="param-header">
|
||
<span class="param-name">Скорость анимации</span>
|
||
<span class="param-val" id="waves-speed-val" style="color:#FFD166">×2.0</span>
|
||
</div>
|
||
<input type="range" id="sl-waves-speed" class="param-slider" min="0.3" max="5" step="0.1" value="2.0" oninput="wavesParam('speed',this.value)" style="accent-color:#FFD166">
|
||
</div>
|
||
|
||
<div class="pp-hint" style="margin-top:10px">v = λ·f — основное волновое уравнение</div>
|
||
</div>
|
||
<div class="proj-canvas-outer">
|
||
<canvas id="waves-canvas"></canvas>
|
||
</div>
|
||
</div>
|
||
<div class="proj-stats-bar" id="wavesbar">
|
||
<div class="pstat"><div class="pstat-label">T (с)</div><div class="pstat-val" id="wavesbar-T" style="color:var(--violet)">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">λ (px)</div><div class="pstat-val" id="wavesbar-lam" style="color:var(--cyan)">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">v (px/с)</div><div class="pstat-val" id="wavesbar-v" style="color:#FFD166">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">f (Гц)</div><div class="pstat-val" id="wavesbar-f" style="color:var(--pink)">—</div></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── STEREO sim body ── -->
|
||
<div id="sim-stereo" class="sim-body-wrap" style="display:none">
|
||
<div class="stereo-panel">
|
||
|
||
<!-- ── Фигуры ── -->
|
||
<div class="gp-section-title" style="margin-bottom:6px">Многогранники</div>
|
||
<div class="stereo-fig-grid">
|
||
<button class="st-fig-btn stereo-fig-btn active" onclick="setStereoFigure('cube',this)" title="Куб">
|
||
<svg viewBox="0 0 24 24"><rect x="3" y="7" width="12" height="12"/><path d="M3 7l4-4h12v12l-4 4"/><path d="M15 3v12M3 19l4-4"/></svg>Куб
|
||
</button>
|
||
<button class="st-fig-btn stereo-fig-btn" onclick="setStereoFigure('parallelepiped',this)" title="Прямоугольный параллелепипед">
|
||
<svg viewBox="0 0 24 24"><rect x="2" y="8" width="13" height="11"/><path d="M2 8l4-5h13v11l-4 5"/><path d="M15 3v11M2 19l4-5"/></svg>Параллел.
|
||
</button>
|
||
<button class="st-fig-btn stereo-fig-btn" onclick="setStereoFigure('prism',this)" title="Правильная призма">
|
||
<svg viewBox="0 0 24 24"><polygon points="12,3 3,8 3,19 12,21 21,19 21,8"/><line x1="12" y1="3" x2="12" y2="21"/></svg>Призма
|
||
</button>
|
||
<button class="st-fig-btn stereo-fig-btn" onclick="setStereoFigure('pyramid',this)" title="Правильная пирамида">
|
||
<svg viewBox="0 0 24 24"><polygon points="12,2 22,20 2,20"/><line x1="12" y1="2" x2="12" y2="20"/></svg>Пирамида
|
||
</button>
|
||
<button class="st-fig-btn stereo-fig-btn" onclick="setStereoFigure('truncpyramid',this)" title="Усечённая пирамида">
|
||
<svg viewBox="0 0 24 24"><polygon points="6,6 18,6 22,20 2,20"/><line x1="9" y1="6" x2="4" y2="20"/><line x1="15" y1="6" x2="20" y2="20"/></svg>Усеч. пир.
|
||
</button>
|
||
<button class="st-fig-btn stereo-fig-btn" onclick="setStereoFigure('tetrahedron',this)" title="Правильный тетраэдр">
|
||
<svg viewBox="0 0 24 24"><polygon points="12,2 22,20 2,20"/><line x1="12" y1="2" x2="12" y2="20"/><line x1="2" y1="20" x2="12" y2="14"/><line x1="22" y1="20" x2="12" y2="14"/></svg>Тетраэдр
|
||
</button>
|
||
</div>
|
||
|
||
<div class="gp-section-title" style="margin-top:6px;margin-bottom:6px">Правильные многогранники</div>
|
||
<div class="stereo-fig-grid">
|
||
<button class="st-fig-btn stereo-fig-btn" onclick="setStereoFigure('octahedron',this)" title="Правильный октаэдр">
|
||
<svg viewBox="0 0 24 24"><polygon points="12,2 22,12 12,22 2,12"/><line x1="12" y1="2" x2="2" y2="12"/><line x1="12" y1="2" x2="22" y2="12"/><line x1="2" y1="12" x2="12" y2="22"/><line x1="22" y1="12" x2="12" y2="22"/></svg>Октаэдр
|
||
</button>
|
||
<button class="st-fig-btn stereo-fig-btn" onclick="setStereoFigure('icosahedron',this)" title="Правильный икосаэдр">
|
||
<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><polygon points="12,3 20,8 18,17 6,17 4,8"/><line x1="12" y1="3" x2="12" y2="21"/></svg>Икосаэдр
|
||
</button>
|
||
<button class="st-fig-btn stereo-fig-btn st-fig-btn-wide" onclick="setStereoFigure('dodecahedron',this)" title="Правильный додекаэдр">
|
||
<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="9" stroke-dasharray="4,2"/><polygon points="12,2 20,8 17,17 7,17 4,8"/></svg>Додекаэдр
|
||
</button>
|
||
</div>
|
||
|
||
<div class="gp-section-title" style="margin-top:6px;margin-bottom:6px">Тела вращения</div>
|
||
<div class="stereo-fig-grid">
|
||
<button class="st-fig-btn stereo-fig-btn" onclick="setStereoFigure('cylinder',this)" title="Цилиндр">
|
||
<svg viewBox="0 0 24 24"><ellipse cx="12" cy="5" rx="9" ry="3"/><ellipse cx="12" cy="19" rx="9" ry="3"/><line x1="3" y1="5" x2="3" y2="19"/><line x1="21" y1="5" x2="21" y2="19"/></svg>Цилиндр
|
||
</button>
|
||
<button class="st-fig-btn stereo-fig-btn" onclick="setStereoFigure('cone',this)" title="Конус">
|
||
<svg viewBox="0 0 24 24"><ellipse cx="12" cy="19" rx="9" ry="3"/><line x1="3" y1="19" x2="12" y2="4"/><line x1="21" y1="19" x2="12" y2="4"/></svg>Конус
|
||
</button>
|
||
<button class="st-fig-btn stereo-fig-btn" onclick="setStereoFigure('trunccone',this)" title="Усечённый конус">
|
||
<svg viewBox="0 0 24 24"><ellipse cx="12" cy="18" rx="9" ry="3"/><ellipse cx="12" cy="7" rx="5" ry="2"/><line x1="3" y1="18" x2="7" y2="7"/><line x1="21" y1="18" x2="17" y2="7"/></svg>Усеч. конус
|
||
</button>
|
||
<button class="st-fig-btn stereo-fig-btn" onclick="setStereoFigure('sphere',this)" title="Шар">
|
||
<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><ellipse cx="12" cy="12" rx="9" ry="3"/></svg>Шар
|
||
</button>
|
||
</div>
|
||
|
||
<!-- ── Параметры ── -->
|
||
<div class="gp-section-title" style="margin-top:8px;margin-bottom:6px">Параметры</div>
|
||
<div id="stereo-params">
|
||
<div class="stereo-sl-row" id="sp-a-row">
|
||
<label>Сторона <b>a</b> <span id="sp-a-val">4</span></label>
|
||
<input type="range" id="sl-sp-a" min="1" max="10" step="0.5" value="4" oninput="stereoParamChange('a',this.value)">
|
||
</div>
|
||
<div class="stereo-sl-row" id="sp-b-row" style="display:none">
|
||
<label>Сторона <b>b</b> <span id="sp-b-val">3</span></label>
|
||
<input type="range" id="sl-sp-b" min="1" max="10" step="0.5" value="3" oninput="stereoParamChange('b',this.value)">
|
||
</div>
|
||
<div class="stereo-sl-row" id="sp-c-row" style="display:none">
|
||
<label>Сторона <b>c</b> <span id="sp-c-val">5</span></label>
|
||
<input type="range" id="sl-sp-c" min="1" max="10" step="0.5" value="5" oninput="stereoParamChange('c',this.value)">
|
||
</div>
|
||
<div class="stereo-sl-row" id="sp-h-row" style="display:none">
|
||
<label>Высота <b>h</b> <span id="sp-h-val">5</span></label>
|
||
<input type="range" id="sl-sp-h" min="1" max="12" step="0.5" value="5" oninput="stereoParamChange('h',this.value)">
|
||
</div>
|
||
<div class="stereo-sl-row" id="sp-r-row" style="display:none">
|
||
<label>Радиус <b>r</b> <span id="sp-r-val">2</span></label>
|
||
<input type="range" id="sl-sp-r" min="0.5" max="8" step="0.5" value="2" oninput="stereoParamChange('r',this.value)">
|
||
</div>
|
||
<div class="stereo-sl-row" id="sp-R-row" style="display:none">
|
||
<label>Радиус осн. <b>R</b> <span id="sp-R-val">3</span></label>
|
||
<input type="range" id="sl-sp-R" min="0.5" max="8" step="0.5" value="3" oninput="stereoParamChange('R',this.value)">
|
||
</div>
|
||
<div class="stereo-sl-row" id="sp-n-row" style="display:none">
|
||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:4px">
|
||
<span style="font-size:0.72rem;color:var(--text-2)">Граней основания <b>n</b></span>
|
||
<div class="st-n-ctrl">
|
||
<button class="st-n-btn" onclick="stereoNChange(-1)"><svg viewBox="0 0 16 16" fill="none"><line x1="3" y1="8" x2="13" y2="8" stroke-width="2" stroke-linecap="round"/></svg></button>
|
||
<span class="st-n-val" id="sp-n-val">4</span>
|
||
<button class="st-n-btn" onclick="stereoNChange(+1)"><svg viewBox="0 0 16 16" fill="none"><line x1="8" y1="3" x2="8" y2="13" stroke-width="2" stroke-linecap="round"/><line x1="3" y1="8" x2="13" y2="8" stroke-width="2" stroke-linecap="round"/></svg></button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="stereo-sl-row" style="margin-top:2px">
|
||
<label>Прозрачность <span id="sp-opacity-val">0.3</span></label>
|
||
<input type="range" id="sl-sp-opacity" min="0" max="1" step="0.05" value="0.3" oninput="stereoOpacityChange(this.value)">
|
||
</div>
|
||
|
||
<!-- ── Отображение ── -->
|
||
<div class="gp-section-title" style="margin-top:8px;margin-bottom:4px">Отображение</div>
|
||
<div onclick="stereoToggleSt('edges',this.querySelector('.st-toggle'))" class="st-toggle-row">
|
||
<span class="st-toggle-label"><svg viewBox="0 0 24 24"><rect x="3" y="3" width="18" height="18"/></svg>Рёбра</span>
|
||
<div class="st-toggle on" id="stg-edges"></div>
|
||
</div>
|
||
<div onclick="stereoToggleSt('vertices',this.querySelector('.st-toggle'))" class="st-toggle-row">
|
||
<span class="st-toggle-label"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="4" fill="currentColor"/></svg>Вершины</span>
|
||
<div class="st-toggle on" id="stg-vertices"></div>
|
||
</div>
|
||
<div onclick="stereoToggleSt('labels',this.querySelector('.st-toggle'))" class="st-toggle-row">
|
||
<span class="st-toggle-label"><svg viewBox="0 0 24 24"><path d="M4 7h16M4 12h10M4 17h7"/></svg>Подписи</span>
|
||
<div class="st-toggle on" id="stg-labels"></div>
|
||
</div>
|
||
<div onclick="stereoToggleSt('axes',this.querySelector('.st-toggle'))" class="st-toggle-row">
|
||
<span class="st-toggle-label"><svg viewBox="0 0 24 24"><line x1="2" y1="12" x2="22" y2="12"/><line x1="12" y1="2" x2="12" y2="22"/></svg>Оси</span>
|
||
<div class="st-toggle on" id="stg-axes"></div>
|
||
</div>
|
||
<div onclick="stereoToggleSt('grid',this.querySelector('.st-toggle'))" class="st-toggle-row">
|
||
<span class="st-toggle-label"><svg viewBox="0 0 24 24"><rect x="3" y="3" width="18" height="18"/><line x1="3" y1="9" x2="21" y2="9"/><line x1="3" y1="15" x2="21" y2="15"/><line x1="9" y1="3" x2="9" y2="21"/><line x1="15" y1="3" x2="15" y2="21"/></svg>Сетка</span>
|
||
<div class="st-toggle on" id="stg-grid"></div>
|
||
</div>
|
||
|
||
<!-- ── Элементы фигуры ── -->
|
||
<div class="gp-section-title" style="margin-top:8px;margin-bottom:4px">Элементы</div>
|
||
<div onclick="stereoToggleElem('height',this.querySelector('.st-toggle'))" class="st-toggle-row">
|
||
<span class="st-toggle-label"><svg viewBox="0 0 24 24"><line x1="12" y1="3" x2="12" y2="21" stroke-dasharray="4,2"/><line x1="9" y1="21" x2="15" y2="21"/></svg>Высота</span>
|
||
<div class="st-toggle" id="stg-height"></div>
|
||
</div>
|
||
<div onclick="stereoToggleElem('apothem',this.querySelector('.st-toggle'))" class="st-toggle-row">
|
||
<span class="st-toggle-label"><svg viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><line x1="6" y1="19" x2="18" y2="19"/></svg>Апофема</span>
|
||
<div class="st-toggle" id="stg-apothem"></div>
|
||
</div>
|
||
<div onclick="stereoToggleElem('diagonals',this.querySelector('.st-toggle'))" class="st-toggle-row">
|
||
<span class="st-toggle-label"><svg viewBox="0 0 24 24"><rect x="3" y="3" width="18" height="18"/><line x1="3" y1="3" x2="21" y2="21" stroke-dasharray="4,2"/><line x1="21" y1="3" x2="3" y2="21" stroke-dasharray="4,2"/></svg>Диагонали</span>
|
||
<div class="st-toggle" id="stg-diagonals"></div>
|
||
</div>
|
||
<div onclick="stereoToggleElem('midpoints',this.querySelector('.st-toggle'))" class="st-toggle-row">
|
||
<span class="st-toggle-label"><svg viewBox="0 0 24 24"><line x1="3" y1="12" x2="21" y2="12"/><circle cx="12" cy="12" r="3" fill="currentColor"/></svg>Середины рёбер</span>
|
||
<div class="st-toggle" id="stg-midpoints"></div>
|
||
</div>
|
||
<div onclick="stereoToggleElem('inscribed',this.querySelector('.st-toggle'))" class="st-toggle-row">
|
||
<span class="st-toggle-label"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="5" stroke-dasharray="3,2"/><rect x="3" y="3" width="18" height="18"/></svg>Вписанная сфера</span>
|
||
<div class="st-toggle" id="stg-inscribed"></div>
|
||
</div>
|
||
<div onclick="stereoToggleElem('circumscribed',this.querySelector('.st-toggle'))" class="st-toggle-row">
|
||
<span class="st-toggle-label"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="9" stroke-dasharray="4,2"/><polygon points="6,18 18,18 12,6"/></svg>Описанная сфера</span>
|
||
<div class="st-toggle" id="stg-circumscribed"></div>
|
||
</div>
|
||
<div onclick="stereoToggleElem('edgelengths',this.querySelector('.st-toggle'))" class="st-toggle-row">
|
||
<span class="st-toggle-label"><svg viewBox="0 0 24 24"><line x1="4" y1="12" x2="20" y2="12"/><line x1="4" y1="9" x2="4" y2="15"/><line x1="20" y1="9" x2="20" y2="15"/></svg>Длины рёбер</span>
|
||
<div class="st-toggle" id="stg-edgelengths"></div>
|
||
</div>
|
||
<div id="sect-area-display" style="font-size:0.7rem;color:var(--cyan);margin-top:2px;display:none"></div>
|
||
<div id="sphere-radius-info" style="font-size:0.7rem;color:#F59E0B;margin-top:2px;display:none"></div>
|
||
|
||
<!-- ── Сечение ── -->
|
||
<div class="gp-section-title" style="margin-top:8px;margin-bottom:6px">Сечение</div>
|
||
<div class="st-tool-grid" style="margin-bottom:4px">
|
||
<button class="st-tool-btn stereo-sect-btn st-tool-btn-wide" id="sect-toggle" onclick="stereoSectionToggle(this)">
|
||
<svg viewBox="0 0 24 24"><path d="M3 12h18M12 3v18" stroke-dasharray="4,2"/></svg>Показать сечение
|
||
</button>
|
||
<button class="st-tool-btn stereo-sect-type active" data-type="horizontal" onclick="stereoSectionType('horizontal',this)">
|
||
<svg viewBox="0 0 24 24"><line x1="3" y1="12" x2="21" y2="12"/></svg>Горизонт.
|
||
</button>
|
||
<button class="st-tool-btn stereo-sect-type" data-type="diagonal" onclick="stereoSectionType('diagonal',this)">
|
||
<svg viewBox="0 0 24 24"><line x1="4" y1="18" x2="20" y2="6"/></svg>Диагональ
|
||
</button>
|
||
<button class="st-tool-btn stereo-sect-type st-tool-btn-wide" data-type="custom" onclick="stereoSectionType('custom',this)">
|
||
<svg viewBox="0 0 24 24"><circle cx="5" cy="19" r="2" fill="currentColor"/><circle cx="12" cy="5" r="2" fill="currentColor"/><circle cx="19" cy="15" r="2" fill="currentColor"/><polyline points="5,19 12,5 19,15 5,19"/></svg>По 3+ точкам
|
||
</button>
|
||
</div>
|
||
<div class="stereo-sl-row">
|
||
<label>Высота <span id="sp-sect-val">50%</span></label>
|
||
<input type="range" id="sl-sp-sect" min="0" max="100" step="1" value="50" oninput="stereoSectionHeight(this.value)">
|
||
</div>
|
||
<div class="stereo-sl-row" id="sp-angle-row" style="display:none">
|
||
<label>Наклон <span id="sp-angle-val">50%</span></label>
|
||
<input type="range" id="sl-sp-angle" min="0" max="100" step="1" value="50" oninput="stereoSectionAngle(this.value)">
|
||
</div>
|
||
|
||
<!-- ── Инструменты ── -->
|
||
<div class="gp-section-title" style="margin-top:8px;margin-bottom:6px">Инструменты</div>
|
||
<div class="st-tool-grid">
|
||
<button class="st-tool-btn" id="stereo-point-btn" onclick="stereoPointMode(this)" title="Поставить точку на ребро">
|
||
<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="4" fill="currentColor"/><line x1="3" y1="12" x2="21" y2="12"/></svg>Точка
|
||
</button>
|
||
<button class="st-tool-btn" id="stereo-connect-btn" onclick="stereoConnectMode(this)" title="Соединить две точки отрезком">
|
||
<svg viewBox="0 0 24 24"><circle cx="5" cy="19" r="2.5" fill="currentColor"/><circle cx="19" cy="5" r="2.5" fill="currentColor"/><line x1="5" y1="19" x2="19" y2="5" stroke-dasharray="4,2"/></svg>Соединить
|
||
</button>
|
||
<button class="st-tool-btn" id="stereo-measure-btn" onclick="stereoMeasure(this)" title="Измерить расстояние между двумя точками">
|
||
<svg viewBox="0 0 24 24"><line x1="4" y1="12" x2="20" y2="12"/><line x1="4" y1="9" x2="4" y2="15"/><line x1="20" y1="9" x2="20" y2="15"/></svg>Измерение
|
||
</button>
|
||
<button class="st-tool-btn" id="stereo-unfold-btn" onclick="stereoUnfold(this)" title="Развернуть в сетку">
|
||
<svg viewBox="0 0 24 24"><rect x="3" y="10" width="18" height="11"/><path d="M8 10V6a4 4 0 0 1 8 0v4"/></svg>Развёртка
|
||
</button>
|
||
</div>
|
||
<div class="st-action-grid" style="margin-top:3px">
|
||
<button class="st-action-btn" onclick="stereoUndoPoint()">Удалить точку</button>
|
||
<button class="st-action-btn" onclick="stereoClearPoints()">Очист. точки</button>
|
||
<button class="st-action-btn" onclick="stereoMeasureUndo()">Удалить изм.</button>
|
||
<button class="st-action-btn" onclick="stereoMeasureClear()">Очист. изм.</button>
|
||
</div>
|
||
<div id="points-info" style="font-size:0.65rem;color:rgba(255,255,255,0.4);margin-top:2px"></div>
|
||
|
||
<!-- ── Метки рёбер ── -->
|
||
<div class="gp-section-title" style="margin-top:8px;margin-bottom:6px">Метки рёбер</div>
|
||
<div class="st-tool-grid">
|
||
<button class="st-tool-btn" id="stereo-mark-tick-btn" onclick="stereoMarkMode('ticks',this)" title="Засечки равных рёбер — кликните ребро (до 3 штрихов)">
|
||
<svg viewBox="0 0 24 24"><line x1="5" y1="19" x2="19" y2="5"/><line x1="9" y1="9" x2="11" y2="11"/><line x1="13" y1="13" x2="15" y2="15"/></svg>Засечки =
|
||
</button>
|
||
<button class="st-tool-btn" id="stereo-mark-par-btn" onclick="stereoMarkMode('parallel',this)" title="Метки параллельных рёбер — кликните ребро">
|
||
<svg viewBox="0 0 24 24"><line x1="3" y1="8" x2="21" y2="8"/><line x1="3" y1="16" x2="21" y2="16"/><polyline points="15 5 18 8 15 11"/><polyline points="15 13 18 16 15 19"/></svg>Паралл. →
|
||
</button>
|
||
</div>
|
||
<div class="st-action-grid" style="margin-top:3px">
|
||
<button class="st-action-btn st-tool-btn-wide" onclick="stereoMarkClear()" style="grid-column:span 2">Очистить метки</button>
|
||
</div>
|
||
|
||
<!-- ── Производные точки ── -->
|
||
<div class="gp-section-title" style="margin-top:8px;margin-bottom:6px">Производные точки</div>
|
||
<div class="st-tool-grid">
|
||
<button class="st-tool-btn" id="stereo-derive-mid-btn" onclick="stereoDerive('midpoint',this)" title="Середина ребра — кликните ребро">
|
||
<svg viewBox="0 0 24 24"><line x1="3" y1="12" x2="21" y2="12"/><circle cx="12" cy="12" r="3.5" fill="currentColor"/></svg>Сер. ребра
|
||
</button>
|
||
<button class="st-tool-btn" id="stereo-derive-fc-btn" onclick="stereoDerive('face_centroid',this)" title="Центр грани — кликните грань">
|
||
<svg viewBox="0 0 24 24"><polygon points="12,3 21,21 3,21"/><circle cx="12" cy="15" r="2.5" fill="currentColor"/></svg>Центр грани
|
||
</button>
|
||
<button class="st-tool-btn" id="stereo-derive-alt-btn" onclick="stereoDerive('alt_foot',this)" title="Основание высоты: вершина → ребро">
|
||
<svg viewBox="0 0 24 24"><line x1="3" y1="20" x2="21" y2="20"/><line x1="10" y1="4" x2="10" y2="20" stroke-dasharray="4,2"/><path d="M10 20 L13 20 L13 17" fill="none"/></svg>Осн. высоты
|
||
</button>
|
||
<button class="st-tool-btn" id="stereo-derive-cen-btn" onclick="stereoDerive('solid_centroid',this)" title="Центроид тела — точка G">
|
||
<svg viewBox="0 0 24 24"><rect x="3" y="3" width="18" height="18"/><circle cx="12" cy="12" r="3" fill="currentColor"/><line x1="3" y1="3" x2="21" y2="21" stroke-dasharray="4,2" opacity=".4"/><line x1="21" y1="3" x2="3" y2="21" stroke-dasharray="4,2" opacity=".4"/></svg>Центроид G
|
||
</button>
|
||
</div>
|
||
<div class="st-action-grid" style="margin-top:3px">
|
||
<button class="st-action-btn" onclick="stereoDeriveUndo()">Удалить послед.</button>
|
||
<button class="st-action-btn" onclick="stereoDeriveClear()">Очистить</button>
|
||
</div>
|
||
|
||
<!-- ── Углы и расстояния ── -->
|
||
<div class="gp-section-title" style="margin-top:8px;margin-bottom:6px">Углы и расстояния</div>
|
||
<div class="st-tool-grid">
|
||
<button class="st-tool-btn" id="stereo-angle-edge-btn" onclick="stereoAngleMode('edge',this)" title="Угол между рёбрами: 3 точки A-B-C">
|
||
<svg viewBox="0 0 24 24"><line x1="12" y1="19" x2="4" y2="5"/><line x1="12" y1="19" x2="20" y2="6"/><path d="M7 16 Q12 13 17 15" fill="none" stroke-dasharray="3,2"/></svg>∠ рёбер
|
||
</button>
|
||
<button class="st-tool-btn" id="stereo-angle-lp-btn" onclick="stereoAngleMode('linePlane',this)" title="Угол прямой к плоскости: 2 точки → грань">
|
||
<svg viewBox="0 0 24 24"><line x1="4" y1="20" x2="20" y2="4"/><ellipse cx="12" cy="18" rx="9" ry="3" fill="none" opacity=".6"/></svg>∠ пр.–пл.
|
||
</button>
|
||
<button class="st-tool-btn" id="stereo-angle-dih-btn" onclick="stereoAngleMode('dihedral',this)" title="Двугранный угол: 2 точки общего ребра">
|
||
<svg viewBox="0 0 24 24"><line x1="12" y1="3" x2="12" y2="21"/><line x1="3" y1="12" x2="12" y2="21"/><line x1="21" y1="7" x2="12" y2="21"/></svg>∠ двугр.
|
||
</button>
|
||
<button class="st-tool-btn" id="stereo-angle-pp-btn" onclick="stereoAngleMode('pointPlane',this)" title="Расстояние точка–плоскость">
|
||
<svg viewBox="0 0 24 24"><ellipse cx="12" cy="18" rx="9" ry="3" fill="none"/><line x1="12" y1="5" x2="12" y2="18" stroke-dasharray="3,2"/><circle cx="12" cy="5" r="2.5" fill="currentColor"/></svg>d(т→пл)
|
||
</button>
|
||
<button class="st-tool-btn st-tool-btn-wide" id="stereo-angle-skew-btn" onclick="stereoAngleMode('skewLines',this)" title="Угол и расстояние скрещивающихся прямых: P1,P2→P3,P4">
|
||
<svg viewBox="0 0 24 24"><line x1="3" y1="6" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="12" opacity=".5"/><circle cx="12" cy="9" r="2" fill="currentColor"/></svg>∠ скрещивающихся прямых
|
||
</button>
|
||
</div>
|
||
<div class="st-action-grid" style="margin-top:3px">
|
||
<button class="st-action-btn" style="grid-column:span 2" onclick="stereoAngleClear()">Очистить углы</button>
|
||
</div>
|
||
<div id="angle-hint" style="font-size:0.63rem;color:rgba(255,255,255,0.38);margin-top:3px;line-height:1.4"></div>
|
||
|
||
<!-- ── Сечение через 3 точки ── -->
|
||
<div class="gp-section-title" style="margin-top:8px;margin-bottom:6px">Сечение через 3 точки</div>
|
||
<div class="st-tool-grid" style="margin-bottom:4px">
|
||
<button class="st-tool-btn st-tool-btn-wide" id="stereo-sect3p-btn" onclick="stereoSection3P(this)" title="Выбрать 3 точки — построить сечение">
|
||
<svg viewBox="0 0 24 24"><circle cx="5" cy="19" r="2.5" fill="currentColor"/><circle cx="12" cy="4" r="2.5" fill="currentColor"/><circle cx="19" cy="14" r="2.5" fill="currentColor"/><polyline points="5,19 12,4 19,14 5,19" fill="none" stroke-dasharray="3,2"/></svg>Сечение через 3 точки
|
||
</button>
|
||
</div>
|
||
<div class="st-action-grid" style="margin-top:3px">
|
||
<button class="st-action-btn" onclick="stereoSection3PClear()" style="grid-column:span 2">Сбросить сечение</button>
|
||
</div>
|
||
<div id="sect3p-hint" style="font-size:0.63rem;color:rgba(255,255,255,0.38);margin-top:3px;line-height:1.4"></div>
|
||
<div id="sect3p-info" style="font-size:0.7rem;margin-top:4px;line-height:1.6"></div>
|
||
<div class="st-toggle-row" style="margin-top:4px" onclick="stereoSection3PStepBy(this.querySelector('.st-toggle'))">
|
||
<span class="st-toggle-label"><svg viewBox="0 0 24 24"><line x1="4" y1="12" x2="20" y2="12"/><polyline points="13 5 20 12 13 19"/></svg>Пошагово</span>
|
||
<div class="st-toggle" id="stg-sect3p-step"></div>
|
||
</div>
|
||
<div class="st-action-grid" style="margin-top:3px">
|
||
<button class="st-action-btn" onclick="stereoSection3PPrevStep()">Назад</button>
|
||
<button class="st-action-btn" onclick="stereoSection3PNextStep()">Вперёд</button>
|
||
</div>
|
||
|
||
<!-- ── Формулы ── -->
|
||
<div class="gp-section-title" style="margin-top:8px;margin-bottom:4px">Формулы</div>
|
||
<div id="stereo-formulas" style="font-size:0.72rem;color:rgba(255,255,255,0.7);line-height:1.5;margin-bottom:6px"></div>
|
||
|
||
</div>
|
||
<div class="graph-canvas-outer">
|
||
<div class="graph-canvas-wrap" id="stereo-container"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- stats bar for stereo -->
|
||
<div class="proj-stats-bar" id="stereo-stats" style="display:none">
|
||
<div class="pstat"><div class="pstat-label">Объём</div><div class="pstat-val" id="stbar-vol">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Полная S</div><div class="pstat-val" id="stbar-area">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Бок. S</div><div class="pstat-val" id="stbar-side">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Высота</div><div class="pstat-val" id="stbar-h">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Диагональ</div><div class="pstat-val" id="stbar-d">—</div></div>
|
||
</div>
|
||
|
||
<!-- ── HYDROSTATICS sim body ── -->
|
||
<div id="sim-hydro" class="sim-proj-wrap" style="display:none">
|
||
<div class="sim-body-wrap">
|
||
|
||
<!-- left panel -->
|
||
<div class="proj-panel" style="width:230px;gap:0;overflow-y:auto">
|
||
|
||
<div class="gp-section-title" style="margin-bottom:8px">Параметры</div>
|
||
|
||
<!-- liquid -->
|
||
<div style="margin-bottom:10px">
|
||
<div style="font-size:.72rem;color:rgba(255,255,255,.4);margin-bottom:4px">Жидкость</div>
|
||
<select onchange="hydroSim&&hydroSim.setLiquid(this.value);document.getElementById('hydro-liq-sel').value=this.value" style="width:100%;background:#1a1030;color:#f0e8ff;border:1px solid rgba(255,255,255,.12);border-radius:8px;padding:5px 8px;font-size:.78rem">
|
||
<option value="water">Вода (1000 кг/м³)</option>
|
||
<option value="saltwater">Солёная вода (1030)</option>
|
||
<option value="oil">Масло (900)</option>
|
||
<option value="alcohol">Спирт (790)</option>
|
||
<option value="glycerin">Глицерин (1260)</option>
|
||
<option value="mercury">Ртуть (13600)</option>
|
||
</select>
|
||
</div>
|
||
|
||
<!-- material (Archimedes only) -->
|
||
<div id="hydro-panel-mat" style="margin-bottom:10px;display:none">
|
||
<div style="font-size:.72rem;color:rgba(255,255,255,.4);margin-bottom:4px">Материал тела</div>
|
||
<select onchange="hydroSim&&hydroSim.setMaterial(this.value)" style="width:100%;background:#1a1030;color:#f0e8ff;border:1px solid rgba(255,255,255,.12);border-radius:8px;padding:5px 8px;font-size:.78rem">
|
||
<option value="styrofoam">Пенопласт (30 кг/м³)</option>
|
||
<option value="cork">Пробка (120)</option>
|
||
<option value="wood">Дерево (500)</option>
|
||
<option value="ice">Лёд (900)</option>
|
||
<option value="plastic">Пластик (1100)</option>
|
||
<option value="glass">Стекло (2500)</option>
|
||
<option value="aluminum">Алюминий (2700)</option>
|
||
<option value="iron">Железо (7800)</option>
|
||
<option value="gold">Золото (19300)</option>
|
||
</select>
|
||
<div style="display:flex;gap:5px;margin-top:6px">
|
||
<button class="gp-btn" onclick="hydroSim&&hydroSim.addBody()" style="flex:1">+ Тело</button>
|
||
<button class="gp-btn" onclick="hydroSim&&hydroSim.clearBodies()" style="flex:1">Очистить</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- contact angle (surface tension) -->
|
||
<div id="hydro-panel-theta" style="margin-bottom:10px;display:none">
|
||
<div style="display:flex;justify-content:space-between;font-size:.72rem;color:rgba(255,255,255,.4);margin-bottom:4px">
|
||
<span>Краевой угол θ</span>
|
||
<span id="hydro-theta-lbl" style="color:var(--violet)">20°</span>
|
||
</div>
|
||
<input type="range" min="0" max="160" value="20" step="5" style="width:100%;accent-color:var(--violet)" oninput="hydroSim&&hydroSim.setContactAngle(+this.value);document.getElementById('hydro-theta-lbl').textContent=this.value+'\u00B0';document.getElementById('hydro-theta-val').textContent=this.value+'\u00B0';document.querySelector('#hydro-surf-ctrl input[type=range]').value=this.value">
|
||
<div style="display:flex;justify-content:space-between;font-size:.65rem;color:rgba(255,255,255,.25);margin-top:2px">
|
||
<span>Смачивание</span><span>Несмачивание</span>
|
||
</div>
|
||
<div style="margin-top:6px">
|
||
<button class="gp-btn" id="hydro-surf-toggle-panel" onclick="hydroToggleSurface()" style="width:100%">Капилляры</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- communicating vessels -->
|
||
<div id="hydro-panel-comm" style="margin-bottom:10px;display:none">
|
||
<div style="font-size:.72rem;color:rgba(255,255,255,.4);margin-bottom:4px">Сосудов</div>
|
||
<div style="display:flex;gap:5px">
|
||
<button class="gp-btn hydro-nv active" onclick="hydroSetVessels(2,this)" style="flex:1">2</button>
|
||
<button class="gp-btn hydro-nv" onclick="hydroSetVessels(3,this)" style="flex:1">3</button>
|
||
<button class="gp-btn hydro-nv" onclick="hydroSetVessels(4,this)" style="flex:1">4</button>
|
||
</div>
|
||
<div style="margin-top:8px">
|
||
<button class="gp-btn" id="hydro-valve-panel-btn" onclick="hydroToggleValve()" style="width:100%;color:#06D6A0;border-color:rgba(6,214,160,.3)">Кран: открыт</button>
|
||
</div>
|
||
<div style="margin-top:6px;display:flex;gap:5px">
|
||
<button class="gp-btn" onclick="hydroSim&&hydroSim.addLiquid(0)" style="flex:1">+ Жидкость</button>
|
||
<button class="gp-btn" onclick="hydroSim&&hydroSim.removeLiquid()" style="flex:1">- Жидкость</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- formula display -->
|
||
<div class="gp-section-title" style="margin-top:4px;margin-bottom:6px">Формулы</div>
|
||
<div id="hydro-formulas" style="font-size:.72rem;font-family:'JetBrains Mono',monospace;color:rgba(255,255,255,.6);line-height:1.7;background:rgba(255,255,255,.03);border-radius:8px;padding:8px 10px;min-height:80px"></div>
|
||
|
||
<!-- result badge -->
|
||
<div id="hydro-result" style="margin-top:8px;font-size:.82rem;font-weight:700;text-align:center;padding:8px;border-radius:8px;display:none"></div>
|
||
|
||
<!-- hydrostatics graphs toggle (Archimedes mode) -->
|
||
<div id="hydro-graphs-row" style="margin-top:8px;display:none">
|
||
<button id="btn-hydro-graphs" onclick="hydroToggleGraphs()" style="width:100%;font-size:.75rem;padding:5px;border-radius:8px;border:1px solid rgba(6,214,224,0.3);background:rgba(6,214,224,0.08);color:#06D6E0;cursor:pointer">График погружения</button>
|
||
</div>
|
||
|
||
</div><!-- /.proj-panel -->
|
||
|
||
<!-- canvas area -->
|
||
<div style="flex:1;min-width:0;position:relative" id="hydro-canvas-wrap">
|
||
<canvas id="hydro-canvas" style="width:100%;height:100%;display:block"></canvas>
|
||
</div>
|
||
|
||
</div><!-- /.sim-body-wrap -->
|
||
</div><!-- /#sim-hydro -->
|
||
|
||
<!-- ══════════════════════════════════════════════
|
||
РАДИОАКТИВНЫЙ РАСПАД
|
||
══════════════════════════════════════════════ -->
|
||
<div id="sim-radioactive" class="sim-proj-wrap" style="display:none">
|
||
<div class="sim-body-wrap">
|
||
|
||
<!-- left panel: controls -->
|
||
<div class="proj-panel" style="width:228px;gap:0;overflow-y:auto">
|
||
|
||
<div class="gp-section-title" style="margin-bottom:6px">Изотоп</div>
|
||
<select id="rd-isotope-sel" onchange="radioactiveIsotope(this.value)"
|
||
style="width:100%;background:#1a1a2e;color:#ccc;border:1px solid rgba(255,255,255,0.15);border-radius:6px;padding:5px 8px;font-size:.82rem;margin-bottom:10px;cursor:pointer">
|
||
<option value="C-14">¹⁴C — углерод (T½ = 5730 лет)</option>
|
||
<option value="I-131">¹³¹I — йод (T½ = 8.0 сут)</option>
|
||
<option value="Cs-137">¹³⁷Cs — цезий (T½ = 30.2 г)</option>
|
||
<option value="Ra-226">²²⁶Ra — радий → цепочка</option>
|
||
<option value="K-40">⁴⁰K — калий (T½ = 1.25·10⁹ г)</option>
|
||
<option value="U-238">²³⁸U → цепочка → ²⁰⁶Pb</option>
|
||
<option value="U-235">²³⁵U → цепочка → ²⁰⁷Pb</option>
|
||
</select>
|
||
|
||
<div class="gp-section-title" style="margin-bottom:6px">Начальное N₀</div>
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Частиц</span>
|
||
<span class="param-val" id="rd-n0-val" style="color:var(--violet)">500</span>
|
||
</div>
|
||
<input type="range" id="sl-rd-n0" class="param-slider" min="50" max="2000" step="50" value="500"
|
||
oninput="radioactiveN0(this.value)">
|
||
</div>
|
||
|
||
<div class="gp-section-title" style="margin-top:4px;margin-bottom:6px">Скорость симуляции</div>
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Масштаб</span>
|
||
<span class="param-val" id="rd-speed-val" style="color:var(--cyan)">×10</span>
|
||
</div>
|
||
<input type="range" id="sl-rd-speed" class="param-slider" min="1" max="1000" step="1" value="10"
|
||
oninput="radioactiveSpeed(this.value)">
|
||
</div>
|
||
|
||
<div style="display:flex;gap:6px;margin-top:8px;flex-wrap:wrap">
|
||
<button id="rd-play-btn" class="preset-btn" onclick="radioactivePlay()" style="flex:1;min-width:70px">Старт</button>
|
||
<button class="preset-btn" onclick="radioactiveReset()" style="flex:1;min-width:70px">Сброс</button>
|
||
</div>
|
||
|
||
<!-- Dating mode -->
|
||
<div style="margin-top:16px;border-top:1px solid rgba(255,255,255,0.08);padding-top:12px">
|
||
<div class="gp-section-title" style="margin-bottom:6px">Радиоуглеродное датирование</div>
|
||
<div class="param-block">
|
||
<div class="param-header">
|
||
<span class="param-name">Осталось ¹⁴C</span>
|
||
<span class="param-val" id="rd-dating-pct-val" style="color:#FFD166">50% осталось</span>
|
||
</div>
|
||
<input type="range" id="sl-rd-dating" class="param-slider" min="1" max="99" step="1" value="50"
|
||
oninput="radioactiveDating(this.value)">
|
||
</div>
|
||
<div id="rd-dating-result" style="font-size:.8rem;color:var(--cyan);text-align:center;margin-top:4px">—</div>
|
||
<div class="pp-hint">Только для ¹⁴C — другие изотопы игнорируют</div>
|
||
</div>
|
||
|
||
</div><!-- /.proj-panel -->
|
||
|
||
<!-- particle canvas -->
|
||
<div class="proj-canvas-outer" style="flex:1;min-width:0">
|
||
<canvas id="radioactive-canvas"></canvas>
|
||
</div>
|
||
|
||
<!-- graph canvas -->
|
||
<div class="proj-canvas-outer" style="width:280px;flex-shrink:0">
|
||
<canvas id="radioactive-graph"></canvas>
|
||
</div>
|
||
|
||
</div><!-- /.sim-body-wrap -->
|
||
|
||
<!-- HUD bar -->
|
||
<div class="proj-stats-bar" id="rd-hud">
|
||
<div class="pstat">
|
||
<div class="pstat-label">Прошло периодов</div>
|
||
<div class="pstat-val" id="rd-hud-periods" style="color:var(--violet)">0 T½</div>
|
||
</div>
|
||
<div class="pstat">
|
||
<div class="pstat-label">Распалось</div>
|
||
<div class="pstat-val" id="rd-hud-decayed" style="color:#EF476F">0%</div>
|
||
</div>
|
||
<div class="pstat">
|
||
<div class="pstat-label">Активность</div>
|
||
<div class="pstat-val" id="rd-hud-activity" style="color:var(--cyan)">0 Бк</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div><!-- /#sim-radioactive -->
|
||
|
||
<!-- ══════════════════════════════════════════════
|
||
ПЛАНИМЕТРИЯ
|
||
══════════════════════════════════════════════ -->
|
||
<div id="sim-geometry" class="sim-proj-wrap" style="display:none">
|
||
<div class="sim-body-wrap">
|
||
|
||
<!-- left panel -->
|
||
<div class="geo-panel geo-panel-modern">
|
||
|
||
<!-- Quick-access bar: most-used tools always visible -->
|
||
<div class="geo-quick-bar">
|
||
<button id="geo-btn-select" class="geo-tool-btn active" onclick="geoSetTool('select',this)" title="Выделить / переместить (Esc)">
|
||
<svg viewBox="0 0 24 24" fill="none"><path d="M5 3l14 9-7 1-4 7z" stroke-width="2"/></svg>
|
||
Выбор
|
||
</button>
|
||
<button id="geo-btn-point" class="geo-tool-btn" onclick="geoSetTool('point',this)" title="Поставить точку">
|
||
<svg viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="4" fill="currentColor"/></svg>
|
||
Точка
|
||
</button>
|
||
<button id="geo-btn-segment" class="geo-tool-btn" onclick="geoSetTool('segment',this)" title="Отрезок — 2 точки">
|
||
<svg viewBox="0 0 24 24" fill="none"><line x1="4" y1="20" x2="20" y2="4" stroke-width="2.5"/><circle cx="4" cy="20" r="2.5" fill="currentColor"/><circle cx="20" cy="4" r="2.5" fill="currentColor"/></svg>
|
||
Отрезок
|
||
</button>
|
||
<button id="geo-btn-circle" class="geo-tool-btn" onclick="geoSetTool('circle',this)" title="Окружность — центр + радиус">
|
||
<svg viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="8" stroke-width="2"/><circle cx="12" cy="12" r="2" fill="currentColor"/></svg>
|
||
Круг
|
||
</button>
|
||
</div>
|
||
|
||
<details class="geo-acc">
|
||
<summary>Линии</summary>
|
||
<div class="geo-acc-body geo-tool-grid">
|
||
<button id="geo-btn-line" class="geo-tool-btn" onclick="geoSetTool('line',this)" title="Прямая — 2 точки">
|
||
<svg viewBox="0 0 24 24" fill="none"><line x1="2" y1="22" x2="22" y2="2" stroke-width="2" stroke-dasharray="3,2"/></svg>
|
||
Прямая
|
||
</button>
|
||
<button id="geo-btn-ray" class="geo-tool-btn" onclick="geoSetTool('ray',this)" title="Луч — начало + направление">
|
||
<svg viewBox="0 0 24 24" fill="none"><line x1="4" y1="20" x2="22" y2="4" stroke-width="2"/><polyline points="17 4 22 4 22 9" stroke-width="2"/><circle cx="4" cy="20" r="2.5" fill="currentColor"/></svg>
|
||
Луч
|
||
</button>
|
||
</div>
|
||
</details>
|
||
|
||
<details class="geo-acc">
|
||
<summary>Фигуры</summary>
|
||
<div class="geo-acc-body">
|
||
<div class="geo-tool-grid">
|
||
<button id="geo-btn-triangle" class="geo-tool-btn" onclick="geoSetTool('triangle',this)" title="Треугольник — 3 точки">
|
||
<svg viewBox="0 0 24 24" fill="none"><polygon points="12,3 22,21 2,21" stroke-width="2"/></svg>
|
||
Треуг.
|
||
</button>
|
||
<button id="geo-btn-quad" class="geo-tool-btn" onclick="geoSetTool('quad',this)" title="Четырёхугольник — 4 точки">
|
||
<svg viewBox="0 0 24 24" fill="none"><polygon points="3,6 21,4 20,19 4,20" stroke-width="2"/></svg>
|
||
Четырёх.
|
||
</button>
|
||
<button id="geo-btn-polygon" class="geo-tool-btn geo-tool-wide" onclick="geoSetTool('polygon',this)" title="Многоугольник — N точек, Enter/двойной клик для завершения">
|
||
<svg viewBox="0 0 24 24" fill="none"><polygon points="12,2 22,8 19,21 5,21 2,8" stroke-width="2"/></svg>
|
||
Многоугольник
|
||
</button>
|
||
<button id="geo-btn-parallelogram" class="geo-tool-btn" onclick="geoSetTool('parallelogram',this)" title="Параллелограмм — 3 точки A, B, C → вычисляет D">
|
||
<svg viewBox="0 0 24 24" fill="none"><polygon points="6,19 3,5 18,5 21,19" stroke-width="1.5" fill="none"/></svg>
|
||
Парал-мм
|
||
</button>
|
||
<button id="geo-btn-ngon" class="geo-tool-btn" onclick="geoSetTool('ngon',this)" title="Правильный n-угольник — клик центр, клик вершина">
|
||
<svg viewBox="0 0 24 24" fill="none"><polygon points="12,3 20.2,8.5 17.3,18 6.7,18 3.8,8.5" stroke-width="1.5" fill="none"/></svg>
|
||
n-уг.
|
||
</button>
|
||
</div>
|
||
<div class="geo-ngon-ctrl" id="geo-ngon-ctrl" style="margin-top:6px">
|
||
<span style="font-size:11px;opacity:.7">N =</span>
|
||
<button class="geo-ngon-btn" onclick="geoNgonN(-1)">
|
||
<svg viewBox="0 0 16 16" fill="none"><line x1="3" y1="8" x2="13" y2="8" stroke-width="2" stroke-linecap="round"/></svg>
|
||
</button>
|
||
<span id="geo-ngon-n">6</span>
|
||
<button class="geo-ngon-btn" onclick="geoNgonN(+1)">
|
||
<svg viewBox="0 0 16 16" fill="none"><line x1="8" y1="3" x2="8" y2="13" stroke-width="2" stroke-linecap="round"/><line x1="3" y1="8" x2="13" y2="8" stroke-width="2" stroke-linecap="round"/></svg>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</details>
|
||
|
||
<details class="geo-acc">
|
||
<summary>Построения</summary>
|
||
<div class="geo-acc-body geo-tool-grid">
|
||
<button id="geo-btn-midpoint" class="geo-tool-btn" onclick="geoSetTool('midpoint',this)" title="Середина отрезка — 2 точки">
|
||
<svg viewBox="0 0 24 24" fill="none"><line x1="3" y1="12" x2="21" y2="12" stroke-width="2"/><circle cx="12" cy="12" r="3.5" fill="currentColor"/></svg>
|
||
Середина
|
||
</button>
|
||
<button id="geo-btn-intersect" class="geo-tool-btn" onclick="geoSetTool('intersect',this)" title="Точка пересечения — клик на две прямые">
|
||
<svg viewBox="0 0 24 24" fill="none"><line x1="4" y1="20" x2="20" y2="4" stroke-width="2"/><line x1="4" y1="4" x2="20" y2="20" stroke-width="2"/><circle cx="12" cy="12" r="3.5" fill="currentColor"/></svg>
|
||
Пересеч.
|
||
</button>
|
||
<button id="geo-btn-perpbisect" class="geo-tool-btn" onclick="geoSetTool('perpbisect',this)" title="Серединный перпендикуляр — 2 точки">
|
||
<svg viewBox="0 0 24 24" fill="none"><line x1="4" y1="18" x2="20" y2="6" stroke-width="2"/><line x1="12" y1="2" x2="12" y2="22" stroke-width="1.5" stroke-dasharray="3,2"/><circle cx="12" cy="12" r="2.5" fill="currentColor"/></svg>
|
||
⊥ биссект.
|
||
</button>
|
||
<button id="geo-btn-anglebisect" class="geo-tool-btn" onclick="geoSetTool('anglebisect',this)" title="Биссектриса угла — 3 точки: A, вершина, B">
|
||
<svg viewBox="0 0 24 24" fill="none"><polyline points="4,20 12,4 20,20" stroke-width="2"/><line x1="12" y1="4" x2="12" y2="20" stroke-width="1.5" stroke-dasharray="3,2"/></svg>
|
||
∠ биссект.
|
||
</button>
|
||
<button id="geo-btn-parallel" class="geo-tool-btn" onclick="geoSetTool('parallel',this)" title="Параллельная прямая — клик на линию, затем на точку">
|
||
<svg viewBox="0 0 24 24" fill="none"><line x1="3" y1="8" x2="21" y2="8" stroke-width="2"/><line x1="3" y1="16" x2="21" y2="16" stroke-width="2" opacity=".5" stroke-dasharray="4,3"/></svg>
|
||
∥ прямая
|
||
</button>
|
||
<button id="geo-btn-perpendicular" class="geo-tool-btn" onclick="geoSetTool('perpendicular',this)" title="Перпендикулярная прямая — клик на линию, затем на точку">
|
||
<svg viewBox="0 0 24 24" fill="none"><line x1="3" y1="12" x2="21" y2="12" stroke-width="2"/><line x1="12" y1="4" x2="12" y2="20" stroke-width="2" opacity=".5" stroke-dasharray="4,3"/></svg>
|
||
⊥ прямая
|
||
</button>
|
||
<button id="geo-btn-foot" class="geo-tool-btn" onclick="geoSetTool('foot',this)" title="Основание перпендикуляра — клик на прямую, затем на точку">
|
||
<svg viewBox="0 0 24 24" fill="none"><line x1="3" y1="18" x2="21" y2="18" stroke-width="2"/><line x1="12" y1="18" x2="12" y2="4" stroke-width="1.5" stroke-dasharray="3,2"/><path d="M12 18 L15 18 L15 15" stroke-width="1.5" fill="none"/><circle cx="12" cy="4" r="2.5" fill="currentColor"/></svg>
|
||
Основание
|
||
</button>
|
||
<button id="geo-btn-tangent" class="geo-tool-btn" onclick="geoSetTool('tangent',this)" title="Касательные из точки к окружности — клик на окружность, затем на точку">
|
||
<svg viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="7" stroke-width="1.5"/><line x1="4" y1="4" x2="19" y2="12" stroke-width="1.5" stroke-dasharray="4,3"/><line x1="4" y1="20" x2="19" y2="12" stroke-width="1.5" stroke-dasharray="4,3"/><circle cx="4" cy="12" r="2.5" fill="currentColor"/></svg>
|
||
Касат.
|
||
</button>
|
||
<button id="geo-btn-diagonal" class="geo-tool-btn" onclick="geoSetTool('diagonal',this)" title="Диагонали — клик внутри многоугольника (4+ вершин)">
|
||
<svg viewBox="0 0 24 24" fill="none"><rect x="3" y="3" width="18" height="18" stroke-width="1.5" fill="none"/><line x1="3" y1="3" x2="21" y2="21" stroke-width="1.5" stroke-dasharray="4,2"/><line x1="21" y1="3" x2="3" y2="21" stroke-width="1.5" stroke-dasharray="4,2"/></svg>
|
||
Диагонали
|
||
</button>
|
||
<button id="geo-btn-circumcircle" class="geo-tool-btn geo-tool-wide" onclick="geoSetTool('circumcircle',this)" title="Описанная окружность — 3 точки треугольника">
|
||
<svg viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="9" stroke-width="1.5" stroke-dasharray="4,3"/><polygon points="6,18 18,18 12,6" stroke-width="1.5" fill="none"/></svg>
|
||
Описанная
|
||
</button>
|
||
<button id="geo-btn-incircle" class="geo-tool-btn geo-tool-wide" onclick="geoSetTool('incircle',this)" title="Вписанная окружность — 3 точки треугольника">
|
||
<svg viewBox="0 0 24 24" fill="none"><polygon points="4,20 20,20 12,4" stroke-width="1.5" fill="none"/><circle cx="12" cy="15" r="5" stroke-width="1.5" stroke-dasharray="4,3"/></svg>
|
||
Вписанная
|
||
</button>
|
||
</div>
|
||
</details>
|
||
|
||
<details class="geo-acc">
|
||
<summary>Треугольник</summary>
|
||
<div class="geo-acc-body geo-tool-grid">
|
||
<button id="geo-btn-altitude" class="geo-tool-btn" onclick="geoSetTool('altitude',this)" title="Высота — клик на сторону, затем на вершину">
|
||
<svg viewBox="0 0 24 24" fill="none"><line x1="3" y1="20" x2="21" y2="20" stroke-width="1.5"/><line x1="10" y1="4" x2="10" y2="20" stroke-width="1.5" stroke-dasharray="4,3"/><rect x="10" y="14" width="4" height="4" stroke-width="1.2"/><polygon points="10,4 3,20 21,20" stroke-width="1.5" fill="none"/></svg>
|
||
Высота
|
||
</button>
|
||
<button id="geo-btn-median" class="geo-tool-btn" onclick="geoSetTool('median',this)" title="Медиана — клик вершина A, B, C">
|
||
<svg viewBox="0 0 24 24" fill="none"><polygon points="12,3 3,20 21,20" stroke-width="1.5" fill="none"/><line x1="12" y1="3" x2="12" y2="20" stroke-width="1.5"/><circle cx="12" cy="20" r="2.5" fill="currentColor"/></svg>
|
||
Медиана
|
||
</button>
|
||
<button id="geo-btn-centroid" class="geo-tool-btn" onclick="geoSetTool('centroid',this)" title="Центроид — 3 точки треугольника, строит 3 медианы">
|
||
<svg viewBox="0 0 24 24" fill="none"><polygon points="12,3 3,20 21,20" stroke-width="1.5" fill="none"/><line x1="12" y1="3" x2="12" y2="20" stroke-width="1.2" opacity=".6"/><line x1="3" y1="20" x2="16.5" y2="11.5" stroke-width="1.2" opacity=".6"/><line x1="21" y1="20" x2="7.5" y2="11.5" stroke-width="1.2" opacity=".6"/><circle cx="12" cy="14.3" r="2.5" fill="currentColor"/></svg>
|
||
Центроид
|
||
</button>
|
||
<button id="geo-btn-orthocenter" class="geo-tool-btn" onclick="geoSetTool('orthocenter',this)" title="Ортоцентр — 3 точки треугольника, строит 3 высоты">
|
||
<svg viewBox="0 0 24 24" fill="none"><polygon points="12,3 3,20 21,20" stroke-width="1.5" fill="none"/><line x1="12" y1="3" x2="12" y2="20" stroke-width="1.2" stroke-dasharray="3,2" opacity=".6"/><line x1="3" y1="20" x2="16" y2="12" stroke-width="1.2" stroke-dasharray="3,2" opacity=".6"/><line x1="21" y1="20" x2="8" y2="12" stroke-width="1.2" stroke-dasharray="3,2" opacity=".6"/><circle cx="12" cy="14" r="2.5" fill="currentColor"/></svg>
|
||
Ортоцентр
|
||
</button>
|
||
<button id="geo-btn-midline" class="geo-tool-btn geo-tool-wide" onclick="geoSetTool('midline',this)" title="Средняя линия треугольника — 3 вершины A, B, C">
|
||
<svg viewBox="0 0 24 24" fill="none"><polygon points="12,3 3,20 21,20" stroke-width="1.5" fill="none"/><line x1="7.5" y1="11.5" x2="16.5" y2="11.5" stroke-width="2"/><circle cx="7.5" cy="11.5" r="2" fill="currentColor"/><circle cx="16.5" cy="11.5" r="2" fill="currentColor"/></svg>
|
||
Средняя линия
|
||
</button>
|
||
<button id="geo-btn-thales" class="geo-tool-btn geo-tool-wide" onclick="geoSetTool('thales',this)" title="Теорема Фалеса — клик O, затем A, затем B → A'B' ∥ AB">
|
||
<svg viewBox="0 0 24 24" fill="none"><circle cx="4" cy="20" r="2" fill="currentColor"/><line x1="4" y1="20" x2="22" y2="4" stroke-width="1.5"/><line x1="4" y1="20" x2="22" y2="12" stroke-width="1.5"/><line x1="10" y1="15" x2="13" y2="12" stroke-width="2" stroke-dasharray="0"/><line x1="17" y1="9" x2="20" y2="7" stroke-width="2" opacity=".6"/></svg>
|
||
Фалес
|
||
</button>
|
||
</div>
|
||
</details>
|
||
|
||
<details class="geo-acc">
|
||
<summary>Преобразования</summary>
|
||
<div class="geo-acc-body">
|
||
<div class="geo-tool-grid">
|
||
<button id="geo-btn-reflect" class="geo-tool-btn" onclick="geoSetTool('reflect',this)" title="Симметрия точки относительно прямой — клик на ось, затем на точку">
|
||
<svg viewBox="0 0 24 24" fill="none"><line x1="12" y1="2" x2="12" y2="22" stroke-width="1.5" stroke-dasharray="3,2"/><circle cx="6" cy="12" r="3" stroke-width="1.5"/><circle cx="18" cy="12" r="2.5" stroke-width="1.5" opacity=".5"/><line x1="9" y1="12" x2="15" y2="12" stroke-width="1" opacity=".6"/></svg>
|
||
Симметрия
|
||
</button>
|
||
<button id="geo-btn-translate" class="geo-tool-btn" onclick="geoSetTool('translate',this)" title="Параллельный перенос — вектор AB, затем точка P">
|
||
<svg viewBox="0 0 24 24" fill="none"><circle cx="6" cy="18" r="2.5" stroke-width="1.5"/><circle cx="18" cy="6" r="2.5" stroke-width="1.5"/><line x1="6" y1="18" x2="18" y2="6" stroke-width="1.5" marker-end="url(#arrow)"/><circle cx="14" cy="18" r="2.5" stroke-width="1.5" opacity=".4"/><circle cx="21" cy="9" r="2" stroke-width="1.5" stroke-dasharray="3,2"/></svg>
|
||
Перенос
|
||
</button>
|
||
<button id="geo-btn-scale" class="geo-tool-btn geo-tool-wide" onclick="geoSetTool('scale',this)" title="Подобие (гомотетия) — клик центр O, затем клик точку P → P' = O + k·(P − O)">
|
||
<svg viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="2" fill="currentColor"/><line x1="12" y1="12" x2="20" y2="6" stroke-width="1.5"/><circle cx="20" cy="6" r="2.5" stroke-width="1.5"/><line x1="12" y1="12" x2="17" y2="18" stroke-width="1.5" stroke-dasharray="3,2"/><circle cx="17" cy="18" r="2.5" stroke-width="1.5" stroke-dasharray="3,2"/></svg>
|
||
Подобие
|
||
</button>
|
||
</div>
|
||
<div class="geo-ngon-ctrl" id="geo-scale-ctrl" style="margin-top:6px">
|
||
<span style="font-size:11px;opacity:.7">k =</span>
|
||
<button class="geo-ngon-btn" onclick="geoScaleK(-0.5)">
|
||
<svg viewBox="0 0 16 16" fill="none"><line x1="3" y1="8" x2="13" y2="8" stroke-width="2" stroke-linecap="round"/></svg>
|
||
</button>
|
||
<span id="geo-scale-k">2</span>
|
||
<button class="geo-ngon-btn" onclick="geoScaleK(+0.5)">
|
||
<svg viewBox="0 0 16 16" fill="none"><line x1="8" y1="3" x2="8" y2="13" stroke-width="2" stroke-linecap="round"/><line x1="3" y1="8" x2="13" y2="8" stroke-width="2" stroke-linecap="round"/></svg>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</details>
|
||
|
||
<details class="geo-acc">
|
||
<summary>Измерения и ГМТ</summary>
|
||
<div class="geo-acc-body geo-tool-grid">
|
||
<button id="geo-btn-measure_length" class="geo-tool-btn" onclick="geoSetTool('measure_length',this)" title="Длина отрезка — кликни на отрезок, получишь живой чип">
|
||
<svg viewBox="0 0 24 24" fill="none"><line x1="3" y1="12" x2="21" y2="12" stroke-width="2"/><line x1="3" y1="8" x2="3" y2="16" stroke-width="2" stroke-linecap="round"/><line x1="21" y1="8" x2="21" y2="16" stroke-width="2" stroke-linecap="round"/></svg>
|
||
Длина
|
||
</button>
|
||
<button id="geo-btn-measure_angle" class="geo-tool-btn" onclick="geoSetTool('measure_angle',this)" title="Угол — 3 клика: точка A, вершина, точка B">
|
||
<svg viewBox="0 0 24 24" fill="none"><path d="M3 20 L20 20" stroke-width="2" stroke-linecap="round"/><path d="M3 20 L14 6" stroke-width="2" stroke-linecap="round"/><path d="M7 20 A10 10 0 0 1 11.5 12" stroke-width="1.5" fill="none"/></svg>
|
||
Угол
|
||
</button>
|
||
<button id="geo-btn-measure_area" class="geo-tool-btn" onclick="geoSetTool('measure_area',this)" title="Площадь многоугольника — кликни на полигон">
|
||
<svg viewBox="0 0 24 24" fill="none"><polygon points="12,3 21,9 18,20 6,20 3,9" stroke-width="2" fill="none"/></svg>
|
||
Площадь
|
||
</button>
|
||
<button id="geo-btn-locus" class="geo-tool-btn" onclick="geoSetTool('locus',this)" title="ГМТ — выбери точку-мовер (on_segment/on_circle), затем целевую точку">
|
||
<svg viewBox="0 0 24 24" fill="none"><path d="M4 20 Q8 4 12 12 Q16 20 20 6" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/><circle cx="8" cy="14" r="2" fill="currentColor"/></svg>
|
||
ГМТ
|
||
</button>
|
||
<button id="geo-btn-point_on_segment" class="geo-tool-btn" onclick="geoSetTool('point_on_segment',this)" title="Точка на отрезке — кликни на отрезок, получишь скользящую точку">
|
||
<svg class="ic" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="3" y1="20" x2="21" y2="4"/><circle cx="12" cy="12" r="3" fill="currentColor" stroke="none"/></svg>
|
||
Т. на отрезке
|
||
</button>
|
||
<button id="geo-btn-point_on_circle" class="geo-tool-btn" onclick="geoSetTool('point_on_circle',this)" title="Точка на окружности — кликни на окружность, получишь скользящую точку">
|
||
<svg class="ic" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><circle cx="12" cy="3" r="2.5" fill="currentColor" stroke="none"/></svg>
|
||
Т. на круге
|
||
</button>
|
||
</div>
|
||
</details>
|
||
|
||
<details class="geo-acc">
|
||
<summary>Метки</summary>
|
||
<div class="geo-acc-body geo-tool-grid">
|
||
<button id="geo-btn-tick" class="geo-tool-btn" onclick="geoSetTool('tick',this)" title="Метки равных сторон — клик на отрезок или сторону (1–3 штриха)">
|
||
<svg viewBox="0 0 24 24" fill="none"><line x1="3" y1="20" x2="21" y2="4" stroke-width="1.5"/><line x1="11" y1="7" x2="8" y2="11" stroke-width="2" stroke-linecap="round"/><line x1="13" y1="9" x2="10" y2="13" stroke-width="2" stroke-linecap="round"/></svg>
|
||
Штрихи
|
||
</button>
|
||
<button id="geo-btn-arcmark" class="geo-tool-btn" onclick="geoSetTool('arcmark',this)" title="Метки равных углов — клик на вершину полигона (1–3 дуги)">
|
||
<svg viewBox="0 0 24 24" fill="none"><path d="M4 20 L20 20 L20 4" stroke-width="1.5" fill="none"/><path d="M8 20 A12 12 0 0 1 20 8" stroke-width="1.5" fill="none"/><path d="M11 20 A9 9 0 0 1 20 11" stroke-width="1.5" fill="none"/></svg>
|
||
Дуги
|
||
</button>
|
||
<button id="geo-btn-parallelmark" class="geo-tool-btn geo-tool-wide" onclick="geoSetTool('parallelmark',this)" title="Метки параллельных сторон — клик на отрезок (1–2 стрелки)">
|
||
<svg viewBox="0 0 24 24" fill="none"><line x1="3" y1="8" x2="21" y2="8" stroke-width="1.5"/><polyline points="9,5 13,8 9,11" stroke-width="1.8" fill="none" stroke-linecap="round" stroke-linejoin="round"/><line x1="3" y1="16" x2="21" y2="16" stroke-width="1.5"/><polyline points="9,13 13,16 9,19" stroke-width="1.8" fill="none" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||
Параллельность
|
||
</button>
|
||
</div>
|
||
</details>
|
||
|
||
<!-- Display options -->
|
||
<div class="gp-section-title" style="margin-top:6px">Параметры</div>
|
||
<label class="geo-toggle-row" onclick="geoToggle('showGrid',this)">
|
||
<span class="geo-toggle-label">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/></svg>
|
||
Сетка
|
||
</span>
|
||
<div class="geo-toggle on" id="geo-tog-showGrid"></div>
|
||
</label>
|
||
<label class="geo-toggle-row" onclick="geoToggle('showAxes',this)">
|
||
<span class="geo-toggle-label">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><line x1="12" y1="20" x2="12" y2="4"/><line x1="4" y1="12" x2="20" y2="12"/></svg>
|
||
Оси
|
||
</span>
|
||
<div class="geo-toggle on" id="geo-tog-showAxes"></div>
|
||
</label>
|
||
<label class="geo-toggle-row" onclick="geoToggle('showLabels',this)">
|
||
<span class="geo-toggle-label">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"/></svg>
|
||
Метки
|
||
</span>
|
||
<div class="geo-toggle on" id="geo-tog-showLabels"></div>
|
||
</label>
|
||
<label class="geo-toggle-row" onclick="geoToggle('showLengths',this)">
|
||
<span class="geo-toggle-label">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><line x1="4" y1="12" x2="20" y2="12"/><line x1="4" y1="8" x2="4" y2="16"/><line x1="20" y1="8" x2="20" y2="16"/></svg>
|
||
Длины
|
||
</span>
|
||
<div class="geo-toggle" id="geo-tog-showLengths"></div>
|
||
</label>
|
||
<label class="geo-toggle-row" onclick="geoToggle('showAngles',this)">
|
||
<span class="geo-toggle-label">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 20 L20 20 L20 4"/><path d="M7 20 A13 13 0 0 1 20 9"/></svg>
|
||
Углы
|
||
</span>
|
||
<div class="geo-toggle" id="geo-tog-showAngles"></div>
|
||
</label>
|
||
|
||
<!-- Stats -->
|
||
<div class="gp-section-title" style="margin-top:6px">Объектов</div>
|
||
<div style="display:flex;flex-direction:column;gap:0">
|
||
<div class="geo-stat-row"><span>Точки</span><b id="geo-st-pts">0</b></div>
|
||
<div class="geo-stat-row"><span>Отрезки</span><b id="geo-st-segs">0</b></div>
|
||
<div class="geo-stat-row"><span>Окружности</span><b id="geo-st-circs">0</b></div>
|
||
<div class="geo-stat-row"><span>Многоугольники</span><b id="geo-st-polys">0</b></div>
|
||
<div class="geo-stat-row"><span>Построения</span><b id="geo-st-constr">0</b></div>
|
||
</div>
|
||
|
||
<!-- Actions -->
|
||
<div style="margin-top:auto;padding-top:8px;display:flex;flex-direction:column;gap:4px">
|
||
<button class="gp-btn" onclick="geomSim&&geomSim.reset()" title="Очистить всё">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14H6L5 6"/></svg>
|
||
Очистить
|
||
</button>
|
||
<button class="geo-challenge-toggle" id="geo-chall-toggle-btn" onclick="geoToggleChallengePanel()" title="Открыть задачник">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>
|
||
Задачник
|
||
<span class="chall-count" id="geo-chall-count">0/5</span>
|
||
</button>
|
||
</div>
|
||
|
||
</div><!-- /.geo-panel -->
|
||
|
||
<!-- canvas area -->
|
||
<div class="geo-canvas-outer">
|
||
<canvas id="geo-canvas"></canvas>
|
||
<div class="geo-hint-bar" id="geo-hint">Кликни для добавления точки</div>
|
||
<div class="geo-del-confirm" id="geo-del-confirm">
|
||
<span id="geo-del-msg"></span>
|
||
<button class="geo-del-btn geo-del-btn-soft" id="geo-del-soft">Только этот</button>
|
||
<button class="geo-del-btn geo-del-btn-hard" id="geo-del-hard">Со всеми зависимыми</button>
|
||
<button class="geo-del-btn geo-del-btn-cancel" id="geo-del-cancel">Отмена</button>
|
||
</div>
|
||
|
||
<!-- Challenge panel (slides in from right) -->
|
||
<div class="geo-challenge-panel" id="geo-challenge-panel">
|
||
<div class="geo-chall-header">
|
||
<span class="geo-chall-header-title">Задачник</span>
|
||
<button class="geo-chall-close" onclick="geoToggleChallengePanel()">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
|
||
</button>
|
||
</div>
|
||
<div class="geo-chall-list" id="geo-chall-list">
|
||
<!-- Populated by JS -->
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div><!-- /.sim-body-wrap -->
|
||
</div><!-- /#sim-geometry -->
|
||
|
||
<!-- ── STOICHIOMETRY sim body ── -->
|
||
<div id="sim-stoichiometry" class="sim-proj-wrap" style="display:none">
|
||
<div id="stoichiometry-wrap" style="flex:1;min-height:0;overflow:hidden;"></div>
|
||
</div>
|
||
|
||
<!-- ── QUALANALYSIS sim body ── -->
|
||
<div id="sim-qualanalysis" class="sim-proj-wrap" style="display:none">
|
||
<div id="qualanalysis-wrap" style="flex:1;min-height:0;overflow:hidden;"></div>
|
||
</div>
|
||
|
||
<!-- ── ORGANIC CHEMISTRY sim body ── -->
|
||
<div id="sim-organic" class="sim-proj-wrap" style="display:none;flex:1;min-height:0;overflow:hidden;"></div>
|
||
|
||
<!-- ── HEAT ENGINE sim body ── -->
|
||
<div id="sim-heatengine" class="sim-proj-wrap" style="display:none">
|
||
<div class="sim-body-wrap" style="flex-direction:column">
|
||
|
||
<!-- top: two canvases side by side -->
|
||
<div style="display:flex;flex:1;min-height:0;gap:0">
|
||
|
||
<!-- left: PV diagram -->
|
||
<div class="proj-canvas-outer" style="flex:1">
|
||
<canvas id="he-pv-canvas"></canvas>
|
||
</div>
|
||
|
||
<!-- right: piston animation -->
|
||
<div class="proj-canvas-outer" style="width:220px;border-left:1px solid var(--border)">
|
||
<canvas id="he-piston-canvas"></canvas>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<!-- bottom: control panel -->
|
||
<div style="display:flex;gap:12px;padding:10px 14px;border-top:1px solid var(--border);flex-wrap:wrap;align-items:flex-start;background:rgba(255,255,255,0.015)">
|
||
|
||
<!-- cycle selector -->
|
||
<div style="display:flex;flex-direction:column;gap:4px;min-width:140px">
|
||
<div class="gp-section-title" style="margin-bottom:4px">Цикл</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:3px">
|
||
<button class="preset-btn he-cycle-btn active" onclick="heSetCycle('carnot',this)" style="font-size:.72rem">Карно</button>
|
||
<button class="preset-btn he-cycle-btn" onclick="heSetCycle('otto',this)" style="font-size:.72rem">Отто</button>
|
||
<button class="preset-btn he-cycle-btn" onclick="heSetCycle('diesel',this)" style="font-size:.72rem">Дизель</button>
|
||
<button class="preset-btn he-cycle-btn" onclick="heSetCycle('brayton',this)" style="font-size:.72rem">Брайтон</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- sliders -->
|
||
<div style="display:flex;flex-direction:column;gap:6px;flex:1;min-width:180px">
|
||
<div class="gp-section-title" style="margin-bottom:2px">Параметры</div>
|
||
<div class="proj-slider-row">
|
||
<label style="font-size:.78rem;color:#ccc;width:90px">T<sub>гор</sub> = <span id="he-th-val" style="color:#EF476F;font-weight:700">800</span> K</label>
|
||
<input type="range" id="sl-he-th" min="300" max="1500" step="10" value="800" oninput="heParam('Th',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row">
|
||
<label style="font-size:.78rem;color:#ccc;width:90px">T<sub>хол</sub> = <span id="he-tc-val" style="color:#06D6E0;font-weight:700">300</span> K</label>
|
||
<input type="range" id="sl-he-tc" min="200" max="500" step="10" value="300" oninput="heParam('Tc',this.value)" style="flex:1">
|
||
</div>
|
||
<div class="proj-slider-row" id="he-cr-row" style="display:none">
|
||
<label style="font-size:.78rem;color:#ccc;width:90px">r<sub>сж</sub> = <span id="he-cr-val" style="color:#FFD166;font-weight:700">8</span></label>
|
||
<input type="range" id="sl-he-cr" min="2" max="20" step="1" value="8" oninput="heParam('cr',this.value)" style="flex:1">
|
||
</div>
|
||
</div>
|
||
|
||
<!-- buttons -->
|
||
<div style="display:flex;flex-direction:column;gap:5px;min-width:120px">
|
||
<div class="gp-section-title" style="margin-bottom:2px">Управление</div>
|
||
<div style="display:flex;gap:4px">
|
||
<button onclick="heStart()" style="flex:1;padding:6px 0;border-radius:7px;border:none;background:linear-gradient(135deg,#EF476F,#9B5DE5);color:#fff;font-size:.78rem;font-weight:700;cursor:pointer" title="Старт">
|
||
<svg class="ic" viewBox="0 0 24 24"><polygon points="5 3 19 12 5 21 5 3"/></svg>
|
||
</button>
|
||
<button onclick="hePause()" style="flex:1;padding:6px 0;border-radius:7px;border:1px solid #444;background:#1a1a2e;color:#ccc;font-size:.78rem;cursor:pointer" title="Пауза">
|
||
<svg class="ic" viewBox="0 0 24 24"><rect x="6" y="4" width="4" height="16"/><rect x="14" y="4" width="4" height="16"/></svg>
|
||
</button>
|
||
<button onclick="heStep()" style="flex:1;padding:6px 0;border-radius:7px;border:1px solid #444;background:#1a1a2e;color:#ccc;font-size:.78rem;cursor:pointer" title="Шаг">
|
||
<svg class="ic" viewBox="0 0 24 24"><polygon points="5 4 15 12 5 20 5 4"/><line x1="19" y1="5" x2="19" y2="19"/></svg>
|
||
</button>
|
||
<button onclick="heReset()" style="flex:1;padding:6px 0;border-radius:7px;border:1px solid #444;background:#1a1a2e;color:#888;font-size:.78rem;cursor:pointer" title="Сброс">
|
||
<svg class="ic" viewBox="0 0 24 24"><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 .49-3.5"/></svg>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
</div><!-- /controls -->
|
||
|
||
</div><!-- /.sim-body-wrap -->
|
||
|
||
<!-- stats bar -->
|
||
<div class="proj-stats-bar">
|
||
<div class="pstat"><div class="pstat-label">T<sub>гор</sub></div><div class="pstat-val" id="hebar-th" style="color:#EF476F">800 K</div></div>
|
||
<div class="pstat"><div class="pstat-label">T<sub>хол</sub></div><div class="pstat-val" id="hebar-tc" style="color:#06D6E0">300 K</div></div>
|
||
<div class="pstat"><div class="pstat-label">η</div><div class="pstat-val" id="hebar-eta" style="color:#7BF5A4">—%</div></div>
|
||
<div class="pstat"><div class="pstat-label">Q<sub>гор</sub>, Дж</div><div class="pstat-val" id="hebar-qh" style="color:#FFD166">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">Q<sub>хол</sub>, Дж</div><div class="pstat-val" id="hebar-qc" style="color:var(--cyan)">—</div></div>
|
||
<div class="pstat"><div class="pstat-label">W, Дж</div><div class="pstat-val" id="hebar-w" style="color:var(--violet)">—</div></div>
|
||
</div>
|
||
</div><!-- /#sim-heatengine -->
|
||
|
||
<!-- ── PERIODIC TABLE sim body ── -->
|
||
<div id="sim-periodic" class="sim-proj-wrap" style="display:none">
|
||
<div id="periodic-wrap" style="flex:1;min-height:0;overflow:hidden;"></div>
|
||
</div>
|
||
|
||
<!-- ── SOLUTIONS sim body ── -->
|
||
<div id="sim-solutions" class="sim-proj-wrap" style="display:none">
|
||
<div id="solutions-wrap" style="flex:1;min-height:0;overflow:hidden;"></div>
|
||
</div>
|
||
|
||
<!-- ── Theory panel (overlay right) ── -->
|
||
<div class="theory-panel" id="theory-panel">
|
||
<div class="theory-panel-inner" id="theory-content"></div>
|
||
</div>
|
||
|
||
</div><!-- /#lab-sim -->
|
||
|
||
</div><!-- /.sb-content -->
|
||
</div><!-- /.app-layout -->
|
||
|
||
<script src="/js/api.js"></script>
|
||
<script src="/js/sidebar.js"></script>
|
||
<script src="https://cdn.jsdelivr.net/npm/three@0.149.0/build/three.min.js"></script>
|
||
<script src="/js/labs/_fx_core.js"></script>
|
||
<script src="/js/labs/_fx_particles.js"></script>
|
||
<script src="/js/labs/_fx_motion.js"></script>
|
||
<script src="/js/labs/_fx_sound.js"></script>
|
||
<script src="/js/labs/graph.js"></script>
|
||
<script src="/js/labs/_phys_visuals.js"></script>
|
||
<script src="/js/labs/emfield.js"></script>
|
||
<script src="/js/labs/triangle.js"></script>
|
||
<script src="/js/labs/_graph_panel.js"></script>
|
||
<script src="/js/labs/projectile.js"></script>
|
||
<script src="/js/labs/collision.js"></script>
|
||
<script src="/js/labs/gas.js"></script>
|
||
<script src="/js/labs/states.js"></script>
|
||
<script src="/js/labs/brownian.js"></script>
|
||
<script src="/js/labs/diffusion.js"></script>
|
||
<!-- coulomb.js removed: merged into emfield.js -->
|
||
<script src="/js/labs/circuit.js"></script>
|
||
<script src="/js/labs/_chem_visuals.js"></script>
|
||
<script src="/js/labs/reactions.js"></script>
|
||
<script src="/js/labs/flask.js"></script>
|
||
<script src="/js/labs/redox.js"></script>
|
||
<script src="/js/labs/ionexchange.js"></script>
|
||
<script src="/js/labs/stereo.js?v=2"></script>
|
||
<script src="/js/notifications.js"></script>
|
||
<script src="/js/search.js"></script>
|
||
<script src="/js/mobile.js"></script>
|
||
<script src="/js/labs/lab-init.js"></script>
|
||
<script src="/js/labs/lab-glue.js"></script>
|
||
<script src="/js/labs/newton.js"></script>
|
||
<script src="/js/labs/forcesandbox.js"></script>
|
||
<script src="/js/labs/angrybirds.js"></script>
|
||
<script src="/js/labs/waves.js"></script>
|
||
<script src="/js/labs/chemsandbox.js"></script>
|
||
<script src="/js/labs/stoichiometry.js"></script>
|
||
<script src="/js/labs/celldivision.js"></script>
|
||
<script src="/js/labs/photosynthesis.js"></script>
|
||
<script src="/js/labs/crystal.js"></script>
|
||
<script src="/js/labs/orbitals.js"></script>
|
||
<script src="/js/labs/trigcircle.js"></script>
|
||
<script src="/js/labs/_util.js"></script>
|
||
<script src="/js/labs/quadratic.js"></script>
|
||
<script src="/js/labs/normaldist.js"></script>
|
||
<script src="/js/labs/graphtransform.js"></script>
|
||
<script src="/js/labs/pendulum.js"></script>
|
||
<script src="/js/labs/equilibrium.js"></script>
|
||
<script src="/js/labs/opticsbench.js"></script>
|
||
<script src="/js/labs/isoprocess.js"></script>
|
||
<script src="/js/labs/titration.js"></script>
|
||
<script src="/js/labs/probability.js"></script>
|
||
<script src="/js/labs/bohratom.js"></script>
|
||
<script src="/js/labs/electrolysis.js"></script>
|
||
<script src="/js/labs/hydrostatics.js"></script>
|
||
<script src="/js/labs/radioactive.js"></script>
|
||
<script src="/js/labs/geometry.js"></script>
|
||
<script src="/js/labs/logic.js"></script>
|
||
<script src="/js/labs/heatengine.js"></script>
|
||
<script src="/js/labs/solutions.js" defer></script>
|
||
<script src="/js/labs/organic.js" defer></script>
|
||
<script src="/js/labs/_periodic_data.js" defer></script>
|
||
<script src="/js/labs/periodic.js" defer></script>
|
||
<script src="/js/labs/qualanalysis.js" defer></script>
|
||
<script>
|
||
/* Sync sound toggle button icon with localStorage state on load */
|
||
(function() {
|
||
var stored = localStorage.getItem('labfx-sound');
|
||
var on = stored === null ? true : stored === 'true';
|
||
var iconOn = document.getElementById('labfx-sound-icon-on');
|
||
var iconOff = document.getElementById('labfx-sound-icon-off');
|
||
var btn = document.getElementById('labfx-sound-btn');
|
||
if (!iconOn || !iconOff || !btn) return;
|
||
iconOn.style.display = on ? '' : 'none';
|
||
iconOff.style.display = on ? 'none' : '';
|
||
btn.setAttribute('aria-pressed', on ? 'true' : 'false');
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html>
|