From 1df7b066306097c48a58a9651024853a44135a97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=BB=D1=8C=D1=8F=D1=81=20=D0=A1=D1=83=D0=BB=D1=82?= =?UTF-8?q?=D0=B0=D0=BD=D0=BE=D0=B2?= Date: Fri, 28 Aug 2026 13:29:11 +0300 Subject: [PATCH] =?UTF-8?q?fix(gps):=20=D0=B8=D0=BD=D1=84=D0=BE-=D0=BF?= =?UTF-8?q?=D0=B0=D0=BD=D0=B5=D0=BB=D1=8C=20=D1=82=D0=BE=D1=87=D0=BA=D0=B8?= =?UTF-8?q?=20=D1=82=D1=80=D0=B5=D0=BA=D0=B0=20=D0=B2=D0=BC=D0=B5=D1=81?= =?UTF-8?q?=D1=82=D0=BE=20balloon=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B0=D0=B9?= =?UTF-8?q?=D0=B4=D0=B5=D1=80=D0=B0=20(=D0=B2=D1=80=D0=B5=D0=BC=D1=8F/?= =?UTF-8?q?=D1=81=D0=BA=D0=BE=D1=80=D0=BE=D1=81=D1=82=D1=8C/=D0=BD=D0=B0?= =?UTF-8?q?=D0=BF=D1=80=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20+=20?= =?UTF-8?q?=D0=BF=D0=BB=D0=B5=D0=B9=D1=85=D0=B5=D0=B4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/pages/gps/RoutesTab.tsx | 49 +++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/client/src/pages/gps/RoutesTab.tsx b/client/src/pages/gps/RoutesTab.tsx index b6c3cde..f8a60d7 100644 --- a/client/src/pages/gps/RoutesTab.tsx +++ b/client/src/pages/gps/RoutesTab.tsx @@ -259,22 +259,20 @@ export function GpsRoutesTab() { const displayedPoints = activePoints.filter((_, idx) => idx % trackPointsStep === 0); const pointsThinned = displayedPoints.length < activePoints.length; - // Попап точки трека: время, скорость (км/ч), направление, координаты - const pointPopupHtml = (p: GpsTrackPoint): string => { - const time = new Date(p.recordedAt).toLocaleString('ru-RU'); - const speed = p.speed != null ? `${Math.round(p.speed)} км/ч` : '—'; - const course = p.course != null ? `
Направление: ${Math.round(p.course)}°` : ''; - return `${time}
Скорость: ${speed}${course}
${p.lat.toFixed(6)}, ${p.lng.toFixed(6)}`; - }; + // Формат даты/времени точки для инфо-панели + const pointTime = (p: GpsTrackPoint): string => new Date(p.recordedAt).toLocaleString('ru-RU'); - // Клик по точке трека: попап (на уровне карты) + плейхед на эту точку + // Клик по точке трека: инфо-панель + плейхед на эту точку const seekToPoint = (p: GpsTrackPoint) => { + setSelectedPoint(p); setPlayTs(new Date(p.recordedAt).getTime()); setPlayEpoch((e) => e + 1); }; // Раскраска трека по скорости (включена по умолчанию) const [colorize, setColorize] = useState(true); + // Выбранная кликом точка трека — инфо-панель поверх карты (вместо balloon карты) + const [selectedPoint, setSelectedPoint] = useState(null); // Сегменты трека, окрашенные по скорости в начальной точке сегмента. // При > 800 точек прореживаем до ~800 для раскраски (базовая полилиния @@ -324,7 +322,6 @@ export function GpsRoutesTab() { kind: 'dot' as const, color: '#64748b', course: p.course ?? undefined, - popup: pointPopupHtml(p), onClick: () => seekToPoint(p), noCluster: true, zIndex: 2, @@ -399,12 +396,34 @@ export function GpsRoutesTab() { )} - +
+ + {/* Инфо-панель выбранной точки трека (своя, не balloon карты) */} + {selectedPoint && ( +
+
+ {pointTime(selectedPoint)} + +
+
Скорость: {selectedPoint.speed != null ? `${Math.round(selectedPoint.speed)} км/ч` : '—'}
+ {selectedPoint.course != null &&
Направление: {Math.round(selectedPoint.course)}°
} +
{selectedPoint.lat.toFixed(6)}, {selectedPoint.lng.toFixed(6)}
+
Плейхед установлен на эту точку
+
+ )} +
{/* Легенда раскраски трека по скорости */} {colorizeEnabled && (