Synchronizing two leaflet maps in R / Rmarkdown

北城以北 提交于 2019-12-05 02:11:27

问题


JS leaflet allows two maps to be synchronized. See an example of synchronized leaflet maps here.

I would like to implement synchronized leaflet maps in R and more specifially in Rmarkdown/knitr.

Preferably, the maps should shown next to each other horizontally (just like in the example).

Here is a minimal Rmarkdown (.Rmd) example of two maps I would like to sync. The solution does not have to be based on the the mapview package. Any solution is welcome really (-:

---
title: "How to sync 2 leaflet maps"
author: "me"
date: "2 April 2016"
output: html_document
---

```{r SETUP, include=FALSE}
library("mapview")
library("sp")

# load example data
data(meuse)
coordinates(meuse) <- ~x+y
proj4string(meuse) <- CRS("+init=epsg:28992")
```

```{r MAPS}
mapView(meuse, zcol="copper")@map # MAP 1
mapview(meuse, zcol="soil")@map # MAP 2
```

回答1:


Note, we have implemented the answer provided by @timelyportfolio in package mapview so that this is now easily achievable using mapview::sync(). See ?mapview::sync for instructions and examples.




回答2:


Here is a way to sync the two leaflet maps, but unfortunately it does not work in RStudio Viewer. This does work in Chrome and Firefox. There are lots of ways to make this much more robust. I tried to add comments in the R code below to explain what is happening.

---
title: "How to sync 2 leaflet maps"
author: "me"
date: "2 April 2016"
output: html_document
---

```{r SETUP, include=FALSE}
#  get the latest htmlwidgets
#   devtools::install_github("ramnathv/htmlwidgets")
library("htmlwidgets")
library("htmltools")
library("mapview")
library("sp")

# load example data
data(meuse)
coordinates(meuse) <- ~x+y
proj4string(meuse) <- CRS("+init=epsg:28992")
```

```{r MAPS}
mapView(meuse, zcol="copper")@map # MAP 1
mapview(meuse, zcol="soil")@map # MAP 2
```

```{r}
#  crudely add the leaflet-sync plugin
#   attachDependency with the rawgit gave me
#   errors so just do this for now
#   could easily add to a package
#   or make a mini package to import this
#   dependency
tags$script(
  type="text/javascript",
  src="https://cdn.rawgit.com/turban/Leaflet.Sync/master/L.Map.Sync.js"
)
```

```{r}
# this is one of the new htmlwidgets methods
#  to add some code after all htmlwidgets are rendered
#  this is very useful since we need all htmlwidgets rendered
#  before we can sync
onStaticRenderComplete(
'
var leaf_widgets = Array.prototype.map.call(
  document.querySelectorAll(".leaflet"),
  function(ldiv){
    return HTMLWidgets.find("#" + ldiv.id);
  }
);

// make this easy since we know only two maps
leaf_widgets[0].sync(leaf_widgets[1]);
leaf_widgets[1].sync(leaf_widgets[0]);
'
)
```

Here is how we can do the same thing in straight R code.

#  http://stackoverflow.com/questions/36373842/synchronizing-two-leaflet-maps-in-r-rmarkdown

#  get the latest htmlwidgets
#   devtools::install_github("ramnathv/htmlwidgets")
library("htmlwidgets")
library("htmltools")
library("mapview")
library("sp")

# load example data
data(meuse)
coordinates(meuse) <- ~x+y
proj4string(meuse) <- CRS("+init=epsg:28992")
map1 <- mapView(meuse, zcol="copper")@map # MAP 1
map2 <- mapview(meuse, zcol="soil")@map # MAP 2

tagList(
  tags$head(tags$script(
    type="text/javascript",
    src="https://cdn.rawgit.com/turban/Leaflet.Sync/master/L.Map.Sync.js"
  )),
  map1,
  map2,
  onStaticRenderComplete(
'
var leaf_widgets = Array.prototype.map.call(
  document.querySelectorAll(".leaflet"),
  function(ldiv){
    return HTMLWidgets.find("#" + ldiv.id);
  }
);

// make this easy since we know only two maps
leaf_widgets[0].sync(leaf_widgets[1]);
leaf_widgets[1].sync(leaf_widgets[0]);
'
  )
) %>%
  browsable

And if you want it side-by-side, here is the basic way to accomplish. We could leverage shiny::fluidPage, fluidRow, and column to get boostrap, but the css/js is really heavy for just side-by-side placement.

#  get the latest htmlwidgets
#   devtools::install_github("ramnathv/htmlwidgets")
library("htmlwidgets")
library("htmltools")
library("shiny")
library("mapview")
library("sp")

# load example data
data(meuse)
coordinates(meuse) <- ~x+y
proj4string(meuse) <- CRS("+init=epsg:28992")
map1 <- mapView(meuse, zcol="copper")@map # MAP 1
map2 <- mapview(meuse, zcol="soil")@map # MAP 2

tagList(
  tags$head(tags$script(
    type="text/javascript",
    src="https://cdn.rawgit.com/turban/Leaflet.Sync/master/L.Map.Sync.js"
  )),
  tags$div(style="display:inline;width:50%;float:left;",map1),
  tags$div(style="display:inline;width:50%;float:left;",map2),
  onStaticRenderComplete(
'
var leaf_widgets = Array.prototype.map.call(
  document.querySelectorAll(".leaflet"),
  function(ldiv){
    return HTMLWidgets.find("#" + ldiv.id);
  }
);

// make this easy since we know only two maps
leaf_widgets[0].sync(leaf_widgets[1]);
leaf_widgets[1].sync(leaf_widgets[0]);
'
  )
) %>%
  browsable


来源:https://stackoverflow.com/questions/36373842/synchronizing-two-leaflet-maps-in-r-rmarkdown

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!