feat: simplify map by removing all stop markers and manual clear button
This commit is contained in:
@ -13,7 +13,6 @@ import { getImageUrl } from "@/utils/imageUrl";
|
||||
import { useDirectionsRoute } from "@/composables/useDirectionsRoute";
|
||||
import { useParadaCercana } from "@/composables/useParadaCercana";
|
||||
import { useETA } from "@/composables/useETA";
|
||||
const BusStopInfoModal = defineAsyncComponent(() => import("@/components/BusStopInfoModal.vue"));
|
||||
const ETACard = defineAsyncComponent(() => import("@/components/ETACard.vue"));
|
||||
import type { BusStop } from '@/types'
|
||||
import { useFlujoPrincipal } from "@/composables/useFlujoPrincipal";
|
||||
@ -27,7 +26,7 @@ const mapStore = useMapStore();
|
||||
const busStopStore = useBusStopStore();
|
||||
const couponStore = useCouponStore();
|
||||
|
||||
const { map, isLoaded, error: mapsError, initMap, addCleanMarker, addHtmlMarker, setCenter, setZoom, addMarker } = useGoogleMaps();
|
||||
const { map, isLoaded, error: mapsError, initMap, addHtmlMarker, setCenter, setZoom, addMarker } = useGoogleMaps();
|
||||
const { estasCargando: estasCargandoRuta, errorRuta } = useDirectionsRoute();
|
||||
const { encontrarParadaCercana, paradaCercana, distanciaMetros, duracionCaminata } = useParadaCercana();
|
||||
const { calcularETA, busesActivos, cargando: etaCargando } = useETA();
|
||||
@ -41,18 +40,18 @@ const showETACard = ref(false);
|
||||
const markers = ref<any[]>([]);
|
||||
const promoMarkers = ref<any[]>([]);
|
||||
const userMarker = ref<any>(null);
|
||||
const polyline = ref<google.maps.Polyline | null>(null);
|
||||
const walkingPolyline = ref<google.maps.Polyline | null>(null);
|
||||
const walkingPolylineBorder = ref<google.maps.Polyline | null>(null); // Borde blanco estilo Google Maps
|
||||
const optimalStopPulse = ref<any>(null); // Radar para la parada óptima
|
||||
const showRouteDropdown = ref(false);
|
||||
const routeCardRef = ref<HTMLElement | null>(null);
|
||||
const currentMarkerMode = ref<'dot' | 'pin' | null>(null);
|
||||
const isUpdatingMarkers = ref(false);
|
||||
const unitMarkers = ref<Map<string, google.maps.Marker>>(new Map());
|
||||
const unitFetchInterval = ref<any>(null);
|
||||
const userCoords = ref<{ lat: number; lng: number } | null>(null); // Store last user location for internal navigation
|
||||
const currentMarkerMode = ref<'dot' | 'pin' | null>(null);
|
||||
const mappingSequenceId = ref(0); // Atomic ID to prevent race conditions
|
||||
const userCoords = ref<{ lat: number; lng: number } | null>(null);
|
||||
const polyline = ref<google.maps.Polyline | null>(null);
|
||||
const walkingPolyline = ref<google.maps.Polyline | null>(null);
|
||||
const walkingPolylineBorder = ref<google.maps.Polyline | null>(null);
|
||||
const optimalStopPulse = ref<any>(null);
|
||||
const showRouteDropdown = ref(false);
|
||||
const routeCardRef = ref<HTMLElement | null>(null);
|
||||
const mappingSequenceId = ref(0);
|
||||
|
||||
const alturaNavbar = ref(64);
|
||||
// Search state
|
||||
@ -90,59 +89,16 @@ function closeUberSearch() {
|
||||
destinationQuery.value = "";
|
||||
}
|
||||
|
||||
async function clearAllMapData() {
|
||||
console.log('🤖 JARVIS: Iniciando PURGA nuclear centralizada...');
|
||||
|
||||
// 1. UI inmediata
|
||||
showUberSearch.value = false;
|
||||
showRoutesToggle.value = false;
|
||||
destinationQuery.value = "";
|
||||
stopSearchQuery.value = "";
|
||||
showETACard.value = false;
|
||||
paradaCercana.value = null; // Borrar banner superior
|
||||
// clearAllMapData removed per request
|
||||
|
||||
// 2. Invalidar hilos en curso
|
||||
mappingSequenceId.value++;
|
||||
|
||||
try {
|
||||
// 3. Resetear stores
|
||||
routeStore.clearSelection();
|
||||
lastProcessedRouteId.value = null;
|
||||
// Modal state removed per request (no more stop markers to click)
|
||||
|
||||
// 4. LIMPIEZA CENTRALIZADA (useMapState)
|
||||
// Esto limpia markers, renderers, polylines, overlays HTML, etc.
|
||||
limpiarTodoCentralizado();
|
||||
|
||||
// 5. Limpiar referencias locales del componente (aunque no tengan mapa asignado ya)
|
||||
markers.value = [];
|
||||
promoMarkers.value = [];
|
||||
unitMarkers.value.clear();
|
||||
polyline.value = null;
|
||||
walkingPolyline.value = null;
|
||||
walkingPolylineBorder.value = null;
|
||||
optimalStopPulse.value = null;
|
||||
|
||||
// 6. Restaurar SOLO el marcador del usuario si tenemos ubicación
|
||||
await nextTick();
|
||||
if (userCoords.value) {
|
||||
const { lat, lng } = userCoords.value;
|
||||
userMarker.value = addHtmlMarker(
|
||||
{ lat, lng },
|
||||
sonarHtml,
|
||||
{ x: -30, y: -30 }
|
||||
);
|
||||
function reloadPage() {
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
console.log('🤖 JARVIS: Purga completada ✓');
|
||||
} catch (err) {
|
||||
console.error('❌ JARVIS: Error en purga:', err);
|
||||
}
|
||||
}
|
||||
|
||||
// Modal state
|
||||
const showBusStopModal = ref(false);
|
||||
const selectedBusStop = ref<BusStop | null>(null);
|
||||
|
||||
const showPromoModal = ref(false);
|
||||
const selectedPromo = ref<any>(null);
|
||||
const isBannerClosing = ref(false);
|
||||
@ -154,27 +110,6 @@ function animateAndReload() {
|
||||
}, 450); // Mismo tiempo que la transición
|
||||
}
|
||||
|
||||
// Close dropdown when clicking outside
|
||||
function handleClickOutside(event: MouseEvent) {
|
||||
if (routeCardRef.value && !routeCardRef.value.contains(event.target as Node)) {
|
||||
showRouteDropdown.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function handleBusStopClick(stop: BusStop) {
|
||||
selectedBusStop.value = stop;
|
||||
showBusStopModal.value = true;
|
||||
}
|
||||
|
||||
function closeBusStopModal() {
|
||||
showBusStopModal.value = false;
|
||||
selectedBusStop.value = null;
|
||||
}
|
||||
|
||||
function reloadPage() {
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
function handlePromoClick(promo: any) {
|
||||
selectedPromo.value = promo;
|
||||
showPromoModal.value = true;
|
||||
@ -207,8 +142,6 @@ onMounted(async () => {
|
||||
}
|
||||
|
||||
analyticsService.logEvent({ event_name: 'screen_view', properties: { screen_name: 'Map' } })
|
||||
// Add click outside listener
|
||||
document.addEventListener('click', handleClickOutside);
|
||||
|
||||
// Load routes, bus stops and promos in parallel
|
||||
await Promise.all([
|
||||
@ -226,19 +159,6 @@ onMounted(async () => {
|
||||
}
|
||||
}
|
||||
|
||||
// Handle stopId if present
|
||||
const queryStopId = router.currentRoute.value.query.stopId as string;
|
||||
if (queryStopId) {
|
||||
await busStopStore.loadBusStops();
|
||||
const foundStop = busStopStore.busStops.find(s => s.id === queryStopId);
|
||||
if (foundStop) {
|
||||
selectedBusStop.value = foundStop;
|
||||
showBusStopModal.value = true;
|
||||
setCenter(foundStop.latitude, foundStop.longitude);
|
||||
setZoom(17);
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for Google Maps to load
|
||||
if (isLoaded.value) {
|
||||
await initializeMap();
|
||||
@ -294,7 +214,6 @@ function prevPromo() {
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
document.removeEventListener('click', handleClickOutside);
|
||||
if (unitFetchInterval.value) clearInterval(unitFetchInterval.value);
|
||||
if (carouselTimer.value) clearInterval(carouselTimer.value);
|
||||
// Clear all markers when component unmounts
|
||||
@ -426,18 +345,7 @@ async function updateMapMarkers() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Agregar todos los stops como marcadores 'normales' para que se vean en el mapa
|
||||
stops.forEach(stop => {
|
||||
// Evitar sobre dibujar si es la cercana (useFlujoPrincipal ya se encargó)
|
||||
if (paradaCercana.value && stop.id === paradaCercana.value.id) return;
|
||||
|
||||
addCleanMarker(
|
||||
{ lat: stop.latitude, lng: stop.longitude },
|
||||
stop.name,
|
||||
'normal',
|
||||
() => handleBusStopClick(stop)
|
||||
);
|
||||
});
|
||||
// All stop markers loop removed per request to avoid marking stops on map
|
||||
} finally {
|
||||
isUpdatingMarkers.value = false;
|
||||
}
|
||||
@ -625,128 +533,9 @@ async function highlightOptimalStopForRoute() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dibuja la ruta caminando en el mapa interno sin abrir apps externas
|
||||
*/
|
||||
function drawInternalWalkingRoute(targetStop: BusStop, originOverride?: { lat: number, lng: number }) {
|
||||
const origin = originOverride || userCoords.value;
|
||||
|
||||
if (!origin) {
|
||||
// Si no tenemos ubicación, la pedimos
|
||||
navigator.geolocation.getCurrentPosition((pos) => {
|
||||
userCoords.value = { lat: pos.coords.latitude, lng: pos.coords.longitude };
|
||||
calculateWalkingPath(userCoords.value, targetStop);
|
||||
}, (_err) => {
|
||||
alert("Necesitamos tu ubicación para trazar la ruta a pie.");
|
||||
});
|
||||
} else {
|
||||
calculateWalkingPath(origin, targetStop);
|
||||
}
|
||||
}
|
||||
|
||||
async function calculateWalkingPath(origin: { lat: number, lng: number }, targetStop: BusStop) {
|
||||
// 1. Limpiar pulso anterior si existe
|
||||
if (optimalStopPulse.value) {
|
||||
if (typeof optimalStopPulse.value.setMap === 'function') {
|
||||
optimalStopPulse.value.setMap(null);
|
||||
}
|
||||
optimalStopPulse.value = null;
|
||||
}
|
||||
|
||||
// 2. Añadir el PULSO NARANJA de "Parada Óptima"
|
||||
optimalStopPulse.value = addHtmlMarker(
|
||||
{ lat: targetStop.latitude, lng: targetStop.longitude },
|
||||
optimalSonarHtml,
|
||||
{ x: -30, y: -30 }
|
||||
);
|
||||
|
||||
// 3. Resaltar la parada en verde (marcador estándar)
|
||||
const targetStops = routeStore.selectedRouteId ? routeStore.selectedRouteStops : busStopStore.busStops;
|
||||
const stopIndex = targetStops.findIndex(s => s.id === targetStop.id);
|
||||
|
||||
if (stopIndex !== -1 && markers.value[stopIndex]) {
|
||||
const marker = markers.value[stopIndex];
|
||||
marker.setIcon({
|
||||
path: currentMarkerMode.value === 'pin'
|
||||
? "M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7z"
|
||||
: google.maps.SymbolPath.CIRCLE,
|
||||
fillColor: '#4CAF50',
|
||||
fillOpacity: 1,
|
||||
strokeColor: '#FFFFFF',
|
||||
strokeWeight: 2,
|
||||
scale: currentMarkerMode.value === 'pin' ? 2.5 : 9,
|
||||
anchor: currentMarkerMode.value === 'pin' ? new google.maps.Point(12, 22) : null
|
||||
});
|
||||
}
|
||||
|
||||
// 2. Trazar línea de puntos verde siguiendo RED VIAL PRINCIPAL
|
||||
try {
|
||||
const { RoutesService } = await google.maps.importLibrary("routes") as any;
|
||||
const routeService = new RoutesService();
|
||||
const response = await routeService.computeRoutes({
|
||||
origin: {
|
||||
location: {
|
||||
latLng: { lat: origin.lat, lng: origin.lng }
|
||||
}
|
||||
},
|
||||
destination: {
|
||||
location: {
|
||||
latLng: { lat: targetStop.latitude, lng: targetStop.longitude }
|
||||
}
|
||||
},
|
||||
travelMode: 'DRIVE',
|
||||
routingPreference: 'TRAFFIC_UNAWARE',
|
||||
polylineQuality: 'HIGH_QUALITY',
|
||||
polylineEncoding: 'ENCODED_POLYLINE',
|
||||
});
|
||||
|
||||
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);
|
||||
|
||||
if (walkingPolyline.value) walkingPolyline.value.setMap(null);
|
||||
if (walkingPolylineBorder.value) walkingPolylineBorder.value.setMap(null);
|
||||
|
||||
const { registrarPolyline: regPoly } = useMapState();
|
||||
|
||||
// CAPA 1: Borde blanco (Para dar contraste estilo Google Maps)
|
||||
walkingPolylineBorder.value = new google.maps.Polyline({
|
||||
path: path,
|
||||
geodesic: true,
|
||||
strokeColor: '#FFFFFF',
|
||||
strokeOpacity: 0.9,
|
||||
strokeWeight: 10,
|
||||
map: map.value,
|
||||
zIndex: 5
|
||||
});
|
||||
regPoly(walkingPolylineBorder.value);
|
||||
|
||||
// CAPA 2: Línea Indigo Central (La ruta principal)
|
||||
walkingPolyline.value = new google.maps.Polyline({
|
||||
path: path,
|
||||
geodesic: true,
|
||||
strokeColor: '#4285F4', // Azul Google Maps
|
||||
strokeOpacity: 1.0,
|
||||
strokeWeight: 5,
|
||||
map: map.value,
|
||||
zIndex: 10
|
||||
});
|
||||
regPoly(walkingPolyline.value);
|
||||
|
||||
// Ajustar zoom para mostrar toda la ruta de caminata
|
||||
if (map.value) {
|
||||
const bounds = new google.maps.LatLngBounds();
|
||||
path.forEach(p => bounds.extend(p));
|
||||
map.value.fitBounds(bounds, { top: 100, bottom: 200, left: 50, right: 50 });
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('SIBU | Error trazando ruta a pie con Routes API:', error);
|
||||
}
|
||||
}
|
||||
// walking route functions removed
|
||||
|
||||
</script>
|
||||
|
||||
@ -886,14 +675,7 @@ async function calculateWalkingPath(origin: { lat: number, lng: number }, target
|
||||
|
||||
<!-- Inputs and Toggle removed per request -->
|
||||
<div class="search-actions-header">
|
||||
<button
|
||||
v-if="routeStore.selectedRouteId || markers.length > 0"
|
||||
class="clear-map-btn"
|
||||
@click="clearAllMapData"
|
||||
>
|
||||
<span class="material-icons text-sm">layers_clear</span>
|
||||
Limpiar Mapa
|
||||
</button>
|
||||
<!-- Limpiar Mapa button removed per request -->
|
||||
</div>
|
||||
|
||||
<!-- Results -->
|
||||
@ -1004,13 +786,7 @@ async function calculateWalkingPath(origin: { lat: number, lng: number }, target
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal for details -->
|
||||
<BusStopInfoModal
|
||||
:is-open="showBusStopModal"
|
||||
:bus-stop="selectedBusStop"
|
||||
@close="closeBusStopModal"
|
||||
@navigate="drawInternalWalkingRoute"
|
||||
/>
|
||||
<!-- Modal for details removed as per request to eliminate extra markings -->
|
||||
|
||||
|
||||
<Transition name="modal-fade">
|
||||
|
||||
@ -4,10 +4,9 @@ import { useScheduleStore } from '@/stores/schedule'
|
||||
import { useRouteStore } from '@/stores/route'
|
||||
import { formatTo12Hour } from '@/utils/timeFormatter'
|
||||
import { analyticsService } from '@/services/analyticsService'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const scheduleStore = useScheduleStore()
|
||||
const routeStore = useRouteStore()
|
||||
|
||||
@ -126,11 +125,8 @@ function pickRoute(id: string, name: string) {
|
||||
scheduleStore.loadRouteSchedules(id)
|
||||
}
|
||||
|
||||
function goToMap() {
|
||||
if (routeStore.selectedRouteId) {
|
||||
router.push({ path: '/map', query: { routeId: routeStore.selectedRouteId } })
|
||||
}
|
||||
}
|
||||
// goToMap removed per request
|
||||
|
||||
|
||||
// ── Cierre del dropdown al hacer clic fuera
|
||||
function handleOutsideClick(e: MouseEvent) {
|
||||
@ -256,11 +252,6 @@ onUnmounted(() => {
|
||||
<span class="live-dot"></span>
|
||||
<span>Próximas salidas</span>
|
||||
</div>
|
||||
<!-- Botón ver en mapa -->
|
||||
<button class="map-btn" @click="goToMap">
|
||||
<span class="material-icons">map</span>
|
||||
Ver en mapa
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Chips de filtro día -->
|
||||
|
||||
Reference in New Issue
Block a user