qfes / rdeck

Deck.gl widget for R
https://qfes.github.io/rdeck
MIT License
97 stars 0 forks source link

Place an MVT layer under a layer present in the basemap #58

Closed bdbmax closed 2 years ago

bdbmax commented 2 years ago

In the mapbox studio, we can slide a layer down others, makeing their labels appear on top of the MVTs. Assuming add_mvt_layer is translated to the map.addLayer function of mapbox, the latter also have the beforeId parameter (https://docs.mapbox.com/mapbox-gl-js/api/map/#map#addlayer), that would let us specify where the added layer appears in relation to the stack of other layers in the mapbox style.

From some documentation coming from mapbox, here is an example of how we can supply the layer under another part of the style. In this case, line geometries under the road labels:

map.addLayer({
  'id': 'tiger-roads-id',
  'type': 'line',
  'source': 'tiger-roads-src',
  'source-layer': 'roads',
  'layout': {
    'line-join': 'round',
    'line-cap': 'round'
  },
  'paint': {
    'line-color': '#ff69b4',
    'line-width': 10
  }
},
'road-label');
});

I tried taking advantage of the ... argument of add_mvt_layer and supply the beforeId = 'road-label', but without success. Is this achievable in the context of rdeck?

Again, thanks for you great package!

anthonynorth commented 2 years ago

rdeck doesn't support interleaving deck.gl layers with basemap layers; all of the layers you add to an rdeck map are deck.gl layers and will be rendered on top of the basemap as an overlay. The mvt_layer is the deck.gl MVTLayer which renders tile data as a GeoJsonLayer.

You could also just use the layer_selector and toggle layers off when you need to see the basemap, unobstructed by data: rdeck(layer_selector = TRUE). Assuming that your data is more important than the basemap context the majority of the time, this should work well -- my team does this.

If you need to put basemap labels on top of your data, you can achieve that by re-drawing the labels on top of other deck.gl layers with another mvt_layer (or text_layer if the data is local).

PS: I don't intend to support deck.gl and mapbox-gl interleaving via MapboxLayer.

bdbmax commented 2 years ago

All right, thanks for the quick answer!

Just tried with local data and add_text_layer, works fine! To avoid the addition of a layer, there's a column in my MVT with the labels of my polygons. I saw the get_text argument in the Usage part of the add_mvt_layer documentation, but couldn't make it work the same way I did with add_text_layer! Labels don't appear. Here's a reprex if you'd like to take a look:

shinyApp(
  ui = fillPage(
    rdeckOutput("map", height = "100%"),
  ),

  server = function(input, output) {

    output$map <- renderRdeck(
      rdeck(theme = "mapbox://styles/mapbox/streets-v11",
            initial_view_state = view_state(center = c(-73.58, 45.53), 
                                            zoom = 10.1)) |> 
        add_mvt_layer(id = "test", 
                      data = mvt_url("maxbdb.borough_7"),
                      pickable = TRUE, tooltip = TRUE, 
                      get_text = rlang::sym("name"),
                      get_fill_color = "#FE7D6AFF")
    )
  }
)
anthonynorth commented 2 years ago

mvt_layer can draw text for point features via point_type = "text" (or "circle+text", "icon+text" etc). That tileset doesn't appear to have any point features though.

Unrelated note, changing the basemap is done via map_style; theme ("kepler" or "light") is for css -- and appears to be not validated.

library(rdeck)
library(shiny)
shinyApp(
  ui = fillPage(
    rdeckOutput("map", height = "100%"),
  ),

  server = function(input, output) {

    output$map <- renderRdeck(
      rdeck(map_style = "mapbox://styles/mapbox/streets-v11",
            initial_view_state = view_state(center = c(-73.58, 45.53), 
                                            zoom = 10.1)) |> 
        add_mvt_layer(id = "test", 
                      data = mvt_url("maxbdb.borough_7"),
                      pickable = TRUE, tooltip = TRUE, 
                      get_text = rlang::sym("name"),
                      get_fill_color = "#FE7D6AFF",
                      point_type = "text")
    )
  }
)
bdbmax commented 2 years ago

That fixes the issue. Thanks a lot!