tangrams / tangram

WebGL map rendering engine for creative cartography
https://tangram.city
MIT License
2.22k stars 290 forks source link

Add URL template support for @2x tiles #695

Closed bcamper closed 5 years ago

bcamper commented 5 years ago

This adds support for @2x-style tile filenames, often used for high-density raster tiles. For this implementation I opted to follow the same, simple logic as Leaflet, which is:

A {r} URL template substitution option, which adds the string @2x for any device with a device pixel ratio > 1.

CartoDB basemap example:

sources:
    raster:
        type: Raster
        url: https://a.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}{r}.png

Note, while this syntax is traditionally used with raster tiles, this implementation also applies to vector tiles (which could conceivably be useful for loading higher resolution vectors on high-density displays, though there are no plans for this currently).

Since the @2x syntax is pretty specific, the next step here, which I intentionally left out of scope for this PR, would probably be to support a JS function that could be passed the relevant tile XYZ and device pixel ratio, and return a tile URL.

bcamper commented 5 years ago

Since there's already a lot of raster related additions in v0.17.0, I figured I would add this in there too, since it's been discussed previously and is a small scope of change.

bcamper commented 5 years ago

@meetar @nvkelso @matteblair any thoughts?

meetar commented 5 years ago

LGTM! :shipit:

pnorman commented 5 years ago

What about other scales? As an example, maps.wikimedia.org allows scales 1.3, 1.5, 2, 2.6, and 3

e.g. https://maps.wikimedia.org/osm-intl/0/0/0@3x.png is image

bcamper commented 5 years ago

@pnorman I wondered if someone would bring up other scales ;) That is really interesting about Wikimedia maps, I didn't know of examples out there with fractional zooms!

So, syntax that would capture that could be something like (following our url_subdomains param):

url_density_scales: [1, 1.3, 1.5, 2, 2.6, 3]

1 could be an assumed/implied value, but I think probably better to explicitly require it to be listed, in case you wanted to not even support 1x display (valid considering the growth of higher density displays).

In that case, the default value for this parameter could be [1, 2].

bcamper commented 5 years ago

I've added support for the proposed url_density_scales parameter, and successfully tested on Wikimedia maps with this scene:

sources:
  raster:
    type: Raster
    url: https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}{r}.png
    url_density_scales: [1, 1.3, 1.5, 2, 2.6, 3]

layers:
  raster:
    data: { source: raster }
    draw:
       raster:
          order: 0

@meetar @nvkelso @matteblair what do you think of the proposed syntax?

nvkelso commented 5 years ago

I don't have objections – beyond pointing out vector tiles FTW ;)

nvkelso commented 5 years ago

Also a nit:

    url: https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}{r}.png
    url_density_scales: [1, 1.3, 1.5, 2, 2.6, 3]

I understand the use of r to represent resolution, but the param url_density_scales doesn't tie together with that well.

bcamper commented 5 years ago

I understand the use of r to represent resolution, but the param url_density_scales doesn't tie together with that well.

Agree, I started with {r} because Leaflet uses it. But we also use density as a param in our texture definitions. We could do something like url_resolutions, or use a different (maybe less recognized) URL syntax like {d} instead.

nvkelso commented 5 years ago

So someone is likely to copy-paste:

url: https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}{r}.png

And expect it to "just work"...

While url_density_scales or url_resolutions is a Tangram-ism? I favor url_density_scales then, but with documentation that explains that it's for "resolution" and linked with the r?

matteblair commented 5 years ago

This seems reasonable to me. I was also going to ask why r is the token - convention is a good enough reason.

Would you still expect to enable specifying this parameter with a JS function? Having two ways to do this seems a bit much.

bcamper commented 5 years ago

Would you still expect to enable specifying this parameter with a JS function? Having two ways to do this seems a bit much.

@matteblair agreed, I don't see a need at this point, I was just making a note that it's a possible way to provide more flexibility. I was planning to stop here :)

bcamper commented 5 years ago

I realize now that while I suggested that tile density 1 should be explicitly listed in url_density_scales, the code I wrote does not do that...

What should happen in the case of a 1x display with url_density_scales: [2, 3]:

  1. No URL qualifier, e.g. just tile.png
  2. Since 2 is the first scale listed, it should be used: tile@2x.png

I still think my instinct towards the latter option is a bit safer, because otherwise you're requiring tile support for "bare" URLs (which is generally but might not always be true). Note that the proposed default is [1, 2], meaning tile.png and tile@2x.png.

matteblair commented 5 years ago

Yeah I agree that this list syntax should be sufficient.

It occurs to me that there might be other styles of declaring image density. We could narrow the parameter to just the density value and declare templates like https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}@{r}x.png but that sort of breaks the 1x case. Probably not worth worrying about.

bcamper commented 5 years ago

I have updated the behavior to match my original description, e.g.:

This means there is special handling for a value of 1 (or below, though I've never seen that in practice), but this seems to match the existing convention.

bcamper commented 5 years ago

Merging based on discussion above -- feel free to leave additional comments, can make adjustments as needed.