Search code examples
typescriptgoogle-maps-api-3vuejs3

how to optimize .forEach loop typescript (long task)


How could I optimize this .forEach loop (inside filterMarkers() function) in this helper that paint a google map and it's markers, with markerClusterer that group all the markers according to the zoom of the map.

I think that grouping all the markers in differents arrays according to the label localizaciones[index].agrupacion inside the initMap() and assigning them somehow when the event that call the filterMarkers() fires, this way the program only run the loop one time not every time the event fires, but I don`t know how to approach this thought, I show you the helper, made in typescript:

import { ref } from "vue";
import axios from "@/plugins/axios";
import { MarkerClusterer } from "@googlemaps/markerclusterer";
import {
    ILocalizacion,
    ILocalizacionesF,
    IDetalleEstacion,
    ITags,
} from "@/Interfaces/mapas/IMapas";

export const map = ref<google.maps.Map>();
export const service = ref<google.maps.places.PlacesService>();
let geoLocation = ref<ILocalizacion>({ lat: 40.53926, lng: -3.69467 });
let infowindow = ref<google.maps.InfoWindow>();
let localizacionesCluster: google.maps.Marker[] = [];
let markerCluster: MarkerClusterer;
let icon: string = "";
let detalleEstacion: any;
const iconosServicios = {
    a24h: "icon-servicio_24h",
    adblue: "icon-adblue",
    cafe_rest: "icon-cafeteria",
    cajero: "icon-cajero",
    descargatacografo: "icon-descarga_tacografo",
    dieselb: "icon-gasoleo_b",
    ducha: "icon-Duchas",
    hotel: "icon-hotel",
    itv: "icon-itv",
    lavacamion: "icon-Lavaderos",
    parking: "icon-parking_camiones",
    tienda: "icon-tienda",
    recomendada: "icon-recomendado_globalstar",
    diesela: "icon-gasoleo_a",
};
export let tags: ITags[] = [
    { tag: "Ver todo", agrupacion: "0" },
    { tag: "Carburante", agrupacion: "487" },
    { tag: "Reserva", agrupacion: "494" },
    { tag: "Parking", agrupacion: "1093" },
    { tag: "Lavadero", agrupacion: "946" },
    { tag: "Tacógrafo", agrupacion: "755" },
    { tag: "Ferry", agrupacion: "944" },
];

export async function initMap(localizaciones: ILocalizacionesF[]) {
    navigator.geolocation.getCurrentPosition(
        function (position) {
            geoLocation.value.lat = position.coords.latitude;
            geoLocation.value.lng = position.coords.longitude;
        },
        function (error) {
            if (error.code == error.PERMISSION_DENIED) {
            }
            //alert("Permiso de geolocalización denegado, esto puede hacer que la app no funcione correctamente.");
        }
    );

    const { Map } = (await google.maps.importLibrary(
        "maps"
    )) as google.maps.MapsLibrary;

    const { PlacesService } = (await google.maps.importLibrary(
        "places"
    )) as google.maps.PlacesLibrary;

    map.value = new Map(document.getElementById("googleMap")! as any, {
        center: geoLocation.value,
        mapTypeControl: false,
        mapTypeId: google.maps.MapTypeId.ROADMAP,
        streetViewControl: false,
        zoom: 5,
        zoomControl: false,
    });

    service.value = new PlacesService(map.value);
    infowindow.value = new google.maps.InfoWindow();

    for (let index = 0; index < localizaciones.length; index++) {
        let marker = new google.maps.Marker({
            position: {
                lat: localizaciones[index].lat,
                lng: localizaciones[index].lng,
            },
            map: map.value,
            title: localizaciones[index].agrupacion,
            icon: setIcon(localizaciones[index].agrupacion),
        });
        localizacionesCluster.push(marker);

        google.maps.event.addListener(marker, "click", async function () {
            detalleEstacion = await pedirDetalleEstacion(
                localizaciones[index].prv_codigo
            );

            for (const [key, value] of Object.entries(detalleEstacion))
                if (
                    (detalleEstacion.hasOwnProperty(key) && value == null) ||
                    value == undefined
                )
                    detalleEstacion[key] = "";

            console.log("detalle estación: ", detalleEstacion);
            infowindow.value?.setContent(setPlantilla(detalleEstacion, marker));
            infowindow.value?.open(map.value, marker);
        });
    }
    cerrarEventos();
    markerCluster = new MarkerClusterer({
        map: map.value,
        markers: localizacionesCluster,
    });
}

function setIcon(agrupacion: string): string {
    icon = "/src/assets/map_icon-";
    switch (agrupacion) {
        case "487":
            return (icon += "1.png");
        case "494":
            return (icon += "2.png");
        case "944":
            return (icon += "3.png");
        case "946":
            return (icon += "4.png");
        case "755":
            return (icon += "5.png");
        case "1093":
            return (icon += "6.png");
        default:
            return "no hay icono";
    }
}

function setPlantilla(
    response: IDetalleEstacion,
    marker: google.maps.Marker
): string {
    let plantilla: string = `
    <div class="blog-slider">
    <h2 class="titulo">${response.titulo}</h2>
    <div class="infoBody">
    <div class="column precio"><div class="precio2">${
        response.precio
    }</div></div>
    <div class="column contenido">
    <table>
    <tr><td>Marca: ${response.marca}</td></tr>
    <tr><td>${response.horario}</td></tr>
    <tr><td>${response.sentido}</td></tr>
    <tr><td><img src="/src/assets/phone.png" /><a href="tel:${
        response.telefono
    }" class="link"> ${response.telefono}</a></td></tr>
    <tr><td>${response.poblacion}</td></tr>
    <tr><td>${response.provincia}</td></tr>
    </table>
    </div>
    </div>
    <div class="iconos"><a href="http://www.google.com/maps/dir/${
        geoLocation.value.lat
    },${geoLocation.value.lng}/${marker.getPosition()?.lat()},${marker
        .getPosition()
        ?.lng()}" target="_blank"><button class="button"><img src="/src/assets/directions.png" /></button></a></div>
    <div class="iconos">`;
    if (response.servicios?.length)
        for (const [key, value] of Object.entries(iconosServicios))
            response.servicios?.forEach((servicio) => {
                if (servicio === key)
                    plantilla += `<i class="icono ${value}" ></i>`;
            });

    plantilla += "</div></div>";
    return plantilla;
}

async function pedirDetalleEstacion(codProveedor: number) {
    console.log(codProveedor);
    const { data } = await axios.get<IDetalleEstacion>(
        `${import.meta.env.VITE_APP_BACKEND_NESTJS}${
            import.meta.env.VITE_APP_GENERAL
        }/detalleEstacionServicio?codProveedor=${codProveedor}`
    );
    return data;
}

export function filterMarkers(agrupacion: string) {
    markerCluster.clearMarkers();
    if (agrupacion == "0") {
        showAllMarkers();
        return;
    }
    localizacionesCluster.forEach((localizacion: google.maps.Marker) => {
        if (localizacion.getTitle() === agrupacion) {
            localizacion.setVisible(true);
            markerCluster.addMarker(localizacion);
            return true;
        } else {
            localizacion.setVisible(false);
            return true;
        }
    });
}

function showAllMarkers() {
    localizacionesCluster.forEach((localizacion: google.maps.Marker) => {
        localizacion.setVisible(true);
    });
    markerCluster.addMarkers(localizacionesCluster);
}

function cerrarEventos() {
    map.value?.addListener("click", function () {
        if (infowindow) infowindow.value?.close();
    });
}

I'm open to any other suggestion. here there is a inspection of the task executed: enter image description here


Solution

  • I solved it like this:

    export function filterMarkers(agrupacion: string) {
        markerCluster.clearMarkers();
        if (agrupacion == "0") {
            showAllMarkers();
            return;
        }
        let customLoc: google.maps.Marker[] = [];
    
        customLoc = localizacionesCluster.filter((lo) => {
            return lo.getTitle() === agrupacion;
        });
    
        markerCluster.addMarkers(customLoc);
    }
    
    function showAllMarkers() {
        markerCluster.addMarkers(localizacionesCluster);
    }