Mapbox wont display some Markers with Marker Clustering included

143 Views Asked by At

I have custom markers on my map for the categories "airport, shopClothes, fuel, supermarket, tattoo, and hospital." These worked flawlessly. Now I have added a marker cluster function that should cluster all these categories separately and still retain the custom marker. This works for the categories "shopClothes, supermarket, and tattoo." However, it doesn't work for "hospital, fuel, and airport." Since the marker cluster has been activated, a standard marker is suddenly displayed for "hospital, fuel, and airport" instead of the custom marker I set and i cant manage to fix this.

Screenshot:

Code for categories and Marker Cluster:

const categories = {
        "airport": {
            query: '[out:json];node["aeroway"="aerodrome"]',
            svg: "icons/airportr.png",
            width: '30px',
            height: '30px'
        },
        "shopClothes": {
            query: '[out:json];node["shop"="clothes"]',
            svg: "icons/clothes3r.png",
            width: '30px',
            height: '30px'
        },
        "fuel": {
            query: '[out:json];node["amenity"="fuel"]',
            svg: "icons/gas-stationr.png",
            width: '28px',
            height: '28px'
        },
        "supermarket": {
            query: '[out:json];node["shop"="supermarket"]',
            svg: "icons/storer.png",
            width: '30px',
            height: '30px'
        },
        "tattoo": {
            query: '[out:json];node["shop"="tattoo"]',
            svg: "icons/tattoo3r.png",
            width: '30px',
            height: '30px'
        },
        "hospital": {
            query: '[out:json];node["amenity"="hospital"]',
            svg: "icons/medicalr.png",
            width: '30px',
            height: '30px'
        }
    };


    function fetchCategoryData(category) {
        const bboxArray = map.getBounds().toArray();
        const bbox = [
            bboxArray[0][1],
            bboxArray[0][0],
            bboxArray[1][1],
            bboxArray[1][0]
        ].join(",");

        fetch(`https://overpass-api.de/api/interpreter?data=${categories[category].query}(${bbox});out;`)
            .then(response => response.json())
            .then(data => {
                const geoData = {
                    type: 'FeatureCollection',
                    features: data.elements.map(el => ({
                        type: 'Feature',
                        geometry: {
                            type: 'Point',
                            coordinates: [el.lon, el.lat]
                        }
                    }))
                };

                if (map.getSource(category)) {
                    map.getSource(category).setData(geoData);
                } else {
                    map.addSource(category, {
                        type: 'geojson',
                        data: geoData,
                        cluster: true,
                        clusterMaxZoom: 14,
                        clusterRadius: 50
                    });

                    map.addLayer({
                        id: `${category}-clusters`,
                        type: 'symbol',
                        source: category,
                        filter: ['has', 'point_count'],
                        layout: {
                            'icon-image': category,
                            'icon-size': 0.5
                        }
                    });

                    map.addLayer({
                        id: `${category}-unclustered-point`,
                        type: 'symbol',
                        source: category,
                        filter: ['!', ['has', 'point_count']],
                        layout: {
                            'icon-image': category,
                            'icon-size': 0.5
                        }
                    });
                }
            });

Full code:

<!DOCTYPE html>
<html lang="de">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Ihre Karte</title>
    <script src="https://api.mapbox.com/mapbox-gl-js/v2.15.0/mapbox-gl.js"></script>
    <link href="https://api.mapbox.com/mapbox-gl-js/v2.15.0/mapbox-gl.css" rel="stylesheet">
</head>
<body>

<div id="map" style="width: 100%; height: 500px;"></div>

<script>
    mapboxgl.accessToken = 'CENSORED';
    const map = new mapboxgl.Map({
        container: 'map',
        style: 'CENSORED',
        center: [9.9937, 53.5511],
        zoom: 12
    });
    
    const categories = {
        "airport": {
            query: '[out:json];node["aeroway"="aerodrome"]',
            svg: "icons/airportr.png",
            width: '30px',
            height: '30px'
        },
        "shopClothes": {
            query: '[out:json];node["shop"="clothes"]',
            svg: "icons/clothes3r.png",
            width: '30px',
            height: '30px'
        },
        "fuel": {
            query: '[out:json];node["amenity"="fuel"]',
            svg: "icons/gas-stationr.png",
            width: '28px',
            height: '28px'
        },
        "supermarket": {
            query: '[out:json];node["shop"="supermarket"]',
            svg: "icons/storer.png",
            width: '30px',
            height: '30px'
        },
        "tattoo": {
            query: '[out:json];node["shop"="tattoo"]',
            svg: "icons/tattoo3r.png",
            width: '30px',
            height: '30px'
        },
        "hospital": {
            query: '[out:json];node["amenity"="hospital"]',
            svg: "icons/medicalr.png",
            width: '30px',
            height: '30px'
        }
    };

    // Throttle Funktion
    function throttle(func, limit) {
        let inThrottle;
        return function() {
            const args = arguments;
            const context = this;
            if (!inThrottle) {
                func.apply(context, args);
                inThrottle = true;
                setTimeout(() => inThrottle = false, limit);
            }
        }
    }

    function reloadData() {
        for (let category in categories) {
            fetchCategoryData(category);
        }
    }

    const throttledReload = throttle(reloadData, 2000);  // 2000ms = 2 Sekunden

    
    

    map.on('load', function() {
        for (let category in categories) {
            map.loadImage(categories[category].svg, (error, image) => {
                if (error) throw error;
                if (!map.hasImage(category)) {
                    map.addImage(category, image);
                }
            });


            fetchCategoryData(category);
        }

        map.on('moveend', throttledReload);
    });

    function fetchCategoryData(category) {
        const bboxArray = map.getBounds().toArray();
        const bbox = [
            bboxArray[0][1],
            bboxArray[0][0],
            bboxArray[1][1],
            bboxArray[1][0]
        ].join(",");

        fetch(`https://overpass-api.de/api/interpreter?data=${categories[category].query}(${bbox});out;`)
            .then(response => response.json())
            .then(data => {
                const geoData = {
                    type: 'FeatureCollection',
                    features: data.elements.map(el => ({
                        type: 'Feature',
                        geometry: {
                            type: 'Point',
                            coordinates: [el.lon, el.lat]
                        }
                    }))
                };

                if (map.getSource(category)) {
                    map.getSource(category).setData(geoData);
                } else {
                    map.addSource(category, {
                        type: 'geojson',
                        data: geoData,
                        cluster: true,
                        clusterMaxZoom: 14,
                        clusterRadius: 50
                    });

                    map.addLayer({
                        id: `${category}-clusters`,
                        type: 'symbol',
                        source: category,
                        filter: ['has', 'point_count'],
                        layout: {
                            'icon-image': category,
                            'icon-size': 0.5
                        }
                    });

                    map.addLayer({
                        id: `${category}-unclustered-point`,
                        type: 'symbol',
                        source: category,
                        filter: ['!', ['has', 'point_count']],
                        layout: {
                            'icon-image': category,
                            'icon-size': 0.5
                        }
                    });
                }
            });
    }

</script>
</body>
</html>

I tried several other pictures for the Custom Markers but It still displays those default Markers. I tried removing the layers for the working Marker Clusters "shopClothes, supermarket, tattoo" to check if there´s a layer conflict but It still displays the default markers for the not working categories. I tried upgrading to Mapbox gl js v2.15.0, nothing changed.

0

There are 0 best solutions below