4

Running into issues syncing two leaflet maps on different tabs.

After looking at previous entries (Synchronizing two leaflet maps in R / Rmarkdown), the solution provided by @TimSalabim does not work because the maps are on different tabs.

Here is a MWE RMarkdown example:

---
title: "QuestionforStackOverflow"
output: 
flexdashboard::flex_dashboard:
runtime: shiny
---

```{r setup, include=FALSE}
library(flexdashboard)
library(shiny)
library(leaflet)
```

Tab One
======================================================================
```{r tab1}
output$map1 <-
   renderLeaflet(
    leaflet() %>%
      addProviderTiles("CartoDB.Positron") %>%
      setView(-93.65, 42.0285, zoom = 4)
  )

leafletOutput("map1")

```
Tab Two
======================================================================
```{r tab2}

output$map2 <-
  renderLeaflet(
    leaflet() %>%
      addProviderTiles("CartoDB.Positron") %>%
      setView(-93.65, 42.0285, zoom = 4)
  )

leafletOutput("map2")
```

I want a two way change. Any view changes to map1 -- changes map2 OR any changes to map2 will change map1.

Ideally: if you scroll into St. Louis on map1, map2 will have the same zoom level on St. Louis.

Right now, there is no interactivity between the two maps. Is there a way to make them sync?

Community
  • 1
  • 1
jpf5046
  • 729
  • 7
  • 32

2 Answers2

3

You can use the leafletProxy() for this : See the help here : https://rstudio.github.io/leaflet/shiny.html

For your particular problem, here's an idea :

---
  title: "QuestionforStackOverflow"
  output: 
    flexdashboard::flex_dashboard:
  runtime: shiny
---

```{r setup, include=FALSE}
  library(flexdashboard)
  library(shiny)
  library(leaflet)
```

Tab One
======================================================================

```{r tab1}
output$map1 <-
  renderLeaflet(
    leaflet() %>%
      addProviderTiles("CartoDB.Positron") %>%
      setView(-93.65, 42.0285, zoom = 4)
  )

actionButton("syncMap1", "Fit to map2 bounds")
leafletOutput("map1")

observeEvent(input$syncMap1,{
  map2coords <- input$map2_bounds
  map1Proxy <- leafletProxy("map1")
  map1Proxy %>% fitBounds(lng1 = map2coords$east,
                          lat1 = map2coords$north,
                          lng2 = map2coords$west,
                          lat2 = map2coords$south)
})
```

Tab Two
======================================================================

```{r tab2}

output$map2 <-
  renderLeaflet(
    leaflet() %>%
      addProviderTiles("CartoDB.Positron") %>%
      setView(-93.65, 42.0285, zoom = 4)
  )
actionButton("syncMap2", "Fit to map1 bounds")
leafletOutput("map2")

observeEvent(input$syncMap2,{
  map1coords <- input$map1_bounds
  map2Proxy <- leafletProxy("map2")
  map2Proxy %>% fitBounds(lng1 = map1coords$east,
                          lat1 = map1coords$north,
                          lng2 = map1coords$west,
                          lat2 = map1coords$south)
})
```

The idea is to retrieve the coordinates of the other map when clicking on the buttons, and to sync the view then.

Minor problem : the view is not that well synced : could be better to find the centroid of the displayed map and to use setView() using input$map1_zoom.

Major problem : this means using buttons, what is not that user-friendly. Theoritically, you could use an observe() block to reflect the coordinates of each map to the other. Tried it and it's quite buggy, probably because of some "infinite" loop as there are micro-variations in the coordinates.

RobinCura
  • 410
  • 2
  • 8
  • For automatic syncing, you could use @Jieter idea of tab change detection. But as far as I tried, it's not possible with flexdashboard: You can't give an id to the tab container, and thus, you can't have an input change each time another tab is selected. Using shiny, this would be much more easy. – RobinCura Jul 01 '16 at 14:57
  • Neat work around. Is it possible to make an event for when the user switches tabs? That might solve the infinite loop problem. After looking quickly, it seems possible in js, but maybe not in R. – jpf5046 Jul 01 '16 at 22:18
0

No idea how that would work with R, but with plain JavaScript you could use Leaflet.Sync to synchronize two maps.

If you have two tabs of which only one is visible at the time, you could also just sync on tab switch, which is much simpler to implement.

Jieter
  • 4,101
  • 1
  • 19
  • 31
  • (http://stackoverflow.com/questions/23599268/include-a-javascript-file-in-shiny-app) I will try and follow this documentation. Add for the JS code... – jpf5046 Jun 28 '16 at 21:50
  • *As for the JS code, not sure where to edit into RMarkdown. – jpf5046 Jun 28 '16 at 21:59