-
Notifications
You must be signed in to change notification settings - Fork 134
Fix vector sources lookup #1267
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix vector sources lookup #1267
Conversation
|
I'm currently reviewing this. Quick note: strictly speaking, there is nothing broken, because your new example would work with applyStyle(layer, styleUrl, {source: 'maptiler_planet'});According to the docs, the first source is only used if the The real problem here is that MapLibre did not add the clarifications "Required if So our actual chore here is to ignore vector sources that neither have |
src/util.js
Outdated
| tileLoadFunction, | ||
| }); | ||
| } else { | ||
| promise = Promise.reject(new Error('source has no tiles')); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| promise = Promise.reject(new Error('source has no tiles')); | |
| promise = Promise.reject(new Error('source has no `tiles` nor `url`')); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was just thinking: should we add a hint like "consider choosing a different source" or something for the next person that misses it like I did? 👀
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You won't get here any more in this case, so the error message here is fine. I suggested a new one in the correct place.
src/apply.js
Outdated
| const type = layer instanceof VectorTileLayer ? 'vector' : 'geojson'; | ||
| const desiredType = | ||
| layer instanceof VectorTileLayer ? 'vector' : 'geojson'; | ||
| const requiredAttrs = { | ||
| // for the respective source tiles, we expect any of those attributes to be present | ||
| 'vector': ['url', 'tiles'], | ||
| 'geojson': ['data'], | ||
| }; | ||
| if (!sourceOrLayers) { | ||
| sourceId = Object.keys(glStyle.sources).find(function (key) { | ||
| return glStyle.sources[key].type === type; | ||
| // NOTE: this is mostly a heuristic way of picking the source, the TODO comment above still applies. | ||
| const sourceType = glStyle.sources[key].type; | ||
| const typeMatch = sourceType === desiredType; | ||
| const hasRequiredAttrs = requiredAttrs[sourceType].some( | ||
| function (attr) { | ||
| return Object.keys(glStyle.sources[key]).includes(attr); | ||
| }, | ||
| ); | ||
| return typeMatch && hasRequiredAttrs; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of this involved change, it would be smarter to detect the source by the layers that use it, i.e.
sourceId = glStyle.layers.find(function (layer) {
return layer.source && glStyle.sources[layer.source].type === type;
}).source;There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that this is more elegant, thanks!
Co-authored-by: Andreas Hocevar <[email protected]>
6b1dd1d to
707f9bb
Compare
|
Thanks a lot for the super quick review :) Sorry, I was quite busy this week. I implemented your suggestions and also updated the test cases and documentation string to reflect them. Thanks also for pointing out that the source can be configured, I had missed that 🤦🏼 |
src/util.js
Outdated
| tileLoadFunction, | ||
| }); | ||
| } else { | ||
| promise = Promise.reject(new Error('source has no tiles')); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You won't get here any more in this case, so the error message here is fine. I suggested a new one in the correct place.
Co-authored-by: Andreas Hocevar <[email protected]>
ahocevar
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, @remogeissbuehler
Overview
This PR introduces a heuristic fix to choose the "correct" source layer for vector maps. In particular, when the
style.jsonhas multiple sources, such as:this currently fails, as the logic to pick the source to display for a
VectorTileLayeris "take the first source withtype == 'vector'":https://github.com/openlayers/ol-mapbox-style/blob/7b69c36a9792581b5d479c24ad9a2789a91593c3/src/apply.js#L253C1-L255C14
So in this case, we pick the one that does not in fact have any tile reference (

.urlor.tiles), which in turn leads to an exception inutils.js:Motivation
This exact bug happens for the Maptiler "basic-v2" map. I included it as a new example, which is broken in the current version but works with this fix.
Implementation
To tackle this problem, I added two main fixes:
Check for tiles and url in utils (
getTileJson)getTileJsonpreviously assumed that either.urlor.tilesare present. Sadly, this assumption doesn't always hold, so I added an extra check and raise an Error when neither are present for a more meaningful message in case this happens.Heuristic choice of source
I replaced the above-mentioned logic to choose the source for
VectorTileLayerfor the following: "choose the first source of correct type that has at least one of the required attributes":https://github.com/remogeissbuehler/ol-mapbox-style/blob/dc21b6e2783451fa5f3190c38b95a60053f4a6b2/src/apply.js#L259C1-L269C14
Note: I don't think this fully fixes the issue, as there could be multiple relevant sources and we still only pick one (at least a relevant one now). If I understand this spec correctly, the sources on their own don't say much about their display and the layers should instead be used as they refer to the different sources. Implementing this seems like a much bigger change to me though...