hugonbg
hugonbg

Reputation: 103

Show popup on the map for the selected item in the side list using the mapbox gl js

I followed this tutorial "Filter features within map view" and managed to adapt it to my data, which are polygons instead of points.

However, the popups on the side menu are not displayed, when I place the mouse over one of the locations, the popup does not appear on the map indicating the location as it should. The problem I believe is that because it is a polygon and not a point (a pair of coordinates) the code cannot display the location, the error in the console is:

"Uncaught Error:` LngLatLike` argument must be specified as a LngLat instance, an object {lng: <lng>, lat: <lat>}, an object {lon: <lng>, lat: <lat>}, or an array of [<lng>, <lat>] "

In the map popup I changed it from ".setLngLat (feature.geometry.coordinates)" to ".setLngLat (e.lngLat)" and it worked, but not in the popup on the side menu. I'm still starting to learn javascript and I couldn't find a solution, I thought about extracting the centroid from the polygon, but I don't know how to do it.

the code that generates the popup:

var prop = feature.properties;
var item = document.createElement('a');
item.href = prop.wikipedia;
item.target = '_blank';
item.textContent = prop.NM_UF + ' (' + prop.SIGLA_UF + ')';
item.addEventListener('mouseover', function () {
    // Highlight corresponding feature on the map
    popup
        .setLngLat(feature.geometry.coordinates)
        .setText(
            feature.properties.NM_UF +
            ' (' +
            feature.properties.SIGLA_UF +
            ')'
        )
        .addTo(map);
});
listingEl.appendChild(item);
    });

Here is a codepen like the code: https://codepen.io/hugonbgg/pen/PoNwWVj and the debug: https://codepen.io/hugonbgg/debug/PoNwWVj/

Upvotes: 0

Views: 1256

Answers (1)

jscastro
jscastro

Reputation: 3780

Long story short, you are using a source that includes Polygon and MultiPolygon features together, so your selected feature coordinates is sometimes an array and sometimes a multidimensional array.

There are different ways to solve this...

Quick and dirty

popup
    .setLngLat(feature.geometry.coordinates[0][0]) //just add [0][0]
    .setText(
        feature.properties.NM_UF +
        ' (' +
        feature.properties.SIGLA_UF +
        ')'
    )
    .addTo(map);

This just works but positions the popup tip on the first point of the first polygon... not definitely the best but it works.

The second method is what I would do...

Find the center of any feature through a method

I have created this codepen based on yours with this change to include a getFeatureCenter method.

function getFeatureCenter(feature) {
    let center = [];
    let latitude = 0;
    let longitude = 0;
    let height = 0;
    let coordinates = [];
    feature.geometry.coordinates.forEach(function (c) {
        let dupe = [];
        if (feature.geometry.type === "MultiPolygon")
            dupe.push(...c[0]); //deep clone to avoid modifying the original array
        else 
            dupe.push(...c); //deep clone to avoid modifying the original array
        dupe.splice(-1, 1); //features in mapbox repeat the first coordinates at the end. We remove it.
        coordinates = coordinates.concat(dupe);
    });
    if (feature.geometry.type === "Point") {
        center = coordinates[0];
    }
    else {
        coordinates.forEach(function (c) {
            latitude += c[0];
            longitude += c[1];
        });
        center = [latitude / coordinates.length, longitude / coordinates.length];
    }

    return center;
}

and then change in your call to the popup

popup
    .setLngLat(getFeatureCenter(feature)) //call the new method and enjoy!
    .setText(
        feature.properties.NM_UF +
        ' (' +
        feature.properties.SIGLA_UF +
        ')'
    )
    .addTo(map);

This will find the feature center independently if it is Point, Polygon or MultiPolygon...

enter image description here

PS.- If this answer solves your question, please mark it as "answer accepted", in that way will also help other users to know it was the right solution.

Upvotes: 1

Related Questions