Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How get features from a style's layer in Mapbox GL JS?

I'm a learner of JavaScript and have a problem with Mapbox GL JS: I have a style in Mapbox Studio, where there is one my layer — "locations". I've added it as a tileset. There are two GeoJSON-points in this layer, but I can't get them in GL JS. I've found that I should use method querySourceFeatures(sourceID, [parameters]), but I have problems with correct filling its parameters. I wrote:

var allFeatures = map.querySourceFeatures('_id-of-my-tyleset_', {
  'sourceLayer': 'locations'
});

..and it doesn't work.

More interesting, that later in the code I use this layer with method queryRenderedFeatures, and it's okay:

map.on('click', function(e) {
      var features = map.queryRenderedFeatures(e.point, {
        layers: ['locations']
      });

      if (!features.length) {
        return;
      }
      var feature = features[0];
      flyToPoint(feature);
      var popup = new mapboxgl.Popup({
          offset: [0, -15]
        })
        .setLngLat(feature.geometry.coordinates)
        .setHTML('<h3>' + feature.properties.name + '</h3>' + '<p>' +
          feature.properties.description + '</p>')
        .addTo(map);
    });

I have read a lot about adding layers on a map and know that the answer is easy, but I can't realise the solution, so help, please :)

Here is the project on GitHub.

like image 920
nikiforovpizza Avatar asked Sep 07 '17 16:09

nikiforovpizza


2 Answers

Your problem is that your map, like all maps created in Mapbox Studio by default, uses auto-compositing. You don't actually have a source called morganvolter.cj77n1jkq1ale33jw0g9haxc0-2haga, you have a source called composite with many sub layers.

You can find the list of layers like this:

map.getSource('composite').vectorLayerIds

Which reveals you have a vector layer called akkerman. ("locations" is the name of your style layer, not your source layer). Hence your query should be:

map.querySourceFeatures('composite', {
  'sourceLayer': 'akkerman'
});

Which returns 4 features.

like image 190
Steve Bennett Avatar answered Oct 16 '22 14:10

Steve Bennett


There are lots of questions about Mapbox get features after filter or Mapbox get features before filter. And I could see there are many posts are scattering around but none of them seem to have a FULL DETAILED solution. I spend some time and put both solution together under a function, try this in jsbin. Here it is for someone interested:

function buildRenderedFeatures(map) {
  // get source from a layer, `mapLayerId` == your layer id in Mapbox Studio    
  var compositeSource = map.getLayer(mapLayerId.toString()).source;
  //console.log(map.getSource(compositeSource).vectorLayers);
  var compositeVectorLayerLength = map.getSource(compositeSource).vectorLayers.length - 1;
  //console.log(compositeVectorLayerLength);
  // sourceId === tileset id which is known as vector layer id
  var sourceId = map.getSource(compositeSource).vectorLayers[compositeVectorLayerLength].id;
  //console.log(sourceId);
  
  // get all applied filters if any, this will return an array    
  var appliedFilters = map.getFilter(mapLayerId.toString());
  //console.log(appliedFilters);
   
  // if you want to get all features with/without any filters
  // remember if no filters applied it will show all features
  // so having `filter` does not harm at all 
  //resultFeatures = map.querySourceFeatures(compositeSource, {sourceLayer: sourceId, filter: appliedFilters});
  var resultFeatures = null;

  // this fixes issues: queryRenderedFeatures getting previous features
  // a timeout helps to get the updated features after filter is applied
  // Mapbox documentation doesn't talk about this! 
  setTimeout(function() {
    resultFeatures = map.queryRenderedFeatures({layers: [mapLayerId.toString()]});
    //console.log(resultFeatures);
    }, 500);
  }

Then you call that function like: buildRenderedFeatures(map) passing the map object which you already have when you created the Mapbox map.

You will then have resultFeatures will return an object which can be iterated using for...in. You can test the querySourceFeatures() code which I commented out but left for if anyone needs it.

like image 2
Asrar Avatar answered Oct 16 '22 14:10

Asrar