I am trying to add an easyButton
with a flyTo
function within a shiny
app.
When the user presses the button, it will fly to the current location (lat/long). I am using a reactivePoll
to poll a boat instrument simulator every 5 seconds (NMEA simulator), which is where the lat/long come from. A path is also drawn by using addCircleMarkers
. I want to keep this path drawn, and the flyTo
button to pan and zoom to the current location without refreshing the map, i.e. removing the path that was drawn.
In my current code with the flyTo
button, with every poll the map refreshes. If I remove this code, the map does not refresh, so I think how I'm using the reactive within this button is the issue, but I'm not sure why. It may be because I have a reactive inside a reactive (All_NMEA()
inside of renderleaflet()
). I tried moving it into an observe
at the bottom, but it does not show up on the map. The code of interest in the reprex is:
addEasyButton(easyButton(
icon = "fa-crosshairs", title = "Locate Vessel",
onClick = JS("
function(btn, map) {
map.flyTo([", paste(as.numeric(All_NMEA()["lat"]) / 100), ",", paste(as.numeric(All_NMEA()["long"]) / -100), "], zoom = 10);
}
")
))
The NMEA simulator is required to produce data that is polled, linked above.
Reproducible example:
# https://chrome.google.com/webstore/detail/nmea-simulator/dfhcgoinjchfcfnnkecjpjcnknlipcll?hl=en
# needs an NMEA simulator to generate the poll data
#
library(shiny)
library(leaflet)
connect <- function() {
s_con <<- socketConnection("127.0.0.1", port = 55555, open = "a+")
Sys.sleep(1)
NMEA_poll <<- readLines(s_con, n = 18)
close(s_con)
return(NMEA_poll)
}
pollGPRMC <- function(data) {
gps_ans <- list(rmc = NULL, rest = data)
rxp <-
"\\$GPRMC(,[^,]*){12}\\*[0-9,A-F]{2}"
beg <- regexpr(rxp, data)
if (beg == -1)
return(gps_ans)
end <-
beg + attr(beg, "match.length")
sub <-
substr(data, beg, end - 6)
gps_ans$rmc <-
strsplit(sub, ",")[[1]]
names(gps_ans$rmc) <- c(
"id_rmc",
"UTC",
"status",
"lat",
"N/S",
"long",
"E/W",
"boat speed (knots)",
"cog (deg)",
"date (ddmmyy)" # ddmmyy
)
gps_ans$rest <- substr(data, end, nchar(data))
return(gps_ans)
}
map_data <- data.frame(lat = c(36.05, 36.25), lon = c(-132.13, -132.33))
ui <- fluidPage(
# Application title
titlePanel("Map"),
mainPanel(tags$style(type = "text/css", "#map {height: calc(100vh - 80px) !important;}"),
leafletOutput("map"))
)
server <- function(input, output, session) {
All_NMEA <- shiny::reactivePoll(
5000,
session,
checkFunc = Sys.time,
valueFunc = function() {
connect()
NMEA_data <- toString(NMEA_poll)
GPS_dat <- pollGPRMC(NMEA_data)
lat_deg <- substr(GPS_dat$rmc["lat"], 1, 2)
lat_mins <- substr(GPS_dat$rmc["lat"], 3, 9)
lat_for_dist <- as.numeric(lat_deg) + (as.numeric(lat_mins) / 60)
print(lat_for_dist)
lon_deg <- substr(GPS_dat$rmc["long"], 1, 3)
lon_mins <- substr(GPS_dat$rmc["long"], 4, 9)
lon_for_dist <- (as.numeric(lon_deg) + (as.numeric(lon_mins) / 60))*-1
print(lon_for_dist)
NMEA_out <- c(GPS_dat$rmc)
return(NMEA_out)
}
)
ord <- function(data) {
print(data)
}
observe(ord(All_NMEA()))
my_map <- leafletProxy("map", session = session)
output$map <- renderLeaflet({
map <- leaflet(map_data) %>%
addProviderTiles(providers$Esri.OceanBasemap, group = "ocean basemap (default)") %>%
addTiles(group = "Basic") %>%
fitBounds( ~ min(lon), ~ min(lat), ~ max(lon), ~ max(lat)) %>%
addLayersControl(
baseGroups = c("ocean basemap (default)", "Basic"),
options = layersControlOptions(collapsed = FALSE)) %>%
fitBounds( ~ min(lon), ~ min(lat), ~ max(lon), ~ max(lat)) %>%
addEasyButton(easyButton(
icon = "fa-crosshairs", title = "Locate Vessel",
onClick = JS("
function(btn, map) {
map.flyTo([", paste(as.numeric(All_NMEA()["lat"]) / 100), ",", paste(as.numeric(All_NMEA()["long"]) / -100), "], zoom = 10);
}
")
))
})
observe({
map_loc <- All_NMEA()
my_map %>%
addCircleMarkers(
lng = as.numeric(map_loc["long"]) / -100,
lat = as.numeric(map_loc["lat"]) / 100,
radius = 1,
fillOpacity = 1, color = "red"
) #%>%
# addEasyButton(easyButton(
# icon = "fa-crosshairs", title = "Locate Vessel",
# onClick = JS("
# function(btn, map) {
# map.flyTo([", as.numeric(map_loc["lat"]) / 100, ",", as.numeric(map_loc["long"]) / -100, "], zoom = 10);
# }
# ")
# ))
})
}
shinyApp(ui = ui, server = server)