Files
SIB/frontend/src/composables/useDirectionsRoute.ts

134 lines
4.7 KiB
TypeScript
Raw Normal View History

2026-02-26 12:39:15 -05:00
import { ref } from 'vue';
import { useMapState } from './useMapState';
2026-02-26 12:39:15 -05:00
export interface Parada {
id: number;
nombre: string;
latitud: number;
longitud: number;
orden: number;
}
export function useDirectionsRoute() {
const estasCargando = ref<boolean>(false);
const errorRuta = ref<string | null>(null);
const { registrarPolyline, polylines } = useMapState();
2026-02-26 12:39:15 -05:00
// Limpia los tramos anteriores dibujados en el mapa
const limpiarRuta = () => {
if (polylines.value.length > 0) {
polylines.value.forEach((polyline) => {
polyline.setMap(null);
2026-02-26 12:39:15 -05:00
});
polylines.value = [];
2026-02-26 12:39:15 -05:00
}
errorRuta.value = null;
};
// Función utilitaria para pausar ejecución
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
const trazarRuta = async (paradas: Parada[], map: google.maps.Map, isPast: boolean = false) => {
2026-02-26 12:39:15 -05:00
if (!paradas || paradas.length < 2) {
errorRuta.value = 'Se requieren al menos 2 paradas para trazar una ruta.';
return;
}
limpiarRuta();
estasCargando.value = true;
errorRuta.value = null;
try {
// Importar librerías necesarias de la nueva API
const { Route } = await google.maps.importLibrary("routes") as any;
// Límite de la API de Google Maps Routes: Origen, Destino, y hasta 25 intermediates
2026-02-26 12:39:15 -05:00
const maxPuntosPorChunk = 25;
const overlaps = 1;
for (let i = 0; i < paradas.length - 1; i += (maxPuntosPorChunk - overlaps)) {
const chunk = paradas.slice(i, i + maxPuntosPorChunk);
if (chunk.length < 2) break;
const origin = {
location: {
latLng: {
latitude: chunk[0]!.latitud,
longitude: chunk[0]!.longitud
}
}
};
2026-02-26 12:39:15 -05:00
const destination = {
location: {
latLng: {
latitude: chunk[chunk.length - 1]!.latitud,
longitude: chunk[chunk.length - 1]!.longitud
}
}
2026-02-26 12:39:15 -05:00
};
const intermediates = chunk.slice(1, -1).map(p => ({
location: {
latLng: {
latitude: p.latitud,
longitude: p.longitud
2026-02-26 12:39:15 -05:00
}
}
}));
2026-02-26 12:39:15 -05:00
try {
const response = await Route.computeRoutes({
origin,
destination,
intermediates,
travelMode: 'DRIVE' as any, // 'DRIVE' es el nuevo estandar en computeRoutes
routingPreference: 'TRAFFIC_UNAWARE' as any,
polylineQuality: 'HIGH_QUALITY' as any,
polylineEncoding: 'ENCODED_POLYLINE' as any,
});
2026-02-26 12:39:15 -05:00
if (response.routes && response.routes.length > 0) {
const route = response.routes[0];
if (route.polyline && route.polyline.encodedPolyline) {
const path = google.maps.geometry.encoding.decodePath(route.polyline.encodedPolyline);
const polyline = new google.maps.Polyline({
path: path,
map: map,
strokeColor: isPast ? '#FDE68A' : '#FBBF24',
strokeWeight: isPast ? 3 : 5,
strokeOpacity: isPast ? 0.4 : 0.95,
icons: isPast ? [{
icon: { path: 'M 0,-1 0,1', strokeOpacity: 1, scale: 2 },
offset: '0',
repeat: '10px'
}] : []
});
registrarPolyline(polyline);
}
}
2026-02-26 12:39:15 -05:00
} catch (err: any) {
console.warn(`SIBU | Tramo ${i} falló con Routes API: `, err);
2026-02-26 12:39:15 -05:00
}
await delay(200);
2026-02-26 12:39:15 -05:00
}
} catch (err: any) {
errorRuta.value = `Error crítico al trazar la ruta: ${err.message || String(err)}`;
console.error(errorRuta.value);
} finally {
estasCargando.value = false;
}
};
return {
trazarRuta,
limpiarRuta,
estasCargando,
errorRuta
};
}