feat(stereo): мастер-тумблер «Фигура» — скрыть тело с поля

Не было способа убрать само тело со сцены. Добавил тумблер «Фигура» в
начале секции «Отображение»: скрывает грани, рёбра, вершины и подписи тела,
оставляя сетку/оси и ВСЕ построения, точки, сечения и выделения — удобно
работать с конструкциями на «пустом» поле.

- StereoSim: флаг showFigure (деф. true) + toggleFigure(v) — переключает
  _figGroup.visible/_labelGroup.visible (флаг переживает _clearGroup, поэтому
  фигура остаётся скрытой и после перестроения при смене параметров). При
  смене типа фигуры (setFigure) тело снова показывается.
- Панель: st-toggle-row #stg-figure; диспетчер stereoToggleSt('figure');
  setStereoFigure возвращает тумблер в «вкл» для новой фигуры.

Верификация: node --check OK; headless-смоук 13/13 (деф. видна; скрытие
прячет fig+labels, но grid/construct/poly/point-группы остаются; перестроение
сохраняет скрытие; обратное включение; setFigure ре-показывает; dispose);
эмодзи/eval/new Function — 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-06-17 18:14:53 +03:00
parent 1f461e96fd
commit ce99c15895
2 changed files with 9 additions and 0 deletions
+5
View File
@@ -247,6 +247,7 @@ class StereoSim {
/* state */ /* state */
this.figureType = 'cube'; this.figureType = 'cube';
this.params = { a: 4, b: 3, c: 5, h: 5, r: 2, R: 3, n: 4 }; this.params = { a: 4, b: 3, c: 5, h: 5, r: 2, R: 3, n: 4 };
this.showFigure = true; // master: show/hide the solid itself (faces+edges+vertices+labels)
this.showEdges = true; this.showEdges = true;
this.showVertices = true; this.showVertices = true;
this.showLabels = true; this.showLabels = true;
@@ -369,6 +370,7 @@ class StereoSim {
setFigure(type) { setFigure(type) {
this.figureType = type; this.figureType = type;
this.showFigure = true; this._figGroup.visible = true; this._labelGroup.visible = true;
this._unfold = false; this._unfoldProgress = 0; this._unfoldTarget = 0; this._unfold = false; this._unfoldProgress = 0; this._unfoldTarget = 0;
this.showSection = false; this.showSection = false;
this.showInscribed = false; this.showCircumscribed = false; this.showInscribed = false; this.showCircumscribed = false;
@@ -423,6 +425,7 @@ class StereoSim {
this._buildFigure(); this._buildFigure();
} }
toggleFigure(v) { this.showFigure = v; this._figGroup.visible = v; this._labelGroup.visible = v; this._invalidate(); }
toggleEdges(v) { this.showEdges = v; this._buildFigure(); } toggleEdges(v) { this.showEdges = v; this._buildFigure(); }
toggleVertices(v) { this.showVertices = v; this._buildFigure(); } toggleVertices(v) { this.showVertices = v; this._buildFigure(); }
toggleLabels(v) { this.showLabels = v; this._buildFigure(); this._rebuildConstructions(); } toggleLabels(v) { this.showLabels = v; this._buildFigure(); this._rebuildConstructions(); }
@@ -4895,6 +4898,7 @@ class StereoSim {
['stg-height','stg-apothem','stg-diagonals','stg-midpoints','stg-inscribed','stg-circumscribed','stg-edgelengths'].forEach(id => { ['stg-height','stg-apothem','stg-diagonals','stg-midpoints','stg-inscribed','stg-circumscribed','stg-edgelengths'].forEach(id => {
document.getElementById(id)?.classList.remove('on'); document.getElementById(id)?.classList.remove('on');
}); });
document.getElementById('stg-figure')?.classList.add('on'); // new figure → visible
_stereoDeactivateTools(); _stereoDeactivateTools();
} }
} }
@@ -4978,6 +4982,7 @@ class StereoSim {
const on = !toggle.classList.contains('on'); const on = !toggle.classList.contains('on');
toggle.classList.toggle('on', on); toggle.classList.toggle('on', on);
if (!stereoSim) return; if (!stereoSim) return;
if (layer === 'figure') stereoSim.toggleFigure(on);
if (layer === 'edges') stereoSim.toggleEdges(on); if (layer === 'edges') stereoSim.toggleEdges(on);
if (layer === 'vertices') stereoSim.toggleVertices(on); if (layer === 'vertices') stereoSim.toggleVertices(on);
if (layer === 'labels') stereoSim.toggleLabels(on); if (layer === 'labels') stereoSim.toggleLabels(on);
+4
View File
@@ -3569,6 +3569,10 @@
<!-- ── Отображение ── --> <!-- ── Отображение ── -->
<div class="gp-section-title" style="margin-top:8px;margin-bottom:4px">Отображение</div> <div class="gp-section-title" style="margin-top:8px;margin-bottom:4px">Отображение</div>
<div onclick="stereoToggleSt('figure',this.querySelector('.st-toggle'))" class="st-toggle-row" title="Показать/скрыть само тело (грани, рёбра, вершины, подписи) — построения и сетка остаются">
<span class="st-toggle-label"><svg viewBox="0 0 24 24"><rect x="3" y="7" width="12" height="12"/><path d="M3 7l4-4h12v12l-4 4M15 3v12"/></svg>Фигура</span>
<div class="st-toggle on" id="stg-figure"></div>
</div>
<div onclick="stereoToggleSt('edges',this.querySelector('.st-toggle'))" class="st-toggle-row"> <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> <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 class="st-toggle on" id="stg-edges"></div>