maplibre / maplibre-gl-js

MapLibre GL JS - Interactive vector tile maps in the browser
https://maplibre.org/maplibre-gl-js/docs/
Other
6.72k stars 718 forks source link

Style definition to allow relative paths in URLs #182

Open zstadler opened 3 years ago

zstadler commented 3 years ago

Motivation

ArcGIS REST API has a Vector Tile Style service that returns styles for vector tiles in Mapbox GL Style specification.

While the Mapbox Style requires that the URLs for glyphs, sprite, and sources must be absolute, the ArcGIS styles uses relative URLs. One advantage of this approach is that a style file can be used by different providers without modification.

It would be great if MapLibre is able to directly support style definitions with relative URLs.

An example from the above page:

{
   "version": 8,
   "sprite": "../sprites/sprite",
   "glyphs": "../fonts/{fontstack}/{range}.pbf",
   "sources": {
       "esri": {
           "type": "vector",
           "url": "../../"
       }
   },
   "layers": [
       {
           "id": "Graduated Color/GraduatedColor_poly/482025.000000 - 2135252.000000",
           "type": "fill",
           "source": "esri",
           "source-layer": "GraduatedColor_poly",
           "filter": [
               "==",
               "_symbol",
               0
           ],
           "layout": {},
           "paint": {
               "fill-color": "#FFFF80",
               "fill-outline-color": "#6E6E6E"
           }

...

       }
   ]
}

Design Alternatives

Design

Mock-Up

Concepts

Implementation

github-actions[bot] commented 3 years ago

This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days.

HarelM commented 3 years ago

fetch is able to get content from relative path, I'm not sure this is not supported... Relative urls are relative to the server that runs the site and the location of the "current" page and baseUrl... Can you share an example where this is not working?

zstadler commented 3 years ago

This is the GL Style for ESRI World_Basemap_v2, for example.

I've only tried it as a new base map in Israel Hiking.

HarelM commented 3 years ago

This won't work, the relative path are for a server somewhere not related to Israel Hiking. I know Israel Hiking is replacing the fonts and glyphs so you can't really test this. for example the relative path to the vector source is: https://basemaps.arcgis.com/arcgis/rest/services/World_Basemap_v2/VectorTileServer/ which seems like a definition of the vector source not part of the style, which is weird. Maybe there's a mapbox powered site somewhere on this server that can present this style, I don't know honesty, but this library is treating the URLs are relative to the current location this it is running from. I'm not sure there's anything to solve in this repo...

xabbu42 commented 3 years ago

I think the idea is to interpret the paths relativ to the style as baseurl, instead of relativ to the current location maplibre-gl-js is running from. I am correct in my understanding @zstadler?

This actually seems to be the more useful way to handle relativ pathes and easy enough to implement. There could be installations out there which depend on the current behaviour of course, but as this styles are non-standard anyway I would not consider that change as breaking the api.

HarelM commented 3 years ago

The question of "relative to what" seems like a complex question to me - what if you are using a tileJson to define the location of the tiles and this tilejson is on another server - do you look for the tiles relative to it or relative to where the style is? When looking at HTML and scripts loading, relative path is always to the server that hosts the page, this seems to me like a non ambiguous approach. @xabbu42 if you feel this is easy to implement go for it :-)

xabbu42 commented 3 years ago

We need to agree on the right thing to do first :-).

I would have expected tile urls in a tilejson to be relativ to that tilejson and tile urls directly in the style to be relativ to that style. So the least surprising and most useful way to handle relativ paths for me is to always interpret them relativ to the json file they occur in, just like relative paths in html are by default relativ to that html file itself.

HarelM commented 3 years ago

The above suggestion seems like the right logic to me, I tend to think there are a lot of edge cases for this request, but if you feel confident about it go ahead :-) We can always solve these later on...

zstadler commented 3 years ago

I think the idea is to interpret the paths relativ to the style as baseurl, instead of relativ to the current location maplibre-gl-js is running from. I am correct in my understanding @zstadler?

This actually seems to be the more useful way to handle relativ pathes and easy enough to implement. There could be installations out there which depend on the current behaviour of course, but as this styles are non-standard anyway I would not consider that change as breaking the api.

Yes.

For example, https://basemaps.arcgis.com/arcgis/rest/services/World_Basemap_v2/VectorTileServer/resources/styles has "sprite" : "../sprites/sprite",. It would be interpreted as https://basemaps.arcgis.com/arcgis/rest/services/World_Basemap_v2/VectorTileServer/resources/sprites/sprite

Sprite access will be done to https://basemaps.arcgis.com/arcgis/rest/services/World_Basemap_v2/VectorTileServer/resources/sprites/sprite.json https://basemaps.arcgis.com/arcgis/rest/services/World_Basemap_v2/VectorTileServer/resources/sprites/sprite.png and https://basemaps.arcgis.com/arcgis/rest/services/World_Basemap_v2/VectorTileServer/resources/sprites/sprite@2x.png

Similarly, "glyphs" : "../fonts/{fontstack}/{range}.pbf", will be interpreted as "glyphs" : "https://basemaps.arcgis.com/arcgis/rest/services/World_Basemap_v2/VectorTileServer/resources/fonts/{fontstack}/{range}.pbf",

and

"sources" : {
    "esri" : {
        "type" : "vector",
        "url" : "../../"
    }

will be interpreted as

"sources" : {
    "esri" : {
        "type" : "vector",
        "url" : "https://basemaps.arcgis.com/arcgis/rest/services/World_Basemap_v2/VectorTileServer"
    }
zstadler commented 3 years ago

Thanks @xabbu42 for taking this task in#645!

klokan commented 2 years ago

Discussed today on the SC meeting.

+1 for the idea - it seems to be a nice general implementation. Thanks for the effort!

Could we update the documentation in https://github.com/maplibre/maplibre-gl-js-docs/tree/main/docs/pages/style-spec

Especially:

animaux commented 1 year ago

Will relative URLs be available in a specific version?

HarelM commented 1 year ago

I think this might be possible using addProtocol and/or transformRequest. If so, a plugin that add this support would be a better solution to this issue, IMHO. @animaux this is currently not available in a specific version.

xabbu42 commented 1 year ago

As already discussed in #645, this can't be implemented with transformRequest.

animaux commented 1 year ago

@animaux this is currently not available in a specific version.

Thanks, my question was more aiming at if an implementation of this is already planned for inclusion in a coming version.

HarelM commented 6 months ago

@Kai-W might have a solution for an issue similar to this one, maybe he could share what can be a workaround/solution to this issue as well.

Kai-W commented 6 months ago

I had urls relative to the pages origin (e.g. /fonts/{fontstack}/{range}.pbf) transformRequest worked to transform the urls absolute paths: transformRequest: url => ({ url: location.origin + url})

animaux commented 6 months ago

As already discussed in #645, this can't be implemented with transformRequest.

@Kai-W thanks! So this is not true anymore?

This looks easy to implement. Where exactly does the transformRequest need to be included?

xabbu42 commented 6 months ago

As already discussed in #645, this can't be implemented with transformRequest.

@Kai-W thanks! So this is not true anymore?

It is true for the general case. The described transformRequest uses the same base for all urls and therefore only works in specific scenarios. So you can work around the missing feature for your situation where you know what urls to expect and what the correct base is. There is no way to write a transformRequest that can handle arbitrary styles with relative urls as they all may have different bases.

KiwiKilian commented 6 months ago

As this initial issue also talks about relative sprite URLs the problem of #3897 also applies, because the sprite url can't be rewritten, as it's parsed before transformRequest is triggered.

animaux commented 6 months ago

@KiwiKilian Thanks, ok so this remains a problem.

Kai-W commented 6 months ago

yes i had problems with the sprite urls https://github.com/maplibre/maplibre-gl-js/issues/3897 the rest worked fine. A temporary fix https://github.com/maplibre/maplibre-gl-js/pull/3923 was merged a few days ago and a more permanet one https://github.com/maplibre/maplibre-gl-js/pull/3898 has a small breaking change and is linked to v5.

KiwiKilian commented 6 months ago

Great, thanks for the clarification @Kai-W!

HarelM commented 2 weeks ago

Ad suggested in #4962, This should be possible using StyleTransformFunction when setting a style, another suggestion would be to allow setting a StyleTransformFunction as part of the map options to facilitate for this. But this was not implemented yet, and I'm not sure it helps enough is this case for someone to implement it...