fix: OSRM sparse data handling, frontend type mismatch, map jumping
- Rewrite OsrmService with smart dense/sparse segmentation: dense GPS traces use Match API, sparse gaps use Route API (turn-by-turn directions between waypoints) - Filter stationary points before OSRM processing - Fix critical frontend bug: LocationHistoryResponse type didn't match backend response shape (matchedRoute vs matched), so OSRM routes were never actually displaying - Fix double distance conversion (backend sends miles, frontend was dividing by 1609.34 again) - Fix map jumping: disable popup autoPan on marker data refresh - Extend default history window from 4h to 12h Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -157,21 +157,21 @@ export function GpsTracking() {
|
||||
|
||||
const history = locationHistory as LocationHistoryResponse;
|
||||
|
||||
// If we have matched coordinates, use those
|
||||
if (history.matched && history.coordinates && history.coordinates.length > 1) {
|
||||
// If we have OSRM matched route, use road-snapped coordinates
|
||||
if (history.matchedRoute && history.matchedRoute.coordinates && history.matchedRoute.coordinates.length > 1) {
|
||||
return {
|
||||
positions: history.coordinates,
|
||||
positions: history.matchedRoute.coordinates,
|
||||
isMatched: true,
|
||||
distance: history.distance,
|
||||
duration: history.duration,
|
||||
confidence: history.confidence,
|
||||
distance: history.matchedRoute.distance, // already in miles from backend
|
||||
duration: history.matchedRoute.duration,
|
||||
confidence: history.matchedRoute.confidence,
|
||||
};
|
||||
}
|
||||
|
||||
// Fall back to raw positions
|
||||
if (history.rawPositions && history.rawPositions.length > 1) {
|
||||
// Fall back to raw GPS points
|
||||
if (history.rawPoints && history.rawPoints.length > 1) {
|
||||
return {
|
||||
positions: history.rawPositions.map(loc => [loc.latitude, loc.longitude] as [number, number]),
|
||||
positions: history.rawPoints.map(loc => [loc.latitude, loc.longitude] as [number, number]),
|
||||
isMatched: false,
|
||||
distance: undefined,
|
||||
duration: undefined,
|
||||
@@ -433,7 +433,7 @@ export function GpsTracking() {
|
||||
position={[driver.location!.latitude, driver.location!.longitude]}
|
||||
icon={createDriverIcon(true)}
|
||||
>
|
||||
<Popup>
|
||||
<Popup autoPan={false}>
|
||||
<div className="min-w-[180px]">
|
||||
<h3 className="font-semibold text-base">{driver.driverName}</h3>
|
||||
{driver.driverPhone && (
|
||||
@@ -489,10 +489,10 @@ export function GpsTracking() {
|
||||
<div className="w-12 h-0.5 bg-gray-400 opacity-40" style={{ borderTop: '2px dashed #94a3b8' }}></div>
|
||||
<span className="text-xs text-muted-foreground">GPS Trail</span>
|
||||
</div>
|
||||
{routePolyline && routePolyline.distance && (
|
||||
{routePolyline && routePolyline.distance != null && (
|
||||
<div className="pt-1 border-t border-border">
|
||||
<div className="text-xs text-muted-foreground">
|
||||
Distance: <span className="font-medium text-foreground">{(routePolyline.distance / 1609.34).toFixed(1)} mi</span>
|
||||
Distance: <span className="font-medium text-foreground">{routePolyline.distance.toFixed(1)} mi</span>
|
||||
</div>
|
||||
{routePolyline.confidence !== undefined && (
|
||||
<div className="text-xs text-muted-foreground">
|
||||
|
||||
@@ -108,10 +108,20 @@ export interface MyGpsStatus {
|
||||
}
|
||||
|
||||
export interface LocationHistoryResponse {
|
||||
matched: boolean;
|
||||
coordinates?: [number, number][]; // road-snapped [lat, lng] pairs
|
||||
distance?: number; // road distance in meters
|
||||
duration?: number; // duration in seconds
|
||||
confidence?: number; // 0-1 confidence score
|
||||
rawPositions?: Array<{ latitude: number; longitude: number; speed: number; timestamp: Date }>;
|
||||
rawPoints: Array<{
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
altitude?: number | null;
|
||||
speed?: number | null;
|
||||
course?: number | null;
|
||||
accuracy?: number | null;
|
||||
battery?: number | null;
|
||||
timestamp: string;
|
||||
}>;
|
||||
matchedRoute: {
|
||||
coordinates: [number, number][]; // road-snapped [lat, lng] pairs
|
||||
distance: number; // road distance in miles
|
||||
duration: number; // duration in seconds
|
||||
confidence: number; // 0-1 confidence score
|
||||
} | null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user