Recording puck: point direction triangle UP (no jitter)

The direction triangle jumped around in GPS mode: rotation was set to the geo
heading with rotateWithView adding map._bearing, and the two desynced (they
should cancel in course-up but updated at different times). Since the map already
rotates the active heading to the top, travel direction is always screen-up —
so just point the triangle up (no rotateWithView, no per-frame rotation), shown
whenever a heading is known. Compass mode still to be tested.
This commit is contained in:
4aiman 2026-08-25 20:48:27 +03:00
commit fe20a4d590
2 changed files with 12 additions and 12 deletions

View file

@ -130,7 +130,7 @@
### Экраны
- **Сегодня** — баланс ккал, еда (продукты + блюда), GPS тренировки, активность, вес, сон, добавки, прогресс-бар жидкости, нутриенты (приход + запасы)
- **Продукты** — подтабы [Продукты | Рецепты], поиск, карточки с КБЖУ, добавление в дневник
- **Трек** — GPS тренировки (запись с HR), карта с компасом (leaflet-rotate). Навигационный «пак» позиции (SVG divIcon, `rotateWithView`): круг цвета трека (на 20% темнее) с белой + 1px чёрной обводкой + треугольник-направленец по АКТИВНОМУ источнику (компас/GPS-курс). Мини-компас только в режиме компаса. Z-order панелями: тайлы < дороги(`roadsPane` 240) < маршрут(`routePane` 250) < трек(overlay) < пак(marker). course-up по GPS-курсу (карта и панель доворачиваются в ландшафт вместе, `bearing = h`), ландшафтный режим (CSS rotation), графики скорости/высоты/ЧСС, импорт GPX/FTB, dead reckoning, placeholder до GPS, карта дорог (дедуп 2м, цвета по вело/пешие/бег), сохранённые маршруты (оверлей-навигация, кнопка-тоггл «М», предпросмотр с профилем высоты, топо/уклон-обводка, тоггл «∡/⛰», высоты по цепочке GPXZ→open-elevation→open-meteo→OpenTopoData), де-джиттер трека (Савицкий-Голей, кнопка «≈» на детали)
- **Трек** — GPS тренировки (запись с HR), карта с компасом (leaflet-rotate). Навигационный «пак» позиции (SVG divIcon): круг цвета трека (на 20% темнее) с белой + 1px чёрной обводкой + треугольник, указывающий ВВЕРХ (карта и так доворачивается активным источником — курс/компас — вверх, поэтому без покадрового поворота: не трясёт). Мини-компас только в режиме компаса. Z-order панелями: тайлы < дороги(`roadsPane` 240) < маршрут(`routePane` 250) < трек(overlay) < пак(marker). course-up по GPS-курсу (карта и панель доворачиваются в ландшафт вместе, `bearing = h`), ландшафтный режим (CSS rotation), графики скорости/высоты/ЧСС, импорт GPX/FTB, dead reckoning, placeholder до GPS, карта дорог (дедуп 2м, цвета по вело/пешие/бег), сохранённые маршруты (оверлей-навигация, кнопка-тоггл «М», предпросмотр с профилем высоты, топо/уклон-обводка, тоггл «∡/⛰», высоты по цепочке GPXZ→open-elevation→open-meteo→OpenTopoData), де-джиттер трека (Савицкий-Голей, кнопка «≈» на детали)
- **Добавки** — 41 нутриент (витамины, минералы, жирные кислоты, женьшень, ресвератрол, CoQ10)
- **Настройки** — профиль, образ жизни, нормы ЧСС/давления, BLE пульсометр, велосипеды, GPS конфиг (в т.ч. цвет трека `trackColor`, цвета дорог, GPXZ-ключ), OTA обновления, импорт тайлов, карта дорог

View file

@ -3699,29 +3699,29 @@ async function renderRecordingInline(container) {
// rotateWithView keeps the geo-heading correct while the map turns.
let puckFill = darkenHex(GPS.config.trackColor || "#bb86fc", 0.8);
let meMarker = null, meHasTri = false;
function activeHeading() {
let h = orientMode === "course" ? courseHeading : smoothedHeading;
return (h == null) ? null : h;
// The map already rotates to put the active heading UP (course-up in GPS mode,
// compass-up in compass mode), so travel direction is always screen-up. So the
// puck triangle just points UP — no per-frame rotation. (Computing rotation from
// heading + map bearing desynced and jittered badly.) The icon lives in
// markerPane (norotatePane), which never rotates with the map, so "up" stays up.
function haveHeading() {
return (orientMode === "course" ? courseHeading : smoothedHeading) != null;
}
function updateMe(ll) {
let h = activeHeading(), wantTri = h != null;
let wantTri = haveHeading();
if (!meMarker) {
meMarker = L.marker(ll, { icon: posPuckIcon(puckFill, wantTri), rotation: h || 0, rotateWithView: true, pane: "markerPane", interactive: false, keyboard: false }).addTo(map);
meMarker = L.marker(ll, { icon: posPuckIcon(puckFill, wantTri), pane: "markerPane", interactive: false, keyboard: false }).addTo(map);
meHasTri = wantTri;
} else {
meMarker.setLatLng(ll);
if (wantTri !== meHasTri) { meMarker.setIcon(posPuckIcon(puckFill, wantTri)); meHasTri = wantTri; }
meMarker.options.rotation = h || 0;
meMarker.update();
}
}
// Refresh only the direction (rotation/triangle) — called when heading changes.
// Show/hide the direction triangle when a heading becomes (un)available.
function refreshMe() {
if (!meMarker) return;
let h = activeHeading(), wantTri = h != null;
let wantTri = haveHeading();
if (wantTri !== meHasTri) { meMarker.setIcon(posPuckIcon(puckFill, wantTri)); meHasTri = wantTri; }
meMarker.options.rotation = h || 0;
meMarker.update();
}
// Base heading = chosen source. GPS mode rotates by course when we have it, else falls