fix(map): total shielding against ghost lines.

- Updated useDirectionsRoute to support and respect cancelTokens in internal loops.
- Ensured all route tracing calls in useFlujoPrincipal are abortable.
- Prevented late polyline registration after map cleanup.
This commit is contained in:
2026-03-10 17:19:22 -05:00
parent 1b0f309f6a
commit 1c951dfced
2 changed files with 18 additions and 8 deletions

View File

@ -29,7 +29,12 @@ export function useDirectionsRoute() {
// Función utilitaria para pausar ejecución // Función utilitaria para pausar ejecución
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
const trazarRuta = async (paradas: Parada[], map: google.maps.Map, isPast: boolean = false) => { const trazarRuta = async (
paradas: Parada[],
map: google.maps.Map,
isPast: boolean = false,
cancelToken?: { cancelled: boolean }
) => {
if (!paradas || paradas.length < 2) { if (!paradas || paradas.length < 2) {
errorRuta.value = 'Se requieren al menos 2 paradas para trazar una ruta.'; errorRuta.value = 'Se requieren al menos 2 paradas para trazar una ruta.';
return; return;
@ -46,6 +51,9 @@ export function useDirectionsRoute() {
const maxWaypoints = 23; // Google Directions limit is typically 25 including origin/dest const maxWaypoints = 23; // Google Directions limit is typically 25 including origin/dest
for (let i = 0; i < paradas.length - 1; i += maxWaypoints) { for (let i = 0; i < paradas.length - 1; i += maxWaypoints) {
// GUARD: Abortar si la operación fue cancelada durante el delay
if (cancelToken?.cancelled) break;
const chunk = paradas.slice(i, i + maxWaypoints + 1); const chunk = paradas.slice(i, i + maxWaypoints + 1);
if (chunk.length < 2) break; if (chunk.length < 2) break;
@ -73,7 +81,7 @@ export function useDirectionsRoute() {
}); });
}); });
if (result.routes && result.routes.length > 0) { if (result.routes && result.routes.length > 0 && !cancelToken?.cancelled) {
const route = result.routes[0]; const route = result.routes[0];
if (route?.overview_path) { if (route?.overview_path) {
const polyline = new google.maps.Polyline({ const polyline = new google.maps.Polyline({
@ -95,13 +103,15 @@ export function useDirectionsRoute() {
console.warn(`SIBU | Tramo ${i} falló con Directions API: `, err); console.warn(`SIBU | Tramo ${i} falló con Directions API: `, err);
} }
if (i + maxWaypoints < paradas.length - 1) { if (i + maxWaypoints < paradas.length - 1 && !cancelToken?.cancelled) {
await delay(300); await delay(300);
} }
} }
} catch (err: any) { } catch (err: any) {
errorRuta.value = `Error crítico al trazar la ruta: ${err.message || String(err)}`; if (!cancelToken?.cancelled) {
console.error(errorRuta.value); errorRuta.value = `Error crítico al trazar la ruta: ${err.message || String(err)}`;
console.error(errorRuta.value);
}
} finally { } finally {
estasCargando.value = false; estasCargando.value = false;
} }

View File

@ -87,7 +87,7 @@ export const useFlujoPrincipal = () => {
// Si no detectamos GPS, trazamos la ruta completa sin zoom guiado // Si no detectamos GPS, trazamos la ruta completa sin zoom guiado
if (!ubicacion) { if (!ubicacion) {
await trazarRuta(paradasFormateadas, map, false); await trazarRuta(paradasFormateadas, map, false, cancelToken);
if (cancelToken?.cancelled) { limpiarMapa(); return; } if (cancelToken?.cancelled) { limpiarMapa(); return; }
const bounds = new google.maps.LatLngBounds() const bounds = new google.maps.LatLngBounds()
paradasFormateadas.forEach(p => bounds.extend(new google.maps.LatLng(p.latitud, p.longitud))) paradasFormateadas.forEach(p => bounds.extend(new google.maps.LatLng(p.latitud, p.longitud)))
@ -102,7 +102,7 @@ export const useFlujoPrincipal = () => {
} }
// Dibujar ruta completa (fondo) // Dibujar ruta completa (fondo)
await trazarRuta(paradasFormateadas, map, true); await trazarRuta(paradasFormateadas, map, true, cancelToken);
if (cancelToken?.cancelled || routeStore.selectedRouteId !== _ruta.id) { if (cancelToken?.cancelled || routeStore.selectedRouteId !== _ruta.id) {
limpiarMapa(); // limpiar polylines ya dibujadas limpiarMapa(); // limpiar polylines ya dibujadas
@ -135,7 +135,7 @@ export const useFlujoPrincipal = () => {
if (idx !== -1) { if (idx !== -1) {
const tramoRelevante = paradasFormateadas.slice(idx) const tramoRelevante = paradasFormateadas.slice(idx)
if (tramoRelevante.length > 1) { if (tramoRelevante.length > 1) {
await trazarRuta(tramoRelevante, map, false) await trazarRuta(tramoRelevante, map, false, cancelToken)
} }
} }