theBean
theBean

Reputation: 133

How to sync maps in R shiny

I want to sync two maps in an R shiny web app(zooming in on one map should zoom in on the other map and panning etc), I managed to do this interactively using the code shown below but I can't figure out how to do this in a Shiny web app.

my_map <- function(x){
    m <- leaflet() %>%
    addTiles() %>%  # Add default OpenStreetMap map tiles
    addMarkers(lng=x[1], lat=x[2], popup="The birthplace of R")
    m
}

y <- c(174.968, 37.852)
x <- c(0.112281, 51.523001)

sync(my_map(x), my_map(y), no.initial.sync = TRUE)

Upvotes: 3

Views: 1709

Answers (2)

Cris Silva
Cris Silva

Reputation: 121

Using sync() as an UI output, not as leafletOutput worked for me.

In ui:

uiOutput("synced_maps")

In server:

output$synced_maps <- renderUI({
   m1 <- leaflet() %>% addTiles() %>% addMarkers(~lon1, ~lat1)
   m2 <- leaflet() %>% addTiles() %>% addMarkers(~lon2, ~lat2)
   sync(m1, m2)      
})

Upvotes: 6

Ben
Ben

Reputation: 30474

Will the maps always be made prior to user interface creation? If so:

library(leaflet)
library(leafsync)
library(shiny)

my_map <- function(x){
  m <- leaflet() %>%
    addTiles() %>%  # Add default OpenStreetMap map tiles
    addMarkers(lng=x[1], lat=x[2], popup="The birthplace of R")
  m
}

y <- c(174.968, 37.852)
x <- c(0.112281, 51.523001)

ui <- sync(my_map(x), my_map(y), no.initial.sync = TRUE)

server = function(input,output){
}

shinyApp(ui, server)

Edit:

In response to your comment, I have looked at options to sync maps including a javascript approach (https://github.com/jieter/Leaflet.Sync) and syncWith (https://github.com/rte-antares-rpackage/leaflet.minicharts). I have not spent time with these.

A quick workaround could be this below (one map's bounds matches the other map's bounds, but not vice versa). It requires adding observe to the server function and setting the bounds from one map to the other. From http://rstudio.github.io/leaflet/shiny.html:

input$MAPID_bounds provides the latitude/longitude bounds of the currently visible map area; the value is a list() that has named elements north, east, south, and west

library(leaflet)
library(leafsync)
library(shiny)

my_map <- function(x){
  m <- leaflet() %>%
    addTiles() %>%  # Add default OpenStreetMap map tiles
    addMarkers(lng=x[1], lat=x[2], popup="The birthplace of R")
  m
}

y <- c(174.968, 37.852)
x <- c(0.112281, 51.523001)

ui <- fluidPage(
  leafletOutput("mymap1"),
  leafletOutput("mymap2")
)

server = function(input, output){

  output$mymap1 = renderLeaflet({
    my_map(x)
  })
  output$mymap2 = renderLeaflet({
    my_map(y)
  })

  observe({
    coords <- input$mymap1_bounds
    if (!is.null(coords)) {
      leafletProxy("mymap2") %>% 
        fitBounds(coords$west,
                  coords$south,
                  coords$east,
                  coords$north)
    }
  })
}

shinyApp(ui, server)

Upvotes: 2

Related Questions