codebot
codebot

Reputation: 697

mapbox gl js feature Id and properties.id not always static and different

In mapbox-gl-js version: 2.10.0 I click on a point on a map and get all the features from 2 vector layers (application/vnd.mapbox-vector-tile) and one geojson layer data: 'http://localhost:8080/geoserver/mydata/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=mydata%3Acontexts&outputFormat=application%2Fjson' , , all served from GeoServer

In Geoserver's store I have Expose primary keys enabled, so in the features properties I have their IDs , coming from the database

I try to remove the duplicates that may created by mapbox based on their properties.id (sometimes mapbox creates duplicates of the same feature in vector and geojson, depending on zoom level)

Then I want to check if I have multiple features in the first vector layer. If I do, I create some objects, including data from other layers. To see what belongs to what feature from the first layer, I do it based on their properties.id , but sometimes its the same for both features, while feature id is different. I thought that properties.id always stays the same and its not duplicated on multiple features.

here is my code

map.current.on('click', (e) => {  
    //get point
    const point = e.point; 
    //get all features from all layers from that point
    let features = map.current.queryRenderedFeatures(point); 

    //separate features by layer
    let excavations = features.filter(f => f.layer.id === 'excavations-layer');
    let parts = features.filter(f => f.layer.id === 'excavation_parts-layer');
    let contexts = features.filter(f => f.layer.id === 'contexts-layer');  
    
    //removing duplicates 
    excavations = excavations.filter((value, index, self) =>
      index === self.findIndex((et) => (
        et.properties.id === value.properties.id
      ))
    )
    parts = parts.filter((value, index, self) =>
      index === self.findIndex((pt) => (
        pt.properties.id === value.properties.id
      ))
    )
    contexts = contexts.filter((value, index, self) =>
      index === self.findIndex((ct) => (
        ct.properties.id === value.properties.id
      ))
    ) 
      //organize data per excavation, based on ids
      excavations.forEach(e => {
        ex_excavations = excavations.filter((value) => 
          e.properties.id == value.properties.id
        )
        ex_parts = parts.filter((value) => 
          e.properties.id = value.properties.excavation_id
        )
        ex_contexts = contexts.filter((value) => 
          turf.booleanIntersects(value,e)
        )
        exgroupArray.push(
          {
            name:e.properties.name,
            excavations:ex_excavations,
            parts:ex_parts,
            contexts:ex_contexts
          }
        )
        console.log('e id  loop ', e.id);    
        console.log('exgroupArray ', exgroupArray);    
        console.log('====================');    
      }); 

The original excavations array where I do the first forEach excavations.forEach(e => { has different feature ids (12,13) , but the same properties.id (12,12)

Other times has the same feature ids (12,12) , but different properties.id (12,13)

Check image

enter image description here

I though that properties.id comes from the Geoserver and should always be the different for each feature.

I try to base my code on that, but because it changes, it messes up my final exgroupArray and cannot loop it correctly in the HTML.

Any help how to fix this?

Thanks

Edit : It seems like if I am fully zoomed out, I get same feature id, different properties.id, check second image

enter image description here

Upvotes: 3

Views: 892

Answers (1)

cicada_
cicada_

Reputation: 336

I encountered a similar problem. I believe what happens is until explicitly instructed mapbox generates unique IDs for each feature in a specific tile.

Hence features that are in different tiles will get the same numeric id.

But there's a way to fix it. You can go through the documentation over here. The promoteId config explcitly tells the mapbox to not generate new IDs but rather use a specific field from properties section.

Here's a sample code:

map.addSource('earthquakes', {
    "type": "vector",
    tiles: ["http://localhost:8081/api/asset/tile/{z}/{x}/{y}.pbf"],
    "promoteId": {"LAYER_NAME": "id"}
});

In this sample code I'm overwriting the ID for only one cluster layer LAYER_NAME and the field I'm using from properties is named id

Upvotes: 0

Related Questions