feat(stereo3d): Фаза 1 — камера и навигация (инерция, pan, пресеты, скриншот)

- инерция орбиты с затуханием; панорамирование (ПКМ/СКМ/Shift+ЛКМ, 2 пальца)
- орбита вокруг сдвигаемого таргета (_panOffset)
- overlay-тулбар: сброс вида + пресеты ракурса (Изо/Спереди/Сбоку/Сверху)
- тумблер авто-вращения с реальным засыпанием loop, fullscreen, снимок PNG
- a11y-атрибуты на кнопках; bump stereo.js?v=4

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-05-30 11:13:04 +03:00
parent 96a2097e70
commit 7c598d6430
4 changed files with 253 additions and 26 deletions
+25 -2
View File
@@ -4119,8 +4119,31 @@
<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-outer" style="position:relative">
<div class="graph-canvas-wrap" id="stereo-container"></div>
<!-- ── view controls overlay ── -->
<div class="st-view-toolbar">
<div class="st-view-group" role="group" aria-label="Ракурс">
<button class="st-view-preset active" onclick="stereoPreset('iso',this)" title="Изометрия">Изо</button>
<button class="st-view-preset" onclick="stereoPreset('front',this)" title="Вид спереди">Спер.</button>
<button class="st-view-preset" onclick="stereoPreset('side',this)" title="Вид сбоку">Сбоку</button>
<button class="st-view-preset" onclick="stereoPreset('top',this)" title="Вид сверху">Сверху</button>
</div>
<div class="st-view-group" role="group" aria-label="Действия с видом">
<button class="st-view-btn" onclick="stereoResetView()" title="Сбросить вид" aria-label="Сбросить вид">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 1 0 3-6.7L3 8"/><path d="M3 3v5h5"/></svg>
</button>
<button class="st-view-btn active" id="st-spin-btn" onclick="stereoToggleSpin(this)" title="Авто-вращение" aria-label="Авто-вращение" aria-pressed="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 1 1-2.6-6.3"/><path d="M21 4v5h-5"/></svg>
</button>
<button class="st-view-btn" onclick="stereoFullscreen()" title="Во весь экран" aria-label="Во весь экран">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 3H5a2 2 0 0 0-2 2v3M21 8V5a2 2 0 0 0-2-2h-3M16 21h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3"/></svg>
</button>
<button class="st-view-btn" onclick="stereoScreenshot()" title="Снимок PNG" aria-label="Снимок PNG">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"/><circle cx="12" cy="13" r="4"/></svg>
</button>
</div>
</div>
</div>
</div>
@@ -4794,7 +4817,7 @@
<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=3"></script>
<script src="/js/labs/stereo.js?v=4"></script>
<script src="/js/notifications.js"></script>
<script src="/js/search.js"></script>
<script src="/js/mobile.js"></script>