MapBox supercluster wrong cluster locations
Asked Answered
S

2

6

I'm making a clustered map with mapbox supercluster. The problem I face is that clusters are not at the correct location. For example I only have dogs in the netherlands but when zoomed out they are in france aswel.

enter image description here

When I zoom further the clusters slowly move al to the Netherlands. When I am scrolling the clusters move on the map aswel.

The problem can be seen here on my site https://v2.sayhi.dog/?dog-map=true.

My code looks like this (I use vue.js):

<template>
    <div class="w-full h-full" id="map"></div>
</template>

<script>
    import mapboxgl from 'mapbox-gl'
    import Supercluster from 'supercluster';

    export default {
        props: ['locations'],

        data() {
            return {
                map: null,
                copyLocations: this.locations,
                clusters: [],
                markers: [],
                clustersGeojson: {},
                clusterIndex: null,
            }
        },

        mounted() {
            mapboxgl.accessToken = 'my-token';
            // init the map
            this.map = new mapboxgl.Map({
                container: 'map',
                style: 'mapbox://styles/sayhi/cjkp9e59x3m3y2rm1zbcc0c',
                zoom: 2,
            });

            this.addControls();
            this.map.on("load", () => { this.addMarkers() });
            this.map.addControl(new mapboxgl.NavigationControl());
        },

        methods: {
            addMarkers() {
                this.clusterIndex = new Supercluster({
                    radius: 40,
                    maxZoom: 10
                });

                this.clusterIndex.load(this.locations.features);
                this.map.on('moveend', () => { this.moveEnd(); });
                this.updateClusters();
            },

            updateClusters() {
                var bounds = this.map.getBounds(),
                    zoom = this.map.getZoom();

                this.clustersGeojson = this.clusterIndex.getClusters([
                    bounds.getWest(),
                    bounds.getSouth(),
                    bounds.getEast(),
                    bounds.getNorth()
                ], Math.floor(zoom));

                if (Object.keys(this.clusters).length) {
                    this.clusters.forEach(function(cluster) {
                        cluster.remove();
                    });
                }

                this.displayFeatures(this.clustersGeojson);
            },

            addControls() {
                this.map.addControl(new mapboxgl.NavigationControl(), "bottom-right");
                this.map.addControl(new mapboxgl.FullscreenControl(), "bottom-right");
            },

            moveEnd() {
                this.updateClusters();
            },

            displayFeatures(features) {
                if (this.markers.length) {
                    this.markers.forEach(function(marker) {
                        marker.remove();
                    });
                }

                features.forEach((feature) => {
                    var isCluster = (!!feature.properties.cluster) ? true : false,
                        $feature;

                    if (isCluster) {
                        var leaf = this.clusterIndex.getLeaves(feature.properties.cluster_id)[0];
                        $feature = document.createElement("div");
                        $feature.className = 'flex items-center justify-center w-12 h-12 rounded-full text-center text-white font-bold shadow bg-cover cursor-pointer bg-center';
                        $feature.style.backgroundImage = `url(${leaf.properties.image})`;

                        var $inner = document.createElement("div");
                        $inner.innerHTML = feature.properties.point_count_abbreviated;

                        $feature.appendChild($inner);
                        this.clusters[feature.properties.cluster_id] = new mapboxgl.Marker($feature).setLngLat(feature.geometry.coordinates).addTo(this.map);
                    } else {
                        $feature = document.createElement('div');
                        $feature.className = 'flex items-center justify-center w-12 h-12 rounded-full text-center text-white font-bold shadow bg-cover cursor-pointer bg-center';
                        $feature.style.backgroundImage = `url(${feature.properties.image})`;

                        this.markers.push(new mapboxgl.Marker($feature).setLngLat(feature.geometry.coordinates).addTo(this.map));
                    }
                });
            }
        }
    }
</script>

https://gist.github.com/larsjanssen6/ebb5d7e3887c885af4c65d294ca1fb77

It's a very frustrating problem and I'm struggling for days now, some help would be really appreciated.

--UPDATE--

I made a JSFiddle:

https://jsfiddle.net/obhstrvz/10/

Hope someone can help.

Sylph answered 31/8, 2019 at 13:19 Comment(3)
I cannot see any cluster markers at v2.sayhi.dog/?dog-map=trueEnugu
@Enugu they are back now :) tried something that didn't work.Sylph
The problem seems to boil down to failing to include the mapbox-gl.css file. See my answer.Enugu
E
4

When your page is loaded the following warning is displayed in the developer tools console:

This page appears to be missing CSS declarations for Mapbox GL JS, which may cause the map to display incorrectly. Please ensure your page includes mapbox-gl.css, as described in https://www.mapbox.com/mapbox-gl-js/api/.

And though the Mapbox GL JS API reference doesn't contain any instructions related to mapbox-gl.css, you can find its usage in the examples. Adding the following line to the <head> section of your page via developer tools eliminated various problems with positions (which, besides markers, are also manifested as missing map controls):

<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v1.3.0/mapbox-gl.css' rel='stylesheet' />

Note that you may need to use another version to match the version of your mapbox-gl.js file.

Enugu answered 3/9, 2019 at 13:9 Comment(1)
You sir are my hero :) Thanks a lot!Sylph
P
2

This link here says you need an offset for your markers so they can stay centerd all the time, and going through your code quickly i think you need it here

this.clusters[feature.properties.cluster_id] = new mapboxgl.Marker($feature,{ offset: 25 } ).setLngLat(feature.geometry.coordinates).addTo(this.map);

and here

this.markers.push(new mapboxgl.Marker($feature, { offset: 25 }).setLngLat(feature.geometry.coordinates).addTo(this.map));
Phthisic answered 2/9, 2019 at 16:2 Comment(4)
Hi, thanks for helping. But the offset is only when someone clicks on a marker. I don't do that yet. So unfortunately this can't be the problem.Sylph
No need, can you set up a fiddle or something, so i can test it more?Phthisic
Yes will make that tonight :)Sylph
I've made a JS fiddle jsfiddle.net/obhstrvz/10 please let me know if you need anything else.Sylph

© 2022 - 2024 — McMap. All rights reserved.