Files
Learn_System/plans/sim-builder/phase-1-plots-interactions.md
T

84 lines
7.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Phase 1: Графики + интеракции
**Status:** ✅ Implemented (не закоммичено — коммит за оркестратором)
**Parent plan:** [PLAN.md](./PLAN.md)
**Domain:** frontend
## Objective
Добавить в рантайм графики (plot-объекты), перетаскиваемые ручки (drag → параметр),
векторы и числовые readout. После фазы спека со слайдером, draggable-точкой и live-графиком работает.
## Tasks
- [x] Plot-объект в спеке: `{ type:'plot', expr:'...', var:'x', range:[a,b], samples, trace? }`
рисует график выражения; `trace:true` — накапливает след по `t`. Решение: рисуем на canvas движка в мир-координатах (НЕ тянем `GraphPanelUI` — он stacked time-series в фикс. оверлее, не `y=f(x)` инлайн). `samples` деф. 200, клампится 2..2000.
- [x] Draggable-ручка: `point`/`circle` с `drag:{ param, axis:'x|y|xy', min,max, paramY? }` — перетаскивание мышью/тачем (pointer events) меняет параметр(ы); позиция ручки следует за параметром (x/y объекта = тот же параметр). Хит-тест в экранных px (допуск 16px), приоритет ручек. Clamp по `drag.min/max` И по диапазону самого параметра.
- [x] Readout: `{ type:'readout', label, expr, unit, precision, x?, y? }` — живой бейдж; мягкая ошибка через `evalSafe` (NaN/синтаксис → «—», не роняет цикл). Без позиции — авто-столбик в верх-правом углу.
- [x] Vector-объект с привязкой к `origin:[ox,oy]` + `dx`/`dy`-выражениям + стрелка (x1/y1/x2/y2 тоже поддержаны). Стрелка уже была в Ф0.
- [x] Тач-поддержка drag (pointer events + `touchAction:none`), не ломая логику лабы (слушатели только на canvas движка, снимаются в destroy).
- [x] Обновить демо-спеку: +слайдеры x0/y0, draggable-старт (axis xy), plot траектории y(x), 2 readout (дальность R, высота H).
## Files to Modify/Create
- `frontend/js/labs/_sim_engine.js` — типы plot/readout/vector, drag-интеракции (modify)
- `frontend/js/labs/_sim_demo.js` — расширить демо (modify)
## Acceptance Criteria
- Перетаскивание ручки меняет параметр; зависимые объекты/график обновляются.
- График строится по выражению; trace накапливает след во времени.
- Readout показывает живое значение. Тач работает.
## Notes
- Drag не должен конфликтовать с pan/zoom рантайма (если есть). Приоритет хит-теста — ручки.
- Сэмплинг графика разумный (без фриза на больших range).
## Review Checklist
- [x] Все задачи выполнены
- [x] Drag работает мышью и тачем (pointer events; headless-тест clamp/sync OK)
- [x] Нет регрессий рантайма Ф0 (рендер всех 8 типов демо × 6 кадров без ошибок; point/segment/circle/rect/polyline/path/vector/label не тронуты в логике)
- [x] Нет эмодзи, стиль проекта (скан кодпойнтов — чисто; IIFE-стиль)
## Handoff to Next Phase
### Что готово (Phase 1) — только `_sim_engine.js` + `_sim_demo.js`
- **plot** — график выражения `f(var)` на отрезке, рисуется на canvas движка в мир-координатах.
- **drag** — `point`/`circle` становятся ручками; pointer events (мышь+тач); clamp двойной (drag.min/max + диапазон параметра).
- **readout** — живой бейдж на оверлее (тот же `_labelLayer`), мягкая ошибка через `SimExpr.evalSafe`.
- **vector** — добавлена форма `origin:[ox,oy]+dx/dy` (конец = origin + (dx,dy)); старая `x1/y1/x2/y2` сохранена; стрелка из Ф0.
### Формат новых типов спеки (точные поля)
```jsonc
// график выражения (мир-координаты)
{ type:'plot', expr:'sin(x)', var:'x', // var деф. 'x'
range:[a,b], // числа/выражения; деф. xmin..xmax
samples?:200, // клампится 2..2000
trace?:false, // true: точка (var=t) пишется в trail по времени;
// при trace без range статич. кривая НЕ рисуется
color?, width? }
// перетаскиваемая ручка (на point/circle)
{ type:'point', x:'x0', y:'y0',
drag:{ param:'x0', // axis x|y -> этот параметр; xy -> X
axis:'x'|'y'|'xy', // деф. 'x'
paramY:'y0', // ТОЛЬКО axis:'xy' -> Y (обязателен для 2D)
min?, max? } } // деф. ±Infinity; доп. clamp по диапазону параметра
// живой числовой бейдж
{ type:'readout', expr:'...', label?:'R', unit?:'м', precision?:2, // precision 0..8, деф.2
x?, y?, // мир-коорд.; без них — авто-столбик верх-право
color? }
// вектор (новая форма)
{ type:'vector', origin:[ox,oy], dx:'...', dy:'...', color?, width? }
```
### API инстанса (без изменений сигнатуры)
`mount(host,spec) -> { play, pause, reset, setParam, getParam, isRunning, destroy, el }`.
Добавлены внутр.: `_toWorld(px,py)`, `_setupDrag`, `_applyDrag`, `_setParamClamped`, `_drawPlot`, `_drawReadout`, `_accumPlotTrace`, `_paramRange`.
### Осталось / риски / на Фазу 2 (физика)
- **Однопроходный env** (`obj.x/obj.y`): из Ф0 — взаимные «вперёд»-ссылки дают значение прошлого кадра. Не трогал; при физике может потребоваться топосорт.
- **Drag только point/circle.** Тащить за конец вектора/вершину polyline — не реализовано (не требовалось).
- **readout позиционирование** на canvas — через DOM-оверлей (`_labelLayer`), как label. На сервере (Ф3) `label`/`unit` readout надо санитизировать как текст.
- **plot и trace на больших range**: ограничены `samples<=2000` и trail `<=2000` точек — без фриза. Очень большие range с тонкой кривой при экстремальном zoom могут ступенчатить — норм для учебных сцен.
- **Физика (`body`/`physics`)** — Фаза 2. Plot/drag/readout/vector полностью совместимы с физ-объектами (drag может задавать начальные условия, readout — читать body-величины, если их положить в env в Ф2).
-`lab.html` и `lab-glue.js` НЕ трогались (зона параллельной сессии). Новых файлов не создавал — всё в `_sim_engine.js`/`_sim_demo.js`.