Files
wiki/tasks/enduro-trails/DEV_TASK_PHASE5_UX3.md
2026-05-05 22:30:06 +03:00

4.9 KiB
Raw Blame History

Dev Task: Enduro Trails — UX маршрута дополнение (drag + дистанции)

Приоритет: HIGH
Проект: enduro-trails
Дата: 2026-05-05
Дополнение к: DEV_TASK_PHASE5_UX2.md


Задача 5: Drag точек в основном sheet — не закрывать sheet

Проблема

Сейчас в _initWaypointDragHandles после drop вызывается debounceBuildRoute() — это нормально. Но где-то в цепочке sheet закрывается.

Нужное поведение

При перетаскивании точек в #waypoints-list (основной sheet открыт):

  • Sheet остаётся открытым
  • Маршрут пересчитывается в фоне (колесо в мини-баре)
  • После пересчёта — обновить карточки маршрута прямо в открытом sheet

Изменения

В endDrag() внутри _initWaypointDragHandles:

function endDrag(finalClientY) {
  if (dragIdx < 0) return;
  clearHighlights();
  const dy = Math.abs(finalClientY - startY);

  if (dragging && dy > 30 && lastOverEl !== null) {
    const dropIdx = parseInt(lastOverEl.dataset.idx, 10);
    let insertAt = lastOverPos === 'top' ? dropIdx : dropIdx + 1;
    const moved = routeWaypoints.splice(dragIdx, 1)[0];
    if (insertAt > dragIdx) insertAt--;
    routeWaypoints.splice(insertAt, 0, moved);
    rebuildWaypointMarkers();
    renderWaypointsList();
    // НЕ закрывать sheet — просто пересчитать маршрут
    if (routeWaypoints.length >= 2) {
      showMiniRouteLoading(); // колесо в мини-баре
      debounceBuildRoute();
    }
    updateMiniRouteCard();
  }

  dragIdx = -1;
  dragging = false;
  lastOverEl = null;
  lastOverPos = null;
}

В buildRoute() — после успешного построения, если основной sheet открыт, обновить карточки без закрытия:

// После drawRouteResults(routeResults, 0):
const sheetOpen = document.getElementById('sheet-route')?.classList.contains('open');
if (sheetOpen) {
  renderRouteCards(routeResults); // обновить карточки в открытом sheet
} else {
  showMiniRouteSheet(); // показать мини-бар
}
hideMiniRouteLoading();

Задача 6: Расстояние между точками в wl-item

Нужное поведение

В каждом wl-item (кроме первой точки) показывать расстояние от предыдущей точки.

Формат:

  • < 1 км → "130 м"
  • ≥ 1 км → "2,3 км" (запятая как разделитель)

Реализация

Добавить функцию форматирования дистанции между точками:

function formatSegmentDist(m) {
  if (m < 1000) return Math.round(m) + ' м';
  return (m / 1000).toFixed(1).replace('.', ',') + ' км';
}

Использовать haversine для расчёта расстояния между соседними точками:

function haversineM(a, b) {
  const R = 6371000;
  const dLat = (b.lat - a.lat) * Math.PI / 180;
  const dLon = (b.lon - a.lon) * Math.PI / 180;
  const s = Math.sin(dLat/2)**2 + Math.cos(a.lat*Math.PI/180) * Math.cos(b.lat*Math.PI/180) * Math.sin(dLon/2)**2;
  return R * 2 * Math.atan2(Math.sqrt(s), Math.sqrt(1-s));
}

В renderWaypointsList() добавить дистанцию в каждый wl-item (кроме первого):

routeWaypoints.map((wp, i) => {
  // ...
  const distStr = i > 0 ? formatSegmentDist(haversineM(routeWaypoints[i-1], wp)) : '';
  return `<div class="wl-item" id="wl-item-${i}" data-idx="${i}">
    <div class="wl-pin">${waypointPinSvg(label, color)}</div>
    <div class="wl-info">
      <span class="wl-label" id="wl-label-${i}">${coordText}</span>
      ${distStr ? `<span class="wl-dist">${distStr}</span>` : ''}
    </div>
    <div class="wl-drag-handle" data-idx="${i}">${gripSvg}</div>
    <button class="wl-remove" onclick="removeWaypoint(${i})" ...>...</button>
  </div>`;
})

CSS для .wl-dist:

.wl-info { display: flex; flex-direction: column; flex: 1; min-width: 0; }
.wl-label { font-size: 13px; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.wl-dist { font-size: 11px; color: var(--text3); margin-top: 1px; }

Деплой

/tmp/deploy_static.js
SSH: host=82.22.50.71, port=22, user=slin, pass=motoZ@yaz2010
Health: curl -s http://mva154:5558/api/health

Ограничения

  • НЕ трогать app.py
  • Без npm-зависимостей
  • Реализовать поверх изменений из DEV_TASK_PHASE5_UX2.md (они уже в коде или деплоятся параллельно)