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:
+463
-1
@@ -1,4 +1,4 @@
|
||||
'use strict';
|
||||
'use strict';
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
NewtonSim — три закона Ньютона
|
||||
Закон I : A — скользящий блок, B — шар на нити
|
||||
@@ -1202,3 +1202,465 @@ function _nwt_lighten(hex, d) {
|
||||
const c = v => Math.max(0, Math.min(255, v));
|
||||
return `rgb(${c((n >> 16) + d)},${c(((n >> 8) & 255) + d)},${c((n & 255) + d)})`;
|
||||
}
|
||||
|
||||
/* ─── lab UI init ─────────────────────────────────── */
|
||||
var newtonSim = null;
|
||||
var sandboxSim = null;
|
||||
let _dynMode = 'sandbox'; // current mode: 'sandbox' | 'law1' | 'law2' | 'law3'
|
||||
|
||||
function _openDynamics(preset) {
|
||||
document.getElementById('sim-topbar-title').textContent = 'Динамика';
|
||||
_simShow('sim-dynamics');
|
||||
_simShow('ctrl-dynamics');
|
||||
requestAnimationFrame(() => requestAnimationFrame(() => {
|
||||
// init sandbox
|
||||
const sbCanvas = document.getElementById('sandbox-canvas');
|
||||
if (!sandboxSim) {
|
||||
sandboxSim = new ForceSandboxSim(sbCanvas);
|
||||
sandboxSim.onUpdate = _sbUpdateUI;
|
||||
}
|
||||
// init newton
|
||||
const nwCanvas = document.getElementById('newton-canvas');
|
||||
if (!newtonSim) {
|
||||
newtonSim = new NewtonSim(nwCanvas);
|
||||
newtonSim.onUpdate = _newtonUpdateUI;
|
||||
}
|
||||
// activate current mode
|
||||
dynMode(_dynMode);
|
||||
if (preset) setTimeout(() => sbPreset(preset), 120);
|
||||
}));
|
||||
}
|
||||
|
||||
function dynMode(mode, btn) {
|
||||
_dynMode = mode;
|
||||
const isSandbox = mode === 'sandbox';
|
||||
|
||||
// toggle mode buttons
|
||||
document.querySelectorAll('.dyn-mode').forEach(b => b.classList.remove('active'));
|
||||
const modeBtn = document.getElementById('dyn-mode-' + mode);
|
||||
if (modeBtn) modeBtn.classList.add('active');
|
||||
|
||||
// toggle panels
|
||||
document.getElementById('dyn-sandbox-panel').style.display = isSandbox ? '' : 'none';
|
||||
document.getElementById('dyn-newton-panel').style.display = isSandbox ? 'none' : '';
|
||||
|
||||
// toggle canvases
|
||||
document.getElementById('sandbox-canvas').style.display = isSandbox ? 'block' : 'none';
|
||||
document.getElementById('newton-canvas').style.display = isSandbox ? 'none' : 'block';
|
||||
|
||||
// toggle topbar tool groups
|
||||
document.getElementById('ctrl-dyn-sb').style.display = isSandbox ? 'contents' : 'none';
|
||||
document.getElementById('ctrl-dyn-nw').style.display = isSandbox ? 'none' : 'contents';
|
||||
|
||||
if (isSandbox) {
|
||||
// stop newton, start sandbox
|
||||
if (newtonSim) newtonSim.stop();
|
||||
if (sandboxSim) { sandboxSim.fit(); sandboxSim.start(); }
|
||||
_sbUpdateUI(sandboxSim ? sandboxSim.info() : null);
|
||||
} else {
|
||||
// stop sandbox, switch newton law
|
||||
if (sandboxSim) sandboxSim.stop();
|
||||
const lawN = mode === 'law1' ? 1 : mode === 'law2' ? 2 : 3;
|
||||
if (newtonSim) {
|
||||
newtonSim.setLaw(lawN);
|
||||
newtonSim.fit();
|
||||
newtonSim.start();
|
||||
_newtonSyncUI();
|
||||
_newtonUpdateUI(newtonSim.info());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function dynPause() {
|
||||
if (_dynMode === 'sandbox') {
|
||||
if (sandboxSim) sandboxSim.togglePause();
|
||||
} else {
|
||||
if (newtonSim) newtonSim.togglePause();
|
||||
}
|
||||
}
|
||||
|
||||
function dynReset() {
|
||||
if (_dynMode === 'sandbox') {
|
||||
sbReset();
|
||||
} else {
|
||||
_resetNewtonScene();
|
||||
}
|
||||
}
|
||||
|
||||
const _NEWTON_SCENES = {
|
||||
1: {
|
||||
A: { desc: 'Закон инерции: тело скользит по поверхности. Нажми на canvas — толкни блок.', action: null },
|
||||
B: { desc: 'Инерция в орбите: шар вращается на нити. Отруби нить — полетит по касательной!', action: '<svg class="ic" viewBox="0 0 24 24"><circle cx="6" cy="6" r="3"/><circle cx="6" cy="18" r="3"/><line x1="20" y1="4" x2="8.12" y2="15.88"/><line x1="14.47" y1="14.48" x2="20" y2="20"/><line x1="8.12" y1="8.12" x2="12" y2="12"/></svg> Отрубить нить' },
|
||||
C: { desc: 'Инерция в космосе: тело движется равномерно, нет сил — нет ускорения.', action: null },
|
||||
},
|
||||
2: {
|
||||
A: { desc: 'Второй закон: F = ma. Прикладывай силу и следи за ускорением и скоростью.', action: '<svg class="ic" viewBox="0 0 24 24"><polygon points="5 3 19 12 5 21 5 3"/></svg> Запустить' },
|
||||
B: { desc: 'Два тела, разные массы — одинаковая сила. Сравни ускорения!', action: '<svg class="ic" viewBox="0 0 24 24"><polygon points="5 3 19 12 5 21 5 3"/></svg> Запустить' },
|
||||
C: { desc: 'Второй закон: изменяй силу и массу ползунками, наблюдай в реальном времени.', action: '<svg class="ic" viewBox="0 0 24 24"><polygon points="5 3 19 12 5 21 5 3"/></svg> Запустить' },
|
||||
},
|
||||
3: {
|
||||
A: { desc: 'Третий закон: пушка выстрелила — отдача. Импульс сохраняется!', action: 'Выстрел' },
|
||||
B: { desc: 'Третий закон: два шара сталкиваются — силы равны и противоположны.', action: '<svg class="ic" viewBox="0 0 24 24"><polygon points="5 3 19 12 5 21 5 3"/></svg> Столкнуть' },
|
||||
C: { desc: 'Реактивное движение: ракета выбрасывает газ — летит в обратную сторону.', action: 'Двигатель' },
|
||||
},
|
||||
};
|
||||
|
||||
const _NEWTON_PRESETS = {
|
||||
1: [
|
||||
{ label: 'Космос', fn: 'space' },
|
||||
{ label: 'Лёд', fn: 'ice' },
|
||||
{ label: 'Асфальт', fn: 'asphalt' },
|
||||
{ label: 'Резина', fn: 'rubber' },
|
||||
],
|
||||
2: [
|
||||
{ label: 'Лёгкий', fn: 'light' },
|
||||
{ label: 'Тяжёлый', fn: 'heavy' },
|
||||
{ label: 'Сравнить', fn: 'compare' },
|
||||
],
|
||||
3: [
|
||||
{ label: 'Большая пушка', fn: 'big_cannon' },
|
||||
{ label: 'Маленькая', fn: 'small_cannon' },
|
||||
{ label: 'Равные шары', fn: 'equal_balls' },
|
||||
],
|
||||
};
|
||||
|
||||
// _openNewton is now handled by _openDynamics + dynMode
|
||||
|
||||
// newtonLaw is now handled by dynMode('law1'/'law2'/'law3')
|
||||
|
||||
function newtonScene(s, topBtn, panelBtn) {
|
||||
if (!newtonSim) return;
|
||||
newtonSim.setScene(s);
|
||||
document.querySelectorAll('.nscene-btn').forEach(b => {
|
||||
b.classList.toggle('active', b.id === 'nscn-' + s || b.id === 'nscn-panel-' + s);
|
||||
});
|
||||
_newtonSyncUI();
|
||||
_newtonUpdateUI(newtonSim.info());
|
||||
}
|
||||
|
||||
function _newtonSyncUI() {
|
||||
if (!newtonSim) return;
|
||||
const law = newtonSim.law;
|
||||
const scene = newtonSim.scene;
|
||||
const sceneData = (_NEWTON_SCENES[law] || {})[scene] || {};
|
||||
|
||||
// description
|
||||
const desc = document.getElementById('newton-scene-desc');
|
||||
if (desc) desc.textContent = sceneData.desc || '';
|
||||
|
||||
// action button label
|
||||
const lbl = sceneData.action || (law === 1 ? '<svg class="ic" viewBox="0 0 24 24"><circle cx="6" cy="6" r="3"/><circle cx="6" cy="18" r="3"/><line x1="20" y1="4" x2="8.12" y2="15.88"/><line x1="14.47" y1="14.48" x2="20" y2="20"/><line x1="8.12" y1="8.12" x2="12" y2="12"/></svg> Нить' : '<svg class="ic" viewBox="0 0 24 24"><polygon points="5 3 19 12 5 21 5 3"/></svg> Действие');
|
||||
document.getElementById('newton-action-label').textContent = lbl;
|
||||
document.getElementById('newton-action-top').textContent = lbl;
|
||||
|
||||
// show/hide sliders
|
||||
document.getElementById('newton-mu-block').style.display = law === 1 && scene === 'A' ? '' : 'none';
|
||||
document.getElementById('newton-mass1-block').style.display = (law === 2 || law === 3) ? '' : 'none';
|
||||
document.getElementById('newton-mass2-block').style.display = law === 3 ? '' : 'none';
|
||||
document.getElementById('newton-force-block').style.display = law === 2 ? '' : 'none';
|
||||
|
||||
// sync slider values from sim
|
||||
document.getElementById('sl-newton-mu').value = newtonSim.mu;
|
||||
document.getElementById('newton-mu-val').textContent = newtonSim.mu.toFixed(2);
|
||||
document.getElementById('sl-newton-m1').value = newtonSim.mass1;
|
||||
document.getElementById('newton-m1-val').textContent = newtonSim.mass1 + ' кг';
|
||||
document.getElementById('sl-newton-m2').value = newtonSim.mass2;
|
||||
document.getElementById('newton-m2-val').textContent = newtonSim.mass2 + ' кг';
|
||||
document.getElementById('sl-newton-F').value = newtonSim.force;
|
||||
document.getElementById('newton-F-val').textContent = newtonSim.force + ' Н';
|
||||
|
||||
// sync scene highlight buttons in both topbar and panel
|
||||
['A','B','C'].forEach(s => {
|
||||
const tb = document.getElementById('nscn-' + s);
|
||||
const pb = document.getElementById('nscn-panel-' + s);
|
||||
const on = s === scene;
|
||||
if (tb) tb.classList.toggle('active', on);
|
||||
if (pb) pb.classList.toggle('active', on);
|
||||
});
|
||||
|
||||
// presets
|
||||
const presetsEl = document.getElementById('newton-presets');
|
||||
const presets = _NEWTON_PRESETS[law] || [];
|
||||
presetsEl.innerHTML = presets.map(p =>
|
||||
`<button class="proj-preset-chip" onclick="newtonPreset('${p.fn}')">${p.label}</button>`
|
||||
).join('');
|
||||
|
||||
// scene B/C visibility for law I (B = orbital, C = space — but law I only has A,B)
|
||||
// scene C doesn't exist for law I/II panel scene picker visibility
|
||||
const cBtn = document.getElementById('nscn-panel-C');
|
||||
const cTopBtn = document.getElementById('nscn-C');
|
||||
const showC = law === 3;
|
||||
if (cBtn) cBtn.style.display = showC ? '' : 'none';
|
||||
if (cTopBtn) cTopBtn.style.display = showC ? '' : 'none';
|
||||
const bBtn = document.getElementById('nscn-panel-B');
|
||||
const bTopBtn = document.getElementById('nscn-B');
|
||||
const showB = law !== 2 || true; // law 2 has compare scene B
|
||||
if (bBtn) bBtn.style.display = '';
|
||||
if (bTopBtn) bTopBtn.style.display = '';
|
||||
}
|
||||
|
||||
function newtonAction() {
|
||||
if (!newtonSim) return;
|
||||
const law = newtonSim.law;
|
||||
const scene = newtonSim.scene;
|
||||
if (law === 1 && scene === 'B') newtonSim.cutString();
|
||||
else if (law === 2) newtonSim.startL2();
|
||||
else if (law === 3 && scene === 'A') newtonSim.fireCannon();
|
||||
else if (law === 3 && scene === 'B') newtonSim._reset3B ? newtonSim._reset3B() : null;
|
||||
else if (law === 3 && scene === 'C') newtonSim.toggleRocket();
|
||||
_newtonUpdateUI(newtonSim.info());
|
||||
}
|
||||
|
||||
function _resetNewtonScene() {
|
||||
if (!newtonSim) return;
|
||||
const law = newtonSim.law;
|
||||
const scene = newtonSim.scene;
|
||||
if (law === 1 && scene === 'A') newtonSim.preset('ice');
|
||||
else if (law === 1) newtonSim.setScene(scene);
|
||||
else if (law === 2) newtonSim.resetL2 ? newtonSim.resetL2() : newtonSim.setScene(scene);
|
||||
else newtonSim.setScene(scene);
|
||||
_newtonUpdateUI(newtonSim.info());
|
||||
}
|
||||
|
||||
function newtonMuChange() {
|
||||
const v = +document.getElementById('sl-newton-mu').value;
|
||||
document.getElementById('newton-mu-val').textContent = v.toFixed(2);
|
||||
if (newtonSim) newtonSim.setMu(v);
|
||||
}
|
||||
|
||||
function newtonMass1Change() {
|
||||
const v = +document.getElementById('sl-newton-m1').value;
|
||||
document.getElementById('newton-m1-val').textContent = v + ' кг';
|
||||
if (newtonSim) newtonSim.setMass1(v);
|
||||
}
|
||||
|
||||
function newtonMass2Change() {
|
||||
const v = +document.getElementById('sl-newton-m2').value;
|
||||
document.getElementById('newton-m2-val').textContent = v + ' кг';
|
||||
if (newtonSim) newtonSim.setMass2(v);
|
||||
}
|
||||
|
||||
function newtonForceChange() {
|
||||
const v = +document.getElementById('sl-newton-F').value;
|
||||
document.getElementById('newton-F-val').textContent = v + ' Н';
|
||||
if (newtonSim) newtonSim.setForce(v);
|
||||
}
|
||||
|
||||
function newtonPreset(name) {
|
||||
if (!newtonSim) return;
|
||||
newtonSim.preset(name);
|
||||
_newtonSyncUI();
|
||||
_newtonUpdateUI(newtonSim.info());
|
||||
}
|
||||
|
||||
function _newtonUpdateUI(info) {
|
||||
if (!info) return;
|
||||
const law = info.law;
|
||||
const scene = info.scene;
|
||||
|
||||
if (law === 1 && scene === 'A') {
|
||||
document.getElementById('dbar-l1').textContent = 'Закон I-A';
|
||||
document.getElementById('dbar-v1').textContent = 'Скольжение';
|
||||
document.getElementById('dbar-l2').textContent = 'Скорость';
|
||||
document.getElementById('dbar-v2').textContent = info.v + ' м/с';
|
||||
document.getElementById('dbar-l3').textContent = 'Сила трения';
|
||||
document.getElementById('dbar-v3').textContent = info.fFr + ' Н';
|
||||
document.getElementById('dbar-l4').textContent = 'Масса';
|
||||
document.getElementById('dbar-v4').textContent = info.m + ' кг';
|
||||
document.getElementById('dbar-l5').textContent = 'μ';
|
||||
document.getElementById('dbar-v5').textContent = info.mu;
|
||||
} else if (law === 1) {
|
||||
document.getElementById('dbar-l1').textContent = 'Закон I-B';
|
||||
document.getElementById('dbar-v1').textContent = info.cut ? 'Нить срублена' : 'Вращение';
|
||||
document.getElementById('dbar-l2').textContent = 'Скорость';
|
||||
document.getElementById('dbar-v2').textContent = info.v + ' м/с';
|
||||
document.getElementById('dbar-l3').textContent = '';
|
||||
document.getElementById('dbar-v3').textContent = '—';
|
||||
document.getElementById('dbar-l4').textContent = '';
|
||||
document.getElementById('dbar-v4').textContent = '—';
|
||||
document.getElementById('dbar-l5').textContent = '';
|
||||
document.getElementById('dbar-v5').textContent = '—';
|
||||
} else if (law === 2) {
|
||||
document.getElementById('dbar-l1').textContent = 'Закон II';
|
||||
document.getElementById('dbar-v1').textContent = 'F = ma';
|
||||
document.getElementById('dbar-l2').textContent = 'Сила F';
|
||||
document.getElementById('dbar-v2').textContent = info.F + ' Н';
|
||||
document.getElementById('dbar-l3').textContent = 'Масса m';
|
||||
document.getElementById('dbar-v3').textContent = info.m + ' кг';
|
||||
document.getElementById('dbar-l4').textContent = 'Ускор. a';
|
||||
document.getElementById('dbar-v4').textContent = info.a + ' м/с²';
|
||||
document.getElementById('dbar-l5').textContent = 'Скорость';
|
||||
document.getElementById('dbar-v5').textContent = info.v + ' м/с';
|
||||
} else if (scene === 'A') {
|
||||
document.getElementById('dbar-l1').textContent = 'Закон III-A';
|
||||
document.getElementById('dbar-v1').textContent = 'Пушка';
|
||||
document.getElementById('dbar-l2').textContent = 'v снаряда';
|
||||
document.getElementById('dbar-v2').textContent = info.vBall !== '—' ? info.vBall + ' м/с' : '—';
|
||||
document.getElementById('dbar-l3').textContent = 'v пушки';
|
||||
document.getElementById('dbar-v3').textContent = info.vCannon + ' м/с';
|
||||
document.getElementById('dbar-l4').textContent = 'm снаряда';
|
||||
document.getElementById('dbar-v4').textContent = info.m1 + ' кг';
|
||||
document.getElementById('dbar-l5').textContent = 'm пушки';
|
||||
document.getElementById('dbar-v5').textContent = info.m2 + ' кг';
|
||||
} else if (scene === 'B') {
|
||||
document.getElementById('dbar-l1').textContent = 'Закон III-B';
|
||||
document.getElementById('dbar-v1').textContent = 'Удар';
|
||||
document.getElementById('dbar-l2').textContent = 'p₁';
|
||||
document.getElementById('dbar-v2').textContent = info.p1 + ' кг·м/с';
|
||||
document.getElementById('dbar-l3').textContent = 'p₂';
|
||||
document.getElementById('dbar-v3').textContent = info.p2 + ' кг·м/с';
|
||||
document.getElementById('dbar-l4').textContent = 'p суммарный';
|
||||
document.getElementById('dbar-v4').textContent = info.pt + ' кг·м/с';
|
||||
document.getElementById('dbar-l5').textContent = '';
|
||||
document.getElementById('dbar-v5').textContent = '—';
|
||||
} else {
|
||||
document.getElementById('dbar-l1').textContent = 'Закон III-C';
|
||||
document.getElementById('dbar-v1').textContent = 'Ракета';
|
||||
document.getElementById('dbar-l2').textContent = 'Ускорение';
|
||||
document.getElementById('dbar-v2').textContent = info.a + ' м/с²';
|
||||
document.getElementById('dbar-l3').textContent = 'Скорость';
|
||||
document.getElementById('dbar-v3').textContent = info.v + ' м/с';
|
||||
document.getElementById('dbar-l4').textContent = 'Масса';
|
||||
document.getElementById('dbar-v4').textContent = info.m + ' кг';
|
||||
document.getElementById('dbar-l5').textContent = 'Топливо';
|
||||
document.getElementById('dbar-v5').textContent = info.fuel + '%';
|
||||
}
|
||||
}
|
||||
|
||||
// _openSandbox is now handled by _openDynamics + dynMode
|
||||
|
||||
function sbTool(t, btn) {
|
||||
if (!sandboxSim) return;
|
||||
sandboxSim.tool = t;
|
||||
sandboxSim._springStart = null;
|
||||
sandboxSim._ropeStart = null;
|
||||
document.querySelectorAll('.sb-tool-btn').forEach(b => b.classList.toggle('active', b.id === 'sbt-' + t));
|
||||
document.querySelectorAll('.sb-panel-tool').forEach(b => b.classList.toggle('active', b.id === 'sbpt-' + t));
|
||||
const canvas = document.getElementById('sandbox-canvas');
|
||||
canvas.style.cursor = t === 'erase' ? 'not-allowed'
|
||||
: (t === 'spring' || t === 'rope') ? 'cell'
|
||||
: t === 'anchor' ? 'copy'
|
||||
: 'crosshair';
|
||||
document.getElementById('sb-spring-block').style.display = t === 'spring' ? '' : 'none';
|
||||
}
|
||||
|
||||
function sbSpringKChange() {
|
||||
const v = +document.getElementById('sl-sb-springk').value;
|
||||
document.getElementById('sb-springk-val').textContent = v + ' Н/м';
|
||||
if (sandboxSim) sandboxSim.newSpringK = v;
|
||||
}
|
||||
|
||||
function sbForceMode(m, btn) {
|
||||
if (!sandboxSim) return;
|
||||
sandboxSim.forceMode = m;
|
||||
document.querySelectorAll('.sb-fmode').forEach(b => b.classList.toggle('active', b.id === 'sbfm-' + m));
|
||||
}
|
||||
|
||||
function sbMassChange() {
|
||||
const v = +document.getElementById('sl-sb-mass').value;
|
||||
document.getElementById('sb-mass-val').textContent = v + ' кг';
|
||||
if (sandboxSim) sandboxSim.newMass = v;
|
||||
}
|
||||
|
||||
function sbRestChange() {
|
||||
const v = +document.getElementById('sl-sb-rest').value;
|
||||
document.getElementById('sb-rest-val').textContent = v.toFixed(2);
|
||||
if (sandboxSim) sandboxSim.newRestitution = v;
|
||||
}
|
||||
|
||||
function sbFloorMuChange() {
|
||||
const v = +document.getElementById('sl-sb-floormu').value;
|
||||
document.getElementById('sb-floormu-val').textContent = v.toFixed(2);
|
||||
if (sandboxSim) sandboxSim.floorMu = v;
|
||||
}
|
||||
|
||||
function sbWorldToggle() {
|
||||
if (!sandboxSim) return;
|
||||
sandboxSim.gravity = document.getElementById('sb-gravity').checked;
|
||||
sandboxSim.hasFloor = document.getElementById('sb-floor').checked;
|
||||
sandboxSim.hasWalls = document.getElementById('sb-walls').checked;
|
||||
sandboxSim.airDrag = document.getElementById('sb-airdrag').checked;
|
||||
}
|
||||
|
||||
function sbRampToggle() {
|
||||
if (!sandboxSim) return;
|
||||
const on = document.getElementById('sb-ramp').checked;
|
||||
sandboxSim.setRamp(on);
|
||||
document.getElementById('sb-ramp-block').style.display = on ? '' : 'none';
|
||||
}
|
||||
|
||||
function sbAngleChange() {
|
||||
const v = +document.getElementById('sl-sb-angle').value;
|
||||
document.getElementById('sb-angle-val').textContent = v + '°';
|
||||
if (sandboxSim) sandboxSim.setRampAngle(v);
|
||||
}
|
||||
|
||||
function sbRampMuChange() {
|
||||
const v = +document.getElementById('sl-sb-rampmu').value;
|
||||
document.getElementById('sb-rampmu-val').textContent = v.toFixed(2);
|
||||
if (sandboxSim) sandboxSim.setRampMu(v);
|
||||
}
|
||||
|
||||
function sbDecompToggle() {
|
||||
if (!sandboxSim) return;
|
||||
sandboxSim.showDecomp = document.getElementById('sb-decomp').checked;
|
||||
}
|
||||
|
||||
function sbDisplayToggle() {
|
||||
if (!sandboxSim) return;
|
||||
sandboxSim.showForces = document.getElementById('sb-forces').checked;
|
||||
sandboxSim.showVelocity = document.getElementById('sb-vel').checked;
|
||||
sandboxSim.showFBD = document.getElementById('sb-fbd').checked;
|
||||
sandboxSim.showEnergy = document.getElementById('sb-energy').checked;
|
||||
sandboxSim.showTrail = document.getElementById('sb-trail').checked;
|
||||
}
|
||||
|
||||
function sbTimeScale(v, btn) {
|
||||
if (!sandboxSim) return;
|
||||
sandboxSim.timeScale = v;
|
||||
document.querySelectorAll('.sb-time').forEach(b => b.classList.remove('active'));
|
||||
if (btn) btn.classList.add('active');
|
||||
}
|
||||
|
||||
function sbPreset(name) {
|
||||
if (!sandboxSim) return;
|
||||
sandboxSim.preset(name);
|
||||
// sync world checkboxes
|
||||
document.getElementById('sb-gravity').checked = sandboxSim.gravity;
|
||||
document.getElementById('sb-floor').checked = sandboxSim.hasFloor;
|
||||
document.getElementById('sb-walls').checked = sandboxSim.hasWalls;
|
||||
document.getElementById('sb-airdrag').checked = sandboxSim.airDrag;
|
||||
document.getElementById('sl-sb-floormu').value = sandboxSim.floorMu;
|
||||
document.getElementById('sb-floormu-val').textContent = sandboxSim.floorMu.toFixed(2);
|
||||
// sync ramp
|
||||
document.getElementById('sb-ramp').checked = sandboxSim.ramp;
|
||||
document.getElementById('sb-ramp-block').style.display = sandboxSim.ramp ? '' : 'none';
|
||||
document.getElementById('sl-sb-angle').value = sandboxSim.rampAngle;
|
||||
document.getElementById('sb-angle-val').textContent = sandboxSim.rampAngle + '°';
|
||||
document.getElementById('sl-sb-rampmu').value = sandboxSim.rampMu;
|
||||
document.getElementById('sb-rampmu-val').textContent = sandboxSim.rampMu.toFixed(2);
|
||||
_sbUpdateUI(sandboxSim.info());
|
||||
}
|
||||
|
||||
function sbReset() {
|
||||
if (!sandboxSim) return;
|
||||
sandboxSim.reset();
|
||||
_sbUpdateUI(sandboxSim.info());
|
||||
}
|
||||
|
||||
function _sbUpdateUI(info) {
|
||||
if (!info) return;
|
||||
document.getElementById('dbar-l1').textContent = 'Тел / связей';
|
||||
document.getElementById('dbar-v1').textContent = info.bodies + ' / ' + (info.springs + info.ropes);
|
||||
document.getElementById('dbar-l2').textContent = 'KE (Дж)';
|
||||
document.getElementById('dbar-v2').textContent = info.KE;
|
||||
document.getElementById('dbar-l3').textContent = 'PE (Дж)';
|
||||
document.getElementById('dbar-v3').textContent = info.PE;
|
||||
document.getElementById('dbar-l4').textContent = 'ΣF';
|
||||
document.getElementById('dbar-v4').textContent = info.netF;
|
||||
document.getElementById('dbar-l5').textContent = 'Время';
|
||||
document.getElementById('dbar-v5').textContent = info.time + ' с';
|
||||
}
|
||||
|
||||
/* ── chem sandbox ── */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user