feat: add performance monitoring for journey transitions and optimize rendering

- Introduced a new markdown file documenting the optimizations made to the journey motion rendering, including changes to CSS and React components to improve performance on low-end devices.
- Implemented a test-only JavaScript file to log layout work during automatic stop changes, tracking metrics such as name resizes, font writes, and heading replacements.
- Enhanced the journey rendering by memoizing components and reducing unnecessary re-renders, aligning with web.dev recommendations for animations and layout thrashing prevention.
This commit is contained in:
2026-10-11 15:13:05 +03:00
parent a1bb3f1c9d
commit 823ab14367
7 changed files with 167 additions and 43 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

View File

@@ -0,0 +1,37 @@
# Прокрутка остановок — 11 октября 2026
Сообщение пользователя: тормозит на Xiaomi Mi Box 4 в Hi Browser в обоих профилях. Устройство не подключено к ADB (список устройств пуст). На физическом Mi Box FPS не измерялся; результат ниже — исходный код, сравнительные счётчики в Codex in-app browser и проверка компоновки.
## Причина и изменение
В `src/styles.css` ширина ячеек анимировалась через `flex-basis`. Каждый промежуточный размер вызывал `ResizeObserver` в `FittedDestination`, измерение текста canvas и подбор шрифта с чтением/записью геометрии. Заголовки дополнительно пересоздавались при смене роли «крупный/компактный».
В `src/NextStops.tsx` выделен мемоизированный `JourneyRail`. Ячейки всегда одинаковой ширины, каждый заголовок имеет два постоянных слоя с заранее подобранным шрифтом. Положение ячеек, увеличение названия и длина линии меняются через `transform`, видимость слоёв — через `opacity`. Коэффициент увеличения согласован со свободным расстоянием до соседней остановки. Анимации ширины, цвета текста и тени маркера удалены. Во время обычного перехода размеры текста не меняются. Тики часов не запускают рендер схемы при неизменных данных; названия, минуты, количество остановок и продолжение сравниваются перед пропуском рендера.
Это соответствует [рекомендациям web.dev по анимациям](https://web.dev/articles/animations-guide) и [предотвращению повторных синхронных перерасчётов layout](https://web.dev/articles/avoid-large-complex-layouts-and-layout-thrashing). Фактический эффект на GPU конкретного браузера требует проверки на устройстве.
## Сравнение
Одинаковый стенд: 960×540, тёмная тема, расстояние «Близко», Автовокзал, фильтр №4. Сохранённое публичное расписание, тестовые часы/погода. Старая производственная сборка сохранена до правки; новая сравнивалась с ней через те же наблюдатели. По три перехода в каждом профиле, окно 1200 мс после смены остановки. Скрипт не меняет прототипы и состояние приложения, не передаёт данные наружу. Счётчики относятся только к названиям остановок, а не ко всему layout или FPS.
| Профиль / переход | Изменения размеров до → после | Записи шрифта до → после | Замены заголовков до → после |
| --- | ---: | ---: | ---: |
| ТВ, 1 → 2 | 110 → 0 | 842 → 0 | 2 → 0 |
| ТВ, 2 → 3 | 110 → 0 | 632 → 0 | 2 → 0 |
| ТВ, 3 → 4 | 110 → 0 | 838 → 0 | 2 → 0 |
| Уличное табло, 1 → 2 | 38 → 0 | 82 → 0 | 2 → 0 |
| Уличное табло, 2 → 3 | 38 → 0 | 160 → 0 | 2 → 0 |
| Уличное табло, 3 → 4 | 38 → 0 | 241 → 0 | 2 → 0 |
## Поведение
- Сохранены интервалы 4/6 секунд и движение 900/300 мс для ТВ/уличного профиля. Пауза прекращает смену остановок.
- Переход 4 → 1 выполняет мягкое появление, без обратного движения всей схемы.
- В промежуточных кадрах ТВ: ширина ячейки постоянна **189,29 px**, высота области названия **51 px**, размер шрифта **41,91 px**. Матрица масштаба меняется 0,871 → 0,984 → 1, зазор до соседней остановки — 24,38 → 27,55 → 28,00 px. Наложения нет.
- На конечной демонстрационного маршрута без продолжения: длина линии **0 px**, её начало и центр последнего маркера совпадают (65,797 / 65,796 px). Ложного продолжения нет.
- 390×667: длинное название «Больница (Новка)» целиком, высота 72,42 px при доступных 76 px; кружок 22 px.
- 1920×1080, три карточки: тот же текст высотой 129,17 px при доступных 239 px; кружок 24 px.
- Accessibility показывает по одному названию остановки: второй визуальный слой скрыт через `aria-hidden`.
- Настройки и API не расширялись. Режим reduced motion отключает переходы и освобождает подсказки слоёв. Счётчики тестового стенда отсутствуют в production bundle и Docker runtime.
Проверки: `npm run build` (TypeScript + Vite), 10 тестов маршрута/информационных блоков, синтаксис двух файлов стенда и `git diff --check` прошли. Снимок — `journey-motion-960x540.jpg`. Для обновления серверного табло необходимо развернуть файлы и пересобрать образ.