引用从 golem 模块到另一个的传单映射
Reference to a leaflet map from a golem module to another
我正在构建一个闪亮的应用程序,使用 Golem 作为框架。
在我的应用程序中,我制作了几个模块,所有模块都由 Leaflet 地图链接。
但是,我无法从创建地图的模块以外的其他模块更新地图。
我已尝试考虑 here 提出的建议,将 map_id
和 parent_session
包含到模块调用中,但每当我尝试将 map_id
和 parent_session
对地图的任何更改(没有错误跟踪)。
这是我的代码的精简版本,在单独的文件中:
app_server.R:
#' The application server-side
#'
#' @param input,output,session Internal parameters for {shiny}.
#' DO NOT REMOVE.
#' @import shiny
#' @import leaflet
#' @noRd
app_server <- function( input, output, session ) {
r <- reactiveValues(
map=NULL,
origin=list(lat=NULL, lng=NULL),
destination=list(lat=NULL, lng=NULL)
)
mod_basemap_server("basemap_ui_1", r, session)
mod_itinerary_server("itinerary_ui_1", r, map_id="basemap", parent_session=session)
}
app_ui.R:
#' The application User-Interface
#'
#' @param request Internal parameter for `{shiny}`.
#' DO NOT REMOVE.
#' @import shiny
#' @noRd
app_ui <- function(request) {
tagList(
bootstrapPage(
mod_basemap_ui("basemap_ui_1"),
mod_itinerary_ui("itinerary_ui_1")
)
)
}
mod_basemap.R:
#' basemap UI Function
#'
#' @description A shiny Module.
#'
#' @param id,input,output,session Internal parameters for {shiny}.
#'
#' @noRd
#'
#' @importFrom shiny NS tagList
mod_basemap_ui <- function(id){
ns <- NS(id)
tagList(
# Map background
leaflet::leafletOutput(ns("basemap"))
)
}
#' basemap Server Functions
#'
#' @noRd
mod_basemap_server <- function(id, r, session){
shiny::moduleServer( id, function(input, output, session){
ns <- session$ns
output$basemap <- leaflet::renderLeaflet({
# generate base leaflet
map = leaflet::leaflet(options = leaflet::leafletOptions(zoomControl = FALSE)) %>%
leaflet::addTiles(leaflet::providers$OpenStreetMap) %>%
leaflet::addProviderTiles(leaflet::providers$OpenStreetMap,
group="Open Street Map") %>%
leaflet::addProviderTiles(leaflet::providers$OpenTopoMap,
group="Open Topo Map") %>%
leaflet::addProviderTiles(leaflet::providers$Esri.WorldImagery,
group="Esri World Imagery") %>%
leaflet::fitBounds(2.78, 44.85, 3.41, 44.71) %>%
leaflet::addLayersControl(
baseGroups = c("Open Street Map", "Open Topo Map", "Esri World Imagery")
)
map
})
# Clicks on the map
observeEvent(input$basemap_click, {
click = input$basemap_click
# Check whether we're updating origin marker or destination marker
if(r$orig_dest_switch=="orig"){
r$origin$lat = click$lat
r$origin$lng = click$lng
# Add origin marker on the map (after removing previously added origin)
leaflet::leafletProxy('basemap')%>%
leaflet::clearGroup("origin") %>%
leaflet::addMarkers(lng=r$origin$lng, lat=r$origin$lat,
group="origin")
} else {
r$destination$lat = click$lat
r$destination$lng = click$lng
# Add destination marker on the map (after removing previously added destination)
leaflet::leafletProxy('basemap')%>%
leaflet::clearGroup("destination") %>%
leaflet::addMarkers(lng=r$destination$lng, lat=r$destination$lat,
group="destination")
}
})
})
}
mod_itinerary.R:
#' itinerary UI Function
#'
#' @description A shiny Module.
#'
#' @param id,input,output,session Internal parameters for {shiny}.
#'
#' @noRd
#'
#' @importFrom shiny NS tagList
mod_itinerary_ui <- function(id){
ns <- NS(id)
tagList(
absolutePanel(id="vehicleDetails", bottom=10, left=15, h4('Itinerary'),
h6("First select an origin on the map, then select a destination before plotting"),
style='background-color:white; opacity:0.8;padding: 0 20px 20px 20px',
radioButtons(
inputId=ns('orig_dest_switch'),
h5("Change origin or destination"),
choices = c("Origin" = 'orig', "Destination" = 'dest'),
inline = TRUE),
actionButton(inputId=ns("confirm_itin"), label="Plot itinerary")
)
)
}
#' itinerary Server Functions
#'
#' @noRd
mod_itinerary_server <- function(id, r, map_id, parent_session){
moduleServer( id, function(input, output, session){
ns <- session$ns
# Change origin/destination switch
observeEvent(input$orig_dest_switch, {
r$orig_dest_switch = input$orig_dest_switch
})
# Click on confirm button
observeEvent(input$confirm_itin, {
# Delete previous itineraries
leaflet::leafletProxy(mapId = map_id, session = parent_session) %>%
leaflet::clearGroup('itin')
# Show itinerary on map
leaflet::leafletProxy(mapId = map_id, session = parent_session) %>%
leaflet::addPolylines(lng=c(r$origin$lng, r$destination$lng),
lat=c(r$origin$lat, r$destination$lat),
group='itin')
})
})
}
shinyApp(app_ui, app_server)
我不知道为什么它会为你崩溃,我没有遇到这个问题。仍然,主要问题是在 app_server.R
中,您在调用行程模块时输入了 map_id="basemap"
。
在mod_basemap.R
中,地图确实叫做“basemap”,但是它被包裹在ns()
中,也就是说它的实际id是“调用模块时给的名字-” + “你给输入的ID”。因此,此处地图的实际 ID 为“basemap_ui_1-basemap”。
现在,指定整个 id 不是一个好主意(如果您以后用其他东西替换“basemap_ui_1”会怎么样?),所以您想要的是 return 地图 id当您调用 mod_basemap.R
时,以便您可以在其他模块中使用此 id。所以在mod_basemap.R
中server部分的末尾可以加上:
return(list(map_id = ns("basemap")))
所以你有:
mod_basemap_server <- function(id, r, session){
shiny::moduleServer( id, function(input, output, session){
ns <- session$ns
# ... Code you already have ...
return(list(map_id = ns("basemap")))
})
}
在app_server.R
中,您现在可以将模块mod_basemap
分配给一个对象(我称之为basemap
),然后在调用模块时使用basemap$map_id
mod_itinerary
:
basemap <- mod_basemap_server("basemap_ui_1", r, session)
mod_itinerary_server("itinerary_ui_1", r, map_id = basemap$map_id, parent_session = session)
我希望这是清楚的。您还可以查看 this RStudio article 关于在模块之间传递信息的信息。
最后一件事,你在 mod_itinerary.R
中打错了,你在应该 r$destination$lat
.
的地方写了 r$destination$lng
有了这个,点击地图上的两点,然后点击“绘制行程”应该会在这两点之间显示一条线。如果您仍然遇到一些意外崩溃,我猜这是您可能拥有的其他模块中的代码,因为这段代码对我来说工作正常。
我正在构建一个闪亮的应用程序,使用 Golem 作为框架。 在我的应用程序中,我制作了几个模块,所有模块都由 Leaflet 地图链接。 但是,我无法从创建地图的模块以外的其他模块更新地图。
我已尝试考虑 here 提出的建议,将 map_id
和 parent_session
包含到模块调用中,但每当我尝试将 map_id
和 parent_session
对地图的任何更改(没有错误跟踪)。
这是我的代码的精简版本,在单独的文件中:
app_server.R:
#' The application server-side
#'
#' @param input,output,session Internal parameters for {shiny}.
#' DO NOT REMOVE.
#' @import shiny
#' @import leaflet
#' @noRd
app_server <- function( input, output, session ) {
r <- reactiveValues(
map=NULL,
origin=list(lat=NULL, lng=NULL),
destination=list(lat=NULL, lng=NULL)
)
mod_basemap_server("basemap_ui_1", r, session)
mod_itinerary_server("itinerary_ui_1", r, map_id="basemap", parent_session=session)
}
app_ui.R:
#' The application User-Interface
#'
#' @param request Internal parameter for `{shiny}`.
#' DO NOT REMOVE.
#' @import shiny
#' @noRd
app_ui <- function(request) {
tagList(
bootstrapPage(
mod_basemap_ui("basemap_ui_1"),
mod_itinerary_ui("itinerary_ui_1")
)
)
}
mod_basemap.R:
#' basemap UI Function
#'
#' @description A shiny Module.
#'
#' @param id,input,output,session Internal parameters for {shiny}.
#'
#' @noRd
#'
#' @importFrom shiny NS tagList
mod_basemap_ui <- function(id){
ns <- NS(id)
tagList(
# Map background
leaflet::leafletOutput(ns("basemap"))
)
}
#' basemap Server Functions
#'
#' @noRd
mod_basemap_server <- function(id, r, session){
shiny::moduleServer( id, function(input, output, session){
ns <- session$ns
output$basemap <- leaflet::renderLeaflet({
# generate base leaflet
map = leaflet::leaflet(options = leaflet::leafletOptions(zoomControl = FALSE)) %>%
leaflet::addTiles(leaflet::providers$OpenStreetMap) %>%
leaflet::addProviderTiles(leaflet::providers$OpenStreetMap,
group="Open Street Map") %>%
leaflet::addProviderTiles(leaflet::providers$OpenTopoMap,
group="Open Topo Map") %>%
leaflet::addProviderTiles(leaflet::providers$Esri.WorldImagery,
group="Esri World Imagery") %>%
leaflet::fitBounds(2.78, 44.85, 3.41, 44.71) %>%
leaflet::addLayersControl(
baseGroups = c("Open Street Map", "Open Topo Map", "Esri World Imagery")
)
map
})
# Clicks on the map
observeEvent(input$basemap_click, {
click = input$basemap_click
# Check whether we're updating origin marker or destination marker
if(r$orig_dest_switch=="orig"){
r$origin$lat = click$lat
r$origin$lng = click$lng
# Add origin marker on the map (after removing previously added origin)
leaflet::leafletProxy('basemap')%>%
leaflet::clearGroup("origin") %>%
leaflet::addMarkers(lng=r$origin$lng, lat=r$origin$lat,
group="origin")
} else {
r$destination$lat = click$lat
r$destination$lng = click$lng
# Add destination marker on the map (after removing previously added destination)
leaflet::leafletProxy('basemap')%>%
leaflet::clearGroup("destination") %>%
leaflet::addMarkers(lng=r$destination$lng, lat=r$destination$lat,
group="destination")
}
})
})
}
mod_itinerary.R:
#' itinerary UI Function
#'
#' @description A shiny Module.
#'
#' @param id,input,output,session Internal parameters for {shiny}.
#'
#' @noRd
#'
#' @importFrom shiny NS tagList
mod_itinerary_ui <- function(id){
ns <- NS(id)
tagList(
absolutePanel(id="vehicleDetails", bottom=10, left=15, h4('Itinerary'),
h6("First select an origin on the map, then select a destination before plotting"),
style='background-color:white; opacity:0.8;padding: 0 20px 20px 20px',
radioButtons(
inputId=ns('orig_dest_switch'),
h5("Change origin or destination"),
choices = c("Origin" = 'orig', "Destination" = 'dest'),
inline = TRUE),
actionButton(inputId=ns("confirm_itin"), label="Plot itinerary")
)
)
}
#' itinerary Server Functions
#'
#' @noRd
mod_itinerary_server <- function(id, r, map_id, parent_session){
moduleServer( id, function(input, output, session){
ns <- session$ns
# Change origin/destination switch
observeEvent(input$orig_dest_switch, {
r$orig_dest_switch = input$orig_dest_switch
})
# Click on confirm button
observeEvent(input$confirm_itin, {
# Delete previous itineraries
leaflet::leafletProxy(mapId = map_id, session = parent_session) %>%
leaflet::clearGroup('itin')
# Show itinerary on map
leaflet::leafletProxy(mapId = map_id, session = parent_session) %>%
leaflet::addPolylines(lng=c(r$origin$lng, r$destination$lng),
lat=c(r$origin$lat, r$destination$lat),
group='itin')
})
})
}
shinyApp(app_ui, app_server)
我不知道为什么它会为你崩溃,我没有遇到这个问题。仍然,主要问题是在 app_server.R
中,您在调用行程模块时输入了 map_id="basemap"
。
在mod_basemap.R
中,地图确实叫做“basemap”,但是它被包裹在ns()
中,也就是说它的实际id是“调用模块时给的名字-” + “你给输入的ID”。因此,此处地图的实际 ID 为“basemap_ui_1-basemap”。
现在,指定整个 id 不是一个好主意(如果您以后用其他东西替换“basemap_ui_1”会怎么样?),所以您想要的是 return 地图 id当您调用 mod_basemap.R
时,以便您可以在其他模块中使用此 id。所以在mod_basemap.R
中server部分的末尾可以加上:
return(list(map_id = ns("basemap")))
所以你有:
mod_basemap_server <- function(id, r, session){
shiny::moduleServer( id, function(input, output, session){
ns <- session$ns
# ... Code you already have ...
return(list(map_id = ns("basemap")))
})
}
在app_server.R
中,您现在可以将模块mod_basemap
分配给一个对象(我称之为basemap
),然后在调用模块时使用basemap$map_id
mod_itinerary
:
basemap <- mod_basemap_server("basemap_ui_1", r, session)
mod_itinerary_server("itinerary_ui_1", r, map_id = basemap$map_id, parent_session = session)
我希望这是清楚的。您还可以查看 this RStudio article 关于在模块之间传递信息的信息。
最后一件事,你在 mod_itinerary.R
中打错了,你在应该 r$destination$lat
.
r$destination$lng
有了这个,点击地图上的两点,然后点击“绘制行程”应该会在这两点之间显示一条线。如果您仍然遇到一些意外崩溃,我猜这是您可能拥有的其他模块中的代码,因为这段代码对我来说工作正常。