Closed cywhale closed 6 years ago
I write a small app.R to test my problems for input$map_bounds and input$map_marker_click (leaflet under editMod), and compare the results just in shiny+leaflet. Append my sessionInfo() in the end.
library(shiny)
library(sf)
library(leaflet)
library(mapview)
library(mapedit)
library(magrittr)
ui <- fluidPage(
fluidRow(
column(4,
fluidRow(
uiOutput("control_ui")
),
fluidRow(
textOutput("outText")
)
),
column(7,
fluidRow(
uiOutput("emod_ui")
),
fluidRow(
uiOutput("leaflet_ui")
)
)
)
)
server <- function(input, output) {
ns <- shiny::NS("eview")
lf0 <- reactive ({ leaflet(breweries91) %>%
addProviderTiles("Esri.WorldTopoMap",options = providerTileOptions(maxZoom=13,minZoom=0,continuousWorld=FALSE,noWrap=TRUE)) %>%
setView(10.5, 49.5, zoom=8) %>%
addCircleMarkers(weight = 1, layerId = 1:nrow(breweries91),
popup = breweries91@data$brewery)
})
output$control_ui <- renderUI({
selectizeInput(inputId="basemapsel", label= "Basemap:",
choices=list("Esri Topo"= 1, "Esri Ocean"=2), multiple=FALSE,
selected = 1, options = list(allowEmptyOption=FALSE)
)
})
output$emod_ui <- renderUI({
editModUI("eview", width="100%", height="400px")
})
output$leaflet_ui <- renderUI({
leafletOutput("lview", width="100%", height="400px")
})
lfx<- isolate({lf0()})
editmapx <- callModule(editMod, "eview", lfx)
observe({ editmapx() })
observeEvent(input$basemapsel, {
lf <- leafletProxy(ns("map"))
if (input$basemapsel == 1) {
lf %>% addProviderTiles("Esri.WorldTopoMap",options = providerTileOptions(maxZoom=13,minZoom=0,continuousWorld=FALSE,noWrap=TRUE))
} else {
lf %>% addProviderTiles("Esri.OceanBasemap",options = providerTileOptions(maxZoom=13,minZoom=0,continuousWorld=FALSE,noWrap=TRUE))
}
})
output$lview <- renderLeaflet({
lfx
})
######## Detect event from leaflet under editMod: Marker click
em_idx <- eventReactive(input$map_marker_click, {
cevent <- input$map_marker_click
if (is.null(cevent)) {
return("click_by_emod_NONE")
}
paste0("click_by_emod: ",as.character(cevent$id))
})
#### Map bounds
em_boundx <- eventReactive(input$map_bounds, {
if (is.null(input$map_bounds)) {
return("bounds_by_emod_NONE")
}
paste0("bounds_by_emod: ",paste(input$map_bounds, collapse = ","))
})
######## Detect event from only leaflet
lf_idx <- eventReactive (input$lview_marker_click, {
cevent <- input$lview_marker_click
if (is.null(cevent)) {
return("click_by_lf_NONE")
}
paste0("click_by_lf: ",as.character(cevent$id))
})
lf_boundx <- eventReactive(input$lview_bounds, {
if (is.null(input$lview_bounds)) {
return("bounds_by_lf_NONE")
}
paste0("bounds_by_lf: ",paste(input$lview_bounds, collapse = ","))
})
#### Output Result, click the markers on leaflet
output$outText <- renderText({
paste(#"From emMod: ", em_idx(), em_boundx(), #### Comment the two text outputs because it cannot work and make renderText failed.
"From LF: ", lf_idx(), lf_boundx(), sep=";\n")## Only the two text outputs from leaflet "lview" works!
})
}
shinyApp(ui = ui, server = server)
sessionInfo()
R version 3.4.1 (2017-06-30)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 16.04.3 LTS
Matrix products: default
BLAS/LAPACK: /opt/openblas/lib/libopenblasp-r0.2.20.dev.so
locale:
[1] LC_CTYPE=zh_TW.UTF-8 LC_NUMERIC=C LC_TIME=lzh_TW
[4] LC_COLLATE=zh_TW.UTF-8 LC_MONETARY=lzh_TW LC_MESSAGES=zh_TW.UTF-8
[7] LC_PAPER=lzh_TW LC_NAME=C LC_ADDRESS=C
[10] LC_TELEPHONE=C LC_MEASUREMENT=lzh_TW LC_IDENTIFICATION=C
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] magrittr_1.5 mapedit_0.3.2 mapview_2.3.0 leaflet_1.1.0 sf_0.6-0
[6] shiny_1.0.5
loaded via a namespace (and not attached):
[1] Rcpp_0.12.15 plyr_1.8.4 pillar_1.1.0 compiler_3.4.1
[5] R.methodsS3_1.7.1 base64enc_0.1-3 R.utils_2.6.0 class_7.3-14
[9] iterators_1.0.9 tools_3.4.1 gdalUtils_2.0.1.7 digest_0.6.15
[13] jsonlite_1.5 viridisLite_0.3.0 satellite_1.0.1 lattice_0.20-35
[17] png_0.1-7 rlang_0.1.6 foreach_1.4.4 DBI_0.7
[21] crosstalk_1.0.0 yaml_2.1.16 rgdal_1.2-16 e1071_1.6-8
[25] raster_2.6-7 htmlwidgets_1.0 webshot_0.5.0 classInt_0.1-24
[29] stats4_3.4.1 grid_3.4.1 R6_2.2.2 sp_1.2-7
[33] udunits2_0.13 leaflet.extras_0.2 scales_0.5.0 codetools_0.2-15
[37] htmltools_0.3.6 units_0.5-1 rsconnect_0.8.5 colorspace_1.3-2
[41] mime_0.5 xtable_1.8-2 httpuv_1.3.5 munsell_0.4.3
[45] R.oo_1.21.0
@cywhale I think I understand the objective. I'll try to post a demo tonight. Thanks for using mapedit
.
@cywhale, I simplified your example a bit to focus on the Shiny module event. Please let me know if my simplification lost important aspects of your question.
Shiny Modules pass messages back and forth between JS and R just like regular old Shiny, but the messages are namespaced. In your example, input$map_bounds
would become input[["eview-map_bounds]]
or using the ns()
function input[[ns("map_bounds")]]
. options(shiny.trace=TRUE)
can be very helpful here.
library(shiny)
library(sf)
library(leaflet)
library(mapview)
library(mapedit)
library(magrittr)
ui <- fluidPage(
fluidRow(
column(7,
editModUI("eview", width="100%", height="400px")
),
column(5,
verbatimTextOutput("textbounds")
)
)
)
server <- function(input, output) {
ns <- shiny::NS("eview")
lf0 <- leaflet(breweries91) %>%
addProviderTiles("Esri.WorldTopoMap",options = providerTileOptions(maxZoom=13,minZoom=0,continuousWorld=FALSE,noWrap=TRUE)) %>%
setView(10.5, 49.5, zoom=8) %>%
addCircleMarkers(weight = 1, layerId = 1:nrow(breweries91),
popup = breweries91@data$brewery)
editmapx <- callModule(editMod, "eview", lf0)
# events within module will be namespaced
# so we will need to wrap them in our ns() function
# show bounds in textOutput
output$textbounds <- renderPrint({
str(input[[ns("map_bounds")]])
})
# print structure in console to demonstrate
observeEvent(
input[[ns("map_bounds")]],
{
str(input[[ns("map_bounds")]])
}
)
}
shinyApp(ui = ui, server = server)
@timelyportfolio Your response is exactly what I needed. I know I misuse the id, but was not aware of the alternative way by using input[[ns(..)]]. Thanks for the timely help, also the trick options(shiny.trace=TRUE). I appreciate the progress in mapview/mapedit, and try to integrate it with my rshiny work.
@cywhale, fantastic, glad it was helpful. I think Shiny modules are unfortunately under-documented. Please let me know how I can help as you progress with mapedit
. Feedback will be critical for the success of the project. Also, look forward to another round of features soon once the newest leaflet
is complete.
@timelyportfolio Sure. I will feedback my rshiny work after integrating with mapedit. I have designed an API that can query some biodiversity information through polygonal regions. So now I just try to extract the polygons that users draw on leaflet by using mapedit, and then feed the polygons into the API. I'll keep watching the new features of leaflet/mapedit. Thanks!
It may be a simple question, but I cannot make it work as I call edit module: server <- function(input, output) {
ns <- shiny::NS("eview") emapx <- callModule(editMod, "eview", leaflet(...)) ... } The leaflet map correctly show, and leafletProxy(ns("map")) also works, including the popup when clicking marker. But I cannot use input$map_bounds or input$map_marker_click to detect map bounds and to get triggered by marker click through the leaflet id "map". The original usage under only shiny+leaflet is ok. Do I misuse the id of leaflet (in edit module of mapedit) for input$'MAPID'_bounds (and _marker_click)? Is there any suggestion to do so? Thanks.