Mapbox-gl-js: Layer features duplicate IDs on mousemove

Created on 24 May 2019  Â·  9Comments  Â·  Source: mapbox/mapbox-gl-js

mapbox-gl-js version: 1.0.0

browser: Firefox

Steps to Trigger Behavior

I was following the tutorial to create hover listeners: https://docs.mapbox.com/mapbox-gl-js/example/hover-styles/
However when I changed the source to a custom tileset: mapbox://krulvis.cwaqjxsv I get duplicate feature id's.

Link to Demonstration

https://jsbin.com/cuhewomepo/1/edit?html,js,output

Expected Behavior

Hover over one feature -> receive id of one feature -> alter state of one feature

Actual Behavior

multiple features get affected by same id

bug needs investigation

Most helpful comment

Just posting a possible workaround for any other weary travelers. I spent a lot of time on this, attempting to translate geojson to mbtiles without messing with the compression recipe, installing numerous libraries, hours of python install / sleep / remove / repeat loops, finally landing on the tilesets cli which ended in tears and broken sockets / dreams.

And then I twigged I could probably just do it on the client after all ...

// instead of setting the state you want:
map.setFeatureState(feature, { hover: true });
// set a reference to a unique feature property:
map.setFeatureState(feature, { id: feature.properties.id });
// then in your layer styles you can self-reference
// so even multiple features with the same id will always be uniquely identifiable
[
  'case',
  ['==', ['get', 'id'], ['feature-state', 'id']],
  1, 0,
]
// ^^ above compares the feature property 'id' to the feature state 'id'
//    returns '1' for a match or '0' for a miss

NB: If your property doesn't support feature-state expressions then give up all hope.
FYI #7038

All 9 comments

Hi @Krulvis thanks for reaching out! Thanks also for including the jsbin - unfortunately the map doesn't seem to display there, but I was able to get your example working locally on my machine and can confirm the behavior you're seeing.

But it seems like this is a data issue rather than a bug. It looks like the 'id' values on the features in your source data are not unique (e.g. map.querySourceFeatures('gemeentes-src', { sourceLayer: 'townships-0u4ffk', filter: ['==', ['id'], 49] } ) returns 4 distinct features), so this is the behavior we would expect to see from the map. It also seems to give the expected behavior for features that _do_ happen to have a unique ID, e.g. 179 or 186. Can you try making sure that each feature in the original data set has a unique id value, and then re-exporting the tileset?

As this doesn't look like a bug in mapbox-gl-js, we're going to close this issue out for now. If the suggestion above still doesn't solve your problem, the best place to ask is either Stack Overflow or Mapbox support. If in the end you still think this is a bug in the mapbox-gl-js library, you can reopen this issue and add more details so we can investigate further.

Thanks! :heart:

There is no property id in the data. It gets assigned an id when uploading to mapbox studio or loading the data in mapbox GL-JS. I have no idea why certain features receive the same ID. Please re-open this issue. This is where the data is uploaded on mapbox studio: https://studio.mapbox.com/tilesets/krulvis.cwaqjxsv/
And this is the original dataset: https://www.dropbox.com/s/5ci0hosqakvdahx/townships.json?dl=0
The 'code' property is similar for some features but does not resemble the same id given by mapbox.

I checked again with the following code:
const filtered = map.querySourceFeatures('gemeentes-src', { sourceLayer: 'townships-0u4ffk', filter: ['>=', ['id'], 0] });
with console.log(filtered) it shows every feature in the source: 'gemeentes-src'
image

Additionally, you can see that the feature Lelystad at some point had id 2 while the img clearly shows that at the point of clicking on the feature, the id is 3. Something very strange is going on with those ids...

I added the code to the jsbin in: https://jsbin.com/cuhewomepo/1/edit?html,js,output

Further debugging with:
const filtered = map.querySourceFeatures('gemeentes-src', { sourceLayer: 'townships-0u4ffk', filter: ['==', 'name', 'Lelystad'] });

shows that there are 4 features with the name 'Lelystad' even though the datafile only contains one of such features.

Hey @Krulvis, looking at this closer, indeed it seems that the automatic IDs weren't generated properly on the Studio uploads side. While we're investigating, a workaround would be to add unique feature ids (as numbers) in the original data and either reupload or use as a GeoJSON source.

@Krulvis GeoJSON with ids loaded directly should certainly work; if Studio upload doesn't work, the best approach would be to use https://github.com/mapbox/tippecanoe (with --generate-ids option), making an mbtiles file and uploading it to Studio — this bypasses any data processing logic on the Studio side and gives you control over what gets into the tiles. Thank you for your patience! We'll update the ticket once we know what happened.

@Krulvis update — just got a word from our uploads API team that this is a known issue — the feature ids generated on the Studio side aren't unique across tiles, and if there are ids in the input GeoJSON, they get overwritten.

The best workaround currently is to use the Tileses API for bigger datasets that need to be tiled, and load GeoJSON directly for smaller ones. I'm going to close this as something that's not a fault of Mapbox GL JS, but feel free to reach out to Mapbox support if you encounter any other problems with the uploads.

@Krulvis GeoJSON with ids loaded directly should certainly work; if Studio upload doesn't work, the best approach would be to use https://github.com/mapbox/tippecanoe (with --generate-ids option), making an mbtiles file and uploading it to Studio — this bypasses any data processing logic on the Studio side and gives you control over what gets into the tiles. Thank you for your patience! We'll update the ticket once we know what happened.

Hi just an FYI this still doesn't work, even with MBTiles with --generate-ids .. id seems to be generated by studio on a per tile / zoom basis. ~Given that this seems to be hard to resolve on the studio side, is there a feature request here to allow for better targeting for feature state updates? Say by providing a tile reference alongside id / layer?~ Too hard basket #6876

Just posting a possible workaround for any other weary travelers. I spent a lot of time on this, attempting to translate geojson to mbtiles without messing with the compression recipe, installing numerous libraries, hours of python install / sleep / remove / repeat loops, finally landing on the tilesets cli which ended in tears and broken sockets / dreams.

And then I twigged I could probably just do it on the client after all ...

// instead of setting the state you want:
map.setFeatureState(feature, { hover: true });
// set a reference to a unique feature property:
map.setFeatureState(feature, { id: feature.properties.id });
// then in your layer styles you can self-reference
// so even multiple features with the same id will always be uniquely identifiable
[
  'case',
  ['==', ['get', 'id'], ['feature-state', 'id']],
  1, 0,
]
// ^^ above compares the feature property 'id' to the feature state 'id'
//    returns '1' for a match or '0' for a miss

NB: If your property doesn't support feature-state expressions then give up all hope.
FYI #7038

Was this page helpful?
0 / 5 - 0 ratings

Related issues

foundryspatial-duncan picture foundryspatial-duncan  Â·  3Comments

infacq picture infacq  Â·  3Comments

rigoneri picture rigoneri  Â·  3Comments

PBrockmann picture PBrockmann  Â·  3Comments

Scarysize picture Scarysize  Â·  3Comments