3

I have a gray layer to display multiple polygons on the Mapbox map. I'm attempting to change the color of only one of them when the user clicks on it to display the "selected" the polygon. I don't want interaction, that's why I'm not using the Draw library, just to show the selected polygon.

enter image description here

Is there any way to do it in just one layer?? I tried adding a boolean property called "selected" to each polygon property, but I didn't achieve to update the layer.

// Define polygons with properties
var features = [];
areas.forEach(area => features.push(turf.polygon(area.polygon, { id_area: area.id_area, name: area.name, selected: 'false' })));
features = turf.featureCollection(features);

map.on('load', function () {
    // Add polygons to map
    map.addSource('areas', {
        'type': 'geojson',
        'data': features
    });
    // Layer settings
    map.addLayer({
        'id': 'polygons',
        'type': 'fill',
        'source': 'areas',
        'paint': {
            'fill-color': [
                'match',
                ['get', 'selected'],
                'true', '#64bdbb', // if selected true, paint in blue
                '#888888' // else paint in gray
            ],
            'fill-opacity': 0.4
        },
        'filter': ['==', '$type', 'Polygon']]
    });
}); 
// Click on polygon
map.on('click', 'polygons', function (e) {
    if(e.features.length) {
        var feature = e.features[0];
        if (feature.properties.id_area == id) {
            feature.properties.selected = 'true';
        } else {
            feature.properties.selected = 'false';
        }


        // How can I update the layer here to repaint polygons????


    }
});
1
  • Please cut/paste your answer (SOLUTION) from the area reserved for questions into the area reserved for answers.
    – PolyGeo
    Feb 7, 2020 at 11:54

2 Answers 2

3

I believe this should work. It's very similar to this hover effect tutorial:

https://docs.mapbox.com/help/tutorials/create-interactive-hover-effects-with-mapbox-gl-js/

map.on('load', function () {
    // Add polygons to map
    map.addSource('areas', {
        'type': 'geojson',
        'data': features
    });
    // Layer settings
    map.addLayer({
        'id': 'polygons',
        'type': 'fill',
        'source': 'areas',
        'paint': {
            'fill-color': [
                'case',
                ['boolean',['feature-state', 'clicked'], true],
                '#64bdbb', // if selected true, paint in blue
                '#888888' // else paint in gray
            ],
            'fill-opacity': 0.4
        },
        'filter': ['==', '$type', 'Polygon']]
    });
}); 

var polygonID = null;

map.on('click', 'polygon', (e) => {
  map.getCanvas().style.cursor = 'pointer';
  if (e.features.length > 0) {
    if (polygonID) {
      map.removeFeatureState({
        source: "polygon",
        id: polygonID
      });
    }

    polygonID = e.features[0].id_area;

    map.setFeatureState({
      source: 'polygon',
      id: polygonID,
    }, {
      clicked: true
    });
  }
});
8
  • Thanks for your reply. I tried that, but it seems e.features[0].id it's undefined, don't know why...
    – nash
    Feb 6, 2020 at 16:29
  • I'm guessing that it's because your feature doesn't have an "id" field, so it's giving you undefined. If you use "id_area" like you have in your code, that should fix that.
    – MattM
    Feb 6, 2020 at 16:33
  • But the "id" field shouldn't be automatically created when adding the polygons sources on the map??
    – nash
    Feb 6, 2020 at 16:35
  • In your code you specify the id_area field: areas.forEach(area => features.push(turf.polygon(area.polygon, { id_area: area.id_area, name: area.name, selected: 'false' })));
    – MattM
    Feb 6, 2020 at 16:39
  • Yea, I fixed that... Thank you!! But anyway, setFeatureState to clicked: true doesn't make any styling change on the layer. Should I configure somehow the layer?
    – nash
    Feb 6, 2020 at 16:42
1

Following @MattM's answer and this tutorial I finally made it work.

map.on('load', function () {
    map.addSource('areas', {
        'type': 'geojson',
        'data': features,
        'generateId': true // From the tutorial, we must generate ids with the generateId option
    });

    map.addLayer({
        'id': 'polygons',
        'type': 'fill',
        'source': 'areas',
        'paint': {
            'fill-color': [
                'case',
                ['boolean', ['feature-state', 'clicked'], false], // Set this to false
                '#64bdbb',
                '#888888'               ],
            'fill-opacity': 0.4
        },
        'filter': ['==', '$type', 'Polygon']
    });
}); 

map.on('click', 'polygons', function (e) {
    if (e.features.length > 0) {
        if(typeof polygonID === 'number') { // Need to change this
            map.removeFeatureState({
                source: "areas",
                id: polygonID
            });
        }

        polygonID = e.features[0].id; // Get generated ID

        map.setFeatureState({
            source: 'areas',
            id: polygonID,
        }, {
            clicked: true
        });
    }
});

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.