Open yvanrichard opened 2 months ago
This is doable. Via shiny is fairly straight forward using an observable()
and doesn't require any javascript. Without shiny this will require an onRender()
javascript function (not straight forward, non-public api).
Are you working in Shiny?
I have been trying the onRender() approach, but I haven't managed to access the layer in the javascript function so far. Could you provide a pointer on how to access the layer by any chance? My aim is to create a standalone html page that can be shared easily, using saveWidget. I'm trying to avoid the use of Shiny as much as I can. Wouldn't the observable cause the re-creation of the whole deck element anyway, which would be slow?
Zoom-dependent visibility is a common feature in GIS viewers. I reckon adding a minZoom and maxZoom argument in the layer functions would be a great addition if possible.
I have been trying the onRender() approach, but I haven't managed to access the layer in the javascript function so far. Could you provide a pointer on how to access the layer by any chance?
Sure. The following should get you started.
points_df <- vctrs::data_frame(position = wk::xy(runif(1e5, -180, 180), runif(1e5, -90, 90), "OGC:CRS84"))
map <- rdeck(map_style = stylebox::mapbox_light(), theme = "light") |>
add_scatterplot_layer(id = "random-point-layer", name = "random_point", data = points_df, get_radius = 5, radius_units = "pixels", visible = FALSE) |>
htmlwidgets::onRender("
function(el, x) {
// rdeck widget instance
const map = this.instance;
if (!map instanceof rdeck.Widget) {
// bail
}
// set layer visibility on zoom change
map.state.deckgl.onViewStateChange = ({viewState}) => map.setLayerVisibility([{ name: 'random_point', groupName: null, visible: viewState.zoom >= 3 }]);
}
")
map
Zoom-dependent visibility is a common feature in GIS viewers. I reckon adding a minZoom and maxZoom argument in the layer functions would be a great addition if possible.
I agree. I'll track this in a separate issue. (edit: unnecessary)
Wouldn't the observable cause the re-creation of the whole deck element anyway, which would be slow?
Rdeck supports partial updates of the map and layers, so a visibility toggle via shiny is efficient.
Looks something like this
library(rdeck)
points_df <- vctrs::data_frame(position = wk::xy(runif(1e5, -180, 180), runif(1e5, -90, 90), "OGC:CRS84"))
map <- rdeck(map_style = stylebox::mapbox_light(), theme = "light") |>
add_scatterplot_layer(id = "random-point-layer", name = "random_point", data = points_df, get_radius = 5, radius_units = "pixels", visible = FALSE)
ui <- shiny::fillPage(rdeckOutput("map", height = "100%"))
server <- function(input, output, session) {
output$map <- renderRdeck(map)
observe({
map_proxy <- rdeck_proxy("map", session)
view_state <- get_view_state(map_proxy)
if (!is.null(view_state$zoom)) {
# payload {"map:layer": {id: "random-point-layer", visible: false}
set_layer_visibility(map_proxy, "random-point-layer", visible = view_state$zoom >= 3)
}
})
}
shiny::shinyApp(ui, server)
Just amazing. Both your responses are very useful and are opening a whole realm of possibilities to me. Thank you so much, Anthony!
Is there any way of constraining a layer visibility based on the zoom level?
I'm aiming to display different text layers, each visible within a specific zoom range. Similar to country names at low zoom levels to town names at high zoom levels.
I have tried a few things using JavaScript but to no avail.