refactor: distribute lab-init.js into 34 engine files

lab-init.js: 4098 -> 543 lines (infrastructure + THEORY only)

Each sim's _open*() + UI helpers moved to its engine file:
graph.js, projectile.js, collision.js, magnetic.js, triangle.js,
geometry.js, trigcircle.js, gas.js (molphys), coulomb.js, circuit.js,
reactions.js (chemistry), newton.js (dynamics), chemsandbox.js,
celldivision.js, photosynthesis.js, angrybirds.js, quadratic.js,
normaldist.js, graphtransform.js, pendulum.js, equilibrium.js,
thinlens.js, mirror.js, isoprocess.js, titration.js, refraction.js,
probability.js, bohratom.js, electrolysis.js, waves.js,
crystal.js, orbitals.js, stereo.js, hydrostatics.js

All 34 engine files syntax-checked OK.
This commit is contained in:
Maxim Dolgolyov
2026-05-08 14:54:54 +03:00
parent d5f77bb648
commit ae31e4c4e8
35 changed files with 3657 additions and 3589 deletions
+95 -1
View File
@@ -1,4 +1,4 @@
'use strict';
'use strict';
/* ══════════════════════════════════════════════════════════════
MirrorSim v3
Flat / Concave / Convex · 1/f = 1/d + 1/d' · M = -d'/d
@@ -1003,3 +1003,97 @@ class MirrorSim {
cv.addEventListener('touchend', () => { this._drag=null; });
}
}
/* ─── lab UI init ─────────────────────────────────── */
var mirrorSim = null;
function _openMirror() {
document.getElementById('sim-topbar-title').textContent = 'Зеркала';
_simShow('sim-mirrors');
_registerSimState('mirrors', () => mirrorSim?.getParams(), st => mirrorSim?.setParams(st));
if (_embedMode) _startStateEmit('mirrors');
requestAnimationFrame(() => requestAnimationFrame(() => {
if (!mirrorSim) {
mirrorSim = new MirrorSim(document.getElementById('mirror-canvas'));
mirrorSim.onUpdate = _mirrorUpdateUI;
mirrorSim.onAnimate = (d) => {
const sl = document.getElementById('sl-mirror-d');
const lbl = document.getElementById('mirror-d-val');
if (sl) sl.value = Math.round(d);
if (lbl) lbl.textContent = Math.round(d);
};
}
mirrorSim.fit();
mirrorSim.draw();
mirrorSim._emit();
if (mirrorSim._showPhotons && !mirrorSim._photonRaf) mirrorSim._startPhotons();
}));
}
function mirrorType(type, el) {
document.querySelectorAll('.mirror-type-btn').forEach(b => b.classList.remove('active'));
if (el) el.classList.add('active');
const fRow = document.getElementById('mirror-f-row');
if (fRow) fRow.style.display = type === 'flat' ? 'none' : 'flex';
if (mirrorSim) mirrorSim.setType(type);
const pb = document.getElementById('mirror-play-btn');
if (pb) { pb.textContent = '▶ Анимация'; }
const sl = document.getElementById('sl-mirror-d');
if (sl) sl.disabled = false;
}
function mirrorParam(name, val) {
const v = parseFloat(val);
const ids = { f: 'mirror-f-val', d: 'mirror-d-val', h: 'mirror-h-val' };
const el = document.getElementById(ids[name]);
if (el) el.textContent = v;
if (mirrorSim) mirrorSim.setParams({ [name]: v });
}
function mirrorPreset(name) {
const P = {
flat: { type: 'flat', f: 120, d: 200, h: 60 },
far: { type: 'concave', f: 100, d: 280, h: 60 },
'2f': { type: 'concave', f: 100, d: 200, h: 60 },
between: { type: 'concave', f: 100, d: 140, h: 60 },
near: { type: 'concave', f: 100, d: 60, h: 60 },
convex: { type: 'convex', f: 100, d: 200, h: 60 },
};
const p = P[name]; if (!p) return;
document.querySelectorAll('.mirror-type-btn').forEach(b => b.classList.remove('active'));
const tb = document.getElementById(`mtype-${p.type}`);
if (tb) tb.classList.add('active');
const fRow = document.getElementById('mirror-f-row');
if (fRow) fRow.style.display = p.type === 'flat' ? 'none' : 'flex';
document.getElementById('sl-mirror-f').value = p.f; document.getElementById('mirror-f-val').textContent = p.f;
document.getElementById('sl-mirror-d').value = p.d; document.getElementById('mirror-d-val').textContent = p.d;
document.getElementById('sl-mirror-h').value = p.h; document.getElementById('mirror-h-val').textContent = p.h;
if (mirrorSim) { mirrorSim.setType(p.type); mirrorSim.setParams({ f: p.f, d: p.d, h: p.h }); }
}
function mirrorTogglePlay(btn) {
if (!mirrorSim) return;
mirrorSim.togglePlay();
const playing = mirrorSim._playing;
if (btn) btn.textContent = playing ? '⏸ Стоп' : '▶ Анимация';
const sl = document.getElementById('sl-mirror-d');
if (sl) sl.disabled = playing;
}
function mirrorSetSpeed(val) { if (mirrorSim) mirrorSim.setAnimSpeed(parseFloat(val)); }
function mirrorToggle(name, val) { if (mirrorSim) mirrorSim.setToggle(name, val); }
function mirrorStepNext() { if (mirrorSim) mirrorSim.stepNext(); }
function mirrorStepReset() { if (mirrorSim) mirrorSim.stepReset(); }
function mirrorSetPointMode(val) { if (mirrorSim) mirrorSim.setPointMode(val); }
function _mirrorUpdateUI(info) {
const v = (id, val) => { const el = document.getElementById(id); if (el) el.textContent = val; };
v('mirrorbar-v1', info.f);
v('mirrorbar-v5', Math.round(info.d));
v('mirrorbar-v2', info.dPrime === Infinity ? '∞' : info.dPrime);
v('mirrorbar-v3', info.M === Infinity ? '∞' : info.M);
v('mirrorbar-v4', info.imageType);
}
/* ── isoprocesses ── */