fix(map): prevent ghost polylines and improve ETA accuracy.

- Added cancel tokens to avoid 'traces' on map after route removal.
- Fixed math bug in ETA proportion calculating 16.6% less time than real.
- Set average bus speed to 30km/h for more realistic calculations.
This commit is contained in:
2026-03-10 17:10:01 -05:00
parent 7536dbe2e3
commit 1b0f309f6a
4 changed files with 14 additions and 6 deletions

View File

@ -15,7 +15,7 @@ export function useETA() {
const cargando = ref<boolean>(false); const cargando = ref<boolean>(false);
// Configuración para el cálculo del ETA mejorado // Configuración para el cálculo del ETA mejorado
const VELOCIDAD_PROMEDIO_KMH = 35; // km/h (promedio ciudad/carretera) const VELOCIDAD_PROMEDIO_KMH = 30; // km/h (promedio ciudad/carretera)
const TIEMPO_PARADA_SEGUNDOS = 45; // segundos detenido por parada const TIEMPO_PARADA_SEGUNDOS = 45; // segundos detenido por parada
// Fórmula Haversine para distancia en línea recta (km) // Fórmula Haversine para distancia en línea recta (km)
@ -111,7 +111,8 @@ export function useETA() {
// Si la ruta tiene una duración estimada en BD, la usamos como base para el trayecto total // Si la ruta tiene una duración estimada en BD, la usamos como base para el trayecto total
// y calculamos la proporción según la parada. // y calculamos la proporción según la parada.
if (routeData.estimated_duration_minutes && routeData.distance_km) { if (routeData.estimated_duration_minutes && routeData.distance_km) {
const proporcionDistancia = distanciaAcumuladaKm / (routeData.distance_km * 1.2); // Bug fix: No multiplicar el denominador por 1.2 si distance_km ya es la distancia real
const proporcionDistancia = Math.min(distanciaAcumuladaKm / routeData.distance_km, 1.0);
minutosHastaParada = routeData.estimated_duration_minutes * proporcionDistancia; minutosHastaParada = routeData.estimated_duration_minutes * proporcionDistancia;
} else { } else {
const tiempoViajeMinutos = (distanciaAcumuladaKm / velocidad) * 60; const tiempoViajeMinutos = (distanciaAcumuladaKm / velocidad) * 60;

View File

@ -116,7 +116,7 @@ export const useFlujoPrincipal = () => {
return; return;
} }
await encontrarParadaCercana(ubicacion, paradas, map) await encontrarParadaCercana(ubicacion, paradas, map, cancelToken)
const paradaCercanaFound = paradaCercana.value const paradaCercanaFound = paradaCercana.value
if (cancelToken?.cancelled || routeStore.selectedRouteId !== _ruta.id) { if (cancelToken?.cancelled || routeStore.selectedRouteId !== _ruta.id) {

View File

@ -35,7 +35,8 @@ export function useParadaCercana() {
const encontrarParadaCercana = async ( const encontrarParadaCercana = async (
ubicacionUsuario: { lat: number; lng: number }, ubicacionUsuario: { lat: number; lng: number },
paradas: BusStop[], paradas: BusStop[],
map: google.maps.Map | undefined map: google.maps.Map | undefined,
cancelToken?: { cancelled: boolean }
) => { ) => {
if (!paradas || paradas.length === 0 || !ubicacionUsuario) return; if (!paradas || paradas.length === 0 || !ubicacionUsuario) return;
limpiarCaminata(); limpiarCaminata();
@ -105,6 +106,12 @@ export function useParadaCercana() {
console.error('Error cargando Directions API en useParadaCercana', e); console.error('Error cargando Directions API en useParadaCercana', e);
} }
// GUARD: Si se canceló durante las peticiones HTTP, abortar antes de dibujar y asignar
if (cancelToken?.cancelled) {
console.log('SIB | Operación encontrarParadaCercana cancelada');
return;
}
// 3. Fallback a la más cercana lineal si falla API // 3. Fallback a la más cercana lineal si falla API
if (!mejorParada) { if (!mejorParada) {
mejorParada = top5[0] || null; mejorParada = top5[0] || null;
@ -117,7 +124,7 @@ export function useParadaCercana() {
duracionCaminata.value = mejorDuracion; // en segundos duracionCaminata.value = mejorDuracion; // en segundos
// 4. Dibujar polilínea de caminata punteada azul // 4. Dibujar polilínea de caminata punteada azul
if (map && mejorRutaPuntos.length > 0) { if (map && mejorRutaPuntos.length > 0 && !cancelToken?.cancelled) {
caminandoPolyline.value = new google.maps.Polyline({ caminandoPolyline.value = new google.maps.Polyline({
path: mejorRutaPuntos, path: mejorRutaPuntos,
strokeColor: '#F59E0B', strokeColor: '#F59E0B',

View File

@ -472,7 +472,7 @@ async function highlightOptimalStopForRoute() {
if (!userCoords.value || routeStore.selectedRouteStops.length === 0) return; if (!userCoords.value || routeStore.selectedRouteStops.length === 0) return;
try { try {
await encontrarParadaCercana(userCoords.value, routeStore.selectedRouteStops as BusStop[], map.value || undefined); await encontrarParadaCercana(userCoords.value, routeStore.selectedRouteStops as BusStop[], map.value || undefined, currentCancelToken);
} catch (e) { } catch (e) {
console.error('Error calculating optimal stop:', e); console.error('Error calculating optimal stop:', e);
} }