7.8 KiB
7.8 KiB
Phase 1: Графики + интеракции
Status: ✅ Implemented (не закоммичено — коммит за оркестратором) Parent plan: PLAN.md Domain: frontend
Objective
Добавить в рантайм графики (plot-объекты), перетаскиваемые ручки (drag → параметр), векторы и числовые readout. После фазы спека со слайдером, draggable-точкой и live-графиком работает.
Tasks
- 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. - Draggable-ручка:
point/circleсdrag:{ param, axis:'x|y|xy', min,max, paramY? }— перетаскивание мышью/тачем (pointer events) меняет параметр(ы); позиция ручки следует за параметром (x/y объекта = тот же параметр). Хит-тест в экранных px (допуск 16px), приоритет ручек. Clamp поdrag.min/maxИ по диапазону самого параметра. - Readout:
{ type:'readout', label, expr, unit, precision, x?, y? }— живой бейдж; мягкая ошибка черезevalSafe(NaN/синтаксис → «—», не роняет цикл). Без позиции — авто-столбик в верх-правом углу. - Vector-объект с привязкой к
origin:[ox,oy]+dx/dy-выражениям + стрелка (x1/y1/x2/y2 тоже поддержаны). Стрелка уже была в Ф0. - Тач-поддержка drag (pointer events +
touchAction:none), не ломая логику лабы (слушатели только на canvas движка, снимаются в destroy). - Обновить демо-спеку: +слайдеры 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
- Все задачи выполнены
- Drag работает мышью и тачем (pointer events; headless-тест clamp/sync OK)
- Нет регрессий рантайма Ф0 (рендер всех 8 типов демо × 6 кадров без ошибок; point/segment/circle/rect/polyline/path/vector/label не тронуты в логике)
- Нет эмодзи, стиль проекта (скан кодпойнтов — чисто; 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.
Формат новых типов спеки (точные поля)
// график выражения (мир-координаты)
{ 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/unitreadout надо санитизировать как текст. - 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.