feat(map): add reference layers and stabilize workspace controls
This commit is contained in:
+19
-2
@@ -39,7 +39,7 @@ FieldFrame объединяет label, control, hint и description. TextField/T
|
||||
|
||||
## RangeControl
|
||||
|
||||
Pill-range с заполнением акцентным цветом, встроенной подписью и значением. Домен определяет min/max/step и формат числа.
|
||||
Pill-range с заполнением акцентным цветом, встроенной подписью и значением. Домен определяет min/max/step и формат числа. Drag всегда принадлежит невидимому native range и продолжается под областью значения. Над числом постоянно смонтирован один прозрачный native text input: клик включает редактирование без замены DOM-узла, браузер ставит каретку в фактическое место клика, а drag-selection остаётся нативным. Поле не получает собственной подложки, select-all или второго focus-ring. Enter/blur применяют значение с clamp/step-нормализацией, Escape отменяет ввод; события редактора не всплывают в оконные shortcuts. Оконный focus-manager выполняет начальный autofocus только при открытии и не отбирает фокус при последующих ререндерах.
|
||||
|
||||
## ColorField
|
||||
|
||||
@@ -92,7 +92,19 @@ Window — единая механика открытия modal и правой
|
||||
|
||||
`WorkspaceWindow` — modeless-окно внутри рабочей сцены приложения. Оно рендерится непосредственно в переданном workspace, не использует portal и не может перекрыть шапку, навигацию или соседние панели за пределами этого workspace.
|
||||
|
||||
Приложение контролирует `rect`, `maximized`, видимость, active-state и `zIndex`. Компонент владеет pointer/keyboard-механикой перемещения и изменения размера, кнопками maximize/restore и close, а также повторно ограничивает геометрию при изменении размеров workspace через `ResizeObserver`. Родительский bounds-контейнер должен быть позиционированным и обрезать содержимое (`position: relative; overflow: hidden`).
|
||||
На Map Page `WorkspaceWindow` используется и для facet-групп, и для
|
||||
provider-neutral карточки выбранного subject. Chevron внутри facet-строки
|
||||
владеет только раскрытием дерева subjects; тело строки сохраняет действие
|
||||
фильтра. Смена совместимого subject не пересоздаёт карточку и не сбрасывает
|
||||
активную вкладку. Joined data-product aspects не создают отдельные окна или
|
||||
слои, а наполняют декларативные секции существующей карточки.
|
||||
|
||||
Справочные точки транспорта используют тот же renderer adapter, но отдельный
|
||||
slot `reference-points`. Их три presentation profiles (`Метро`, `Вокзалы`,
|
||||
`Станции РЖД`) являются живыми каноническими Inspector sections: приложение
|
||||
может менять высоту, размер, label и LOD, не создавая provider-specific UI.
|
||||
|
||||
Приложение контролирует `rect`, `maximized`, видимость, active-state и `zIndex`. Компонент владеет pointer/keyboard-механикой перемещения и изменения размера, кнопками maximize/restore и close, а также повторно ограничивает геометрию при изменении размеров workspace через `ResizeObserver`. Опциональный `autoHeight` подгоняет высоту под живое содержимое и сжимает её обратно, не выходя за нижнюю границу workspace. Родительский bounds-контейнер должен быть позиционированным и обрезать содержимое (`position: relative; overflow: hidden`).
|
||||
|
||||
Окно предназначено для вспомогательных камер, инструментов и сопоставляемых представлений внутри сцены. Modal workflow, подтверждение и viewport-level Inspector по-прежнему используют `Window`.
|
||||
|
||||
@@ -228,6 +240,11 @@ Inspector владеет:
|
||||
- вертикальным ритмом;
|
||||
- раскладкой label/control.
|
||||
|
||||
В uncontrolled-режиме начальные секции задаёт `defaultOpen`. Для layout-aware
|
||||
приложений Inspector поддерживает controlled-пару
|
||||
`openSections/onOpenSectionsChange`: она позволяет общей кнопке Save сохранять
|
||||
точную конфигурацию раскрытых секций и восстанавливать её без remount-default.
|
||||
|
||||
Для Engine Environment Settings desktop-контракт точный: окно `390 px`, рабочая колонка `330 px`, строка `154 + 14 + 162 px`, высота контрола `46 px`, section header `50 px` с радиусом `12 px`. Accent-filled section headers и полноширинные range/checker/select сохраняют геометрию исходника.
|
||||
|
||||
Engine продолжает владеть определениями полей, типами нод и сохранением значений. В живом catalog эти collapsible sections находятся в `Guideline → Контролы`; отдельной product-вкладки Inspector нет.
|
||||
|
||||
@@ -59,8 +59,70 @@ profile; renderer не содержит provider-specific условий.
|
||||
`aspectId`. Соединение выполняется по стабильному `sourceId`; provider endpoint,
|
||||
credentials и raw payload в Application Manifest не попадают.
|
||||
|
||||
В меню `Объекты` показываются только primary bindings. Joined aspects
|
||||
(`technical profile`, `contacts`, `identity` и следующие типизированные
|
||||
проекции) не являются самостоятельными слоями карты: они дополняют карточку
|
||||
выбранного primary subject и потому не дублируются в меню. Если пользователь
|
||||
переключает один subject на другой с совместимым detail profile, активная
|
||||
вкладка карточки сохраняется; отсутствующие поля и секции не создаются.
|
||||
|
||||
Строка facet в окне объектов разделяет два действия. Клик по телу по-прежнему
|
||||
применяет facet-фильтр, а отдельный chevron раскрывает список совпавших
|
||||
subjects. Выбор subject в списке открывает его карточку и переносит текущую
|
||||
композицию камеры к точке. Адаптер повторяет проверенную механику legacy
|
||||
MMAP/AIS: сохраняет `heading`, `pitch`, `roll` и смещение камеры относительно
|
||||
центра viewport; длительность перелёта для текущего канонического workflow —
|
||||
`2.1 s`.
|
||||
|
||||
Facet-фильтры поддерживают мультивыбор: OR внутри одного facet и AND между facets. Missing facet означает отсутствие ограничения, а явно пустой список — ноль совпадений. Отжатие последнего chip не включает `Все`; `Все` включается и выключается только явным кликом. Переключение фильтра не двигает камеру, обзор выполняется отдельным действием.
|
||||
|
||||
## Platform reference layers
|
||||
|
||||
Станции метро, железнодорожные станции и вокзалы не являются L1/L2 workflow и
|
||||
не материализуются как пользовательский Data Product. Это медленно меняющийся
|
||||
provider-neutral справочный слой Platform Map Gateway:
|
||||
|
||||
```text
|
||||
OSM/approved seed → Map Gateway spatial cache → map.station | map.terminal
|
||||
→ reference-points → Foundry presentation profile → renderer
|
||||
```
|
||||
|
||||
Контракт `transport-stations.v1` возвращает только allowlisted проекцию:
|
||||
стабильный `sourceId`, нормализованный semantic type, категорию, названия,
|
||||
оператора/сеть, допустимые официальные идентификаторы и координаты. Raw OSM
|
||||
payload, upstream endpoint, credentials и произвольные tags в Foundry не
|
||||
попадают. Начальный snapshot Москвы получен из legacy L1 MMAP как donor и
|
||||
разделён на три категории: `metro`, `railway_station`,
|
||||
`railway_terminal`. За пределами snapshot Map Gateway может последовательно
|
||||
загрузить spatial cells из OSM и сохраняет нормализованный результат в
|
||||
persistent cache; повторный viewport читается локально.
|
||||
|
||||
Page Layout хранит три независимых reference bindings:
|
||||
|
||||
- `reference.transport.metro` → `map.reference.transport.metro.v1`;
|
||||
- `reference.transport.railway_terminal` →
|
||||
`map.reference.transport.terminal.v1`;
|
||||
- `reference.transport.railway_station` →
|
||||
`map.reference.transport.railway-station.v1`.
|
||||
|
||||
Каждый профиль отдельно управляет видимостью, высотой таргета, размером точки,
|
||||
подписью и высотой скрытия через обычный Inspector. Старые сохранённые Map
|
||||
Layout получают зарегистрированные reference bindings и profiles при чтении;
|
||||
их файл не переписывается до явного сохранения пользователем.
|
||||
|
||||
Тот же Page Layout хранит `inspectorOpenSections`. В текущем single-open
|
||||
Inspector это пустой список либо id ровно одной раскрытой секции. Поэтому
|
||||
закрытие окна настроек и повторное открытие не сбрасывает аккордеон, а общая
|
||||
кнопка Application Save сохраняет его вместе с камерой и остальным layout.
|
||||
|
||||
Cesium adapter рендерит elevated targets и label plates как единый overlay над
|
||||
terrain, buildings и imagery (`disableDepthTestDistance`). Цветная обводка
|
||||
головки остаётся частью `elevated-spike` profile. Головка рисуется как
|
||||
billboard до label-слоя, поэтому непрозрачная плашка нормально перекрывает
|
||||
лежащий под ней маркер вместо «рентгеновского» проступания его обводки. Text
|
||||
outline плашки отключён и не создаёт дополнительный halo. Контуры
|
||||
`surface-fill` остаются частью отдельного контракта геозон.
|
||||
|
||||
## Acceptance fixtures
|
||||
|
||||
- `registry/fixtures/map/map-empty-offline-v0.1.json` — отсутствие provider/live data без разрушения shell и управляющих действий.
|
||||
@@ -118,6 +180,8 @@ semantic types, field projection, `presentationProfileId`, optional
|
||||
`subjectDetailProfileId`, `aspectId`/`joinToBindingId` и `slotId`: `points`
|
||||
для live point entities, `zones` для polygon/multipolygon `map.zone` или
|
||||
`subject-details` для non-spatial current aspects выбранного объекта.
|
||||
Platform-owned справочные сущности используют отдельный `reference-points`
|
||||
slot и не подменяют этот Data Product contract.
|
||||
При открытии Application page browser делает same-origin запрос к Foundry:
|
||||
|
||||
```text
|
||||
|
||||
@@ -95,8 +95,9 @@ Foundry и без неописанного generic JSON.
|
||||
|
||||
`foundry_save_map_page_view_state` является MCP-эквивалентом одной Application
|
||||
кнопки `Сохранить`. Операция атомарно сохраняет camera/map height, typed patch
|
||||
base settings, exact visibility/facet selections и все canonical binding
|
||||
windows (`open`, `rect`, `maximized`, `zIndex`). Состояние keyed только по
|
||||
base settings, точный список раскрытых секций Inspector, exact
|
||||
visibility/facet selections и все canonical binding windows (`open`, `rect`,
|
||||
`maximized`, `zIndex`). Состояние keyed только по
|
||||
`bindingId`: editable `displayName` не участвует в identity. Missing facet не
|
||||
ограничивает выборку, явно пустой список остаётся empty после reopen и не
|
||||
мигрирует обратно в `Все`.
|
||||
|
||||
Reference in New Issue
Block a user