135 lines
4.9 KiB
TypeScript
135 lines
4.9 KiB
TypeScript
import { ref } from 'vue';
|
|
|
|
import { useMapState } from './useMapState';
|
|
|
|
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();
|
|
|
|
// Limpia los tramos anteriores dibujados en el mapa
|
|
const limpiarRuta = () => {
|
|
if (polylines.value.length > 0) {
|
|
polylines.value.forEach((polyline) => {
|
|
polyline.setMap(null);
|
|
});
|
|
polylines.value = [];
|
|
}
|
|
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) => {
|
|
if (!paradas || paradas.length < 2) {
|
|
errorRuta.value = 'Se requieren al menos 2 paradas para trazar una ruta.';
|
|
return;
|
|
}
|
|
|
|
// NOTA: No llamamos a limpiarRuta() aquí para poder encadenar llamadas (dibujar fondo + trazado activo)
|
|
estasCargando.value = true;
|
|
errorRuta.value = null;
|
|
|
|
try {
|
|
// Importar librerías necesarias de la nueva API
|
|
const { RoutesService } = await google.maps.importLibrary("routes") as any;
|
|
const routeService = new RoutesService();
|
|
|
|
// Límite de la API de Google Maps Routes: Origen, Destino, y hasta 25 intermediates
|
|
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
|
|
}
|
|
}
|
|
};
|
|
|
|
const destination = {
|
|
location: {
|
|
latLng: {
|
|
latitude: chunk[chunk.length - 1]!.latitud,
|
|
longitude: chunk[chunk.length - 1]!.longitud
|
|
}
|
|
}
|
|
};
|
|
|
|
const intermediates = chunk.slice(1, -1).map(p => ({
|
|
location: {
|
|
latLng: {
|
|
latitude: p.latitud,
|
|
longitude: p.longitud
|
|
}
|
|
}
|
|
}));
|
|
|
|
try {
|
|
const response = await routeService.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,
|
|
});
|
|
|
|
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 ? '#9CA3AF' : '#FBBF24', // Gris para lo lejano, Amarillo para lo cercano
|
|
strokeWeight: isPast ? 4 : 6,
|
|
strokeOpacity: isPast ? 0.6 : 1.0,
|
|
icons: isPast ? [{
|
|
icon: { path: 'M 0,-1 0,1', strokeOpacity: 1, scale: 2 },
|
|
offset: '0',
|
|
repeat: '10px'
|
|
}] : []
|
|
});
|
|
|
|
registrarPolyline(polyline);
|
|
}
|
|
}
|
|
} catch (err: any) {
|
|
console.warn(`SIBU | Tramo ${i} falló con Routes API: `, err);
|
|
}
|
|
|
|
await delay(200);
|
|
}
|
|
} 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
|
|
};
|
|
}
|