fix(gps): инфо-панель точки трека вместо balloon провайдера (время/скорость/направление + плейхед)

This commit is contained in:
2026-08-28 13:29:11 +03:00
parent 3ea0f8c187
commit 1df7b06630

View File

@@ -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 ? `<br/>Направление: ${Math.round(p.course)}°` : '';
return `<b>${time}</b><br/>Скорость: ${speed}${course}<br/>${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<GpsTrackPoint | null>(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() {
</div>
)}
<GpsMap
bounds={bounds}
polylines={mapPolylines}
markers={mapMarkers}
className="h-[55vh] min-h-[350px] w-full rounded-md overflow-hidden border border-border"
/>
<div className="relative">
<GpsMap
bounds={bounds}
polylines={mapPolylines}
markers={mapMarkers}
className="h-[55vh] min-h-[350px] w-full rounded-md overflow-hidden border border-border"
/>
{/* Инфо-панель выбранной точки трека (своя, не balloon карты) */}
{selectedPoint && (
<div className="absolute top-2 left-2 z-[1002] bg-background/95 border border-border rounded-md shadow-md p-2.5 text-xs space-y-1 max-w-[240px]">
<div className="flex items-center justify-between gap-2">
<span className="font-medium">{pointTime(selectedPoint)}</span>
<button
type="button"
className="text-muted-foreground hover:text-foreground px-1"
onClick={() => setSelectedPoint(null)}
aria-label="Закрыть"
>
✕
</button>
</div>
<div>Скорость: <b>{selectedPoint.speed != null ? `${Math.round(selectedPoint.speed)} км/ч` : '—'}</b></div>
{selectedPoint.course != null && <div>Направление: {Math.round(selectedPoint.course)}°</div>}
<div className="text-muted-foreground">{selectedPoint.lat.toFixed(6)}, {selectedPoint.lng.toFixed(6)}</div>
<div className="text-muted-foreground">Плейхед установлен на эту точку</div>
</div>
)}
</div>
{/* Легенда раскраски трека по скорости */}
{colorizeEnabled && (