Mette Laegdsmand
Mette Laegdsmand

Reputation: 41

Saving leaflet maps in R shiny

I have created an app where the user can modify a leaflet map and i would like to use this map in a pdf report. I have 1. installed packages leaflet, webshot and htmlwidget 2. installed PhantomJS

below is a simplified version of the code

server.R:

    library(shiny)
    library(leaflet)
    library(htmlwidgets)
    library(webshot)

    shinyServer(function(input, output, session) {

      output$amap <- renderLeaflet({
      leaflet() %>%
        addProviderTiles("Stamen.Toner",
                     options = providerTileOptions(noWrap = TRUE,      reuseTiles=TRUE))
  })

  observe({
    leafletProxy("amap") %>%
    clearShapes() %>%
    addCircles(lng = c(22,-2), lat = c(42,65))
  })



  observeEvent(input$saveButton,{
    themap<- leafletProxy("amap")
    saveWidget(themap, file="temp.html", selfcontained = F) 
    webshot("temp.html", file = "Rplot.png",
          cliprect = "viewport")

  })
})

ui.R:

fluidPage(
  leafletOutput("amap", height="600px", width="600px"),
  br(),
  actionButton("saveButton", "Save")
  )

I get this error message:

Warning: Error in system.file: 'package' must be of length 1 Stack trace (innermost first): 73: system.file 72: readLines 71: paste 70: yaml.load 69: yaml::yaml.load_file 68: getDependency 67: widget_dependencies 66: htmltools::attachDependencies 65: toHTML 64: saveWidget 63: observeEventHandler [C:\R files\test/server.R#24] 1: shiny::runApp

when the save button is activated. savewidget works fine when i define the save button like this:

  observeEvent(input$saveButton,{
    themap<-leaflet() %>%
      addProviderTiles("Stamen.Toner",
                       options = providerTileOptions(noWrap = TRUE, reuseTiles=TRUE))

    saveWidget(themap, file="temp.html", selfcontained = F) 
    webshot("temp.html", file = "Rplot.png",
          cliprect = "viewport")

  })

But i really want the changes that the user makes in the webshot. Can anyone help?

Upvotes: 4

Views: 1791

Answers (1)

timelyportfolio
timelyportfolio

Reputation: 6579

This is not perfect, but here a solution using the library html2canvas. Please be careful of attribution, license, and copyright. Also, this won't work in RStudio Viewer, but there are ways to get it to work.

library(leaflet)
library(htmltools)

lf <- leaflet() %>%
  addProviderTiles(
    "Stamen.Toner",
    options = providerTileOptions(
      noWrap = TRUE,
      reuseTiles=TRUE
    )
  )


#  add the mapbox leaflet-image library
#   https://github.com/mapbox/leaflet-image
#lf$dependencies[[length(lf$dependencies)+1]] <- htmlDependency(
#  name = "leaflet-image",
#  version = "0.0.4",
#  src = c(href = "http://api.tiles.mapbox.com/mapbox.js/plugins/leaflet-image/v0.0.4/"),
#  script = "leaflet-image.js"
#)

lf$dependencies[[length(lf$dependencies)+1]] <- htmlDependency(
  name = "html2canvas",
  version = "0.5.0",
  src = c(href="https://cdn.rawgit.com/niklasvh/html2canvas/master/dist/"),
  script = "html2canvas.min.js"
)



browsable(
  tagList(
    tags$button("snapshot",id="snap"),
    lf,
    tags$script(
'
document.getElementById("snap").addEventListener("click", function() {
  var lf = document.querySelectorAll(".leaflet");
  html2canvas(lf, {
    useCORS: true,
    onrendered: function(canvas) {
      var url = canvas.toDataURL("image/png");
      var downloadLink = document.createElement("a");
      downloadLink.href = url;
      downloadLink.download = "map.png"

      document.body.appendChild(downloadLink);
      downloadLink.click();
      document.body.removeChild(downloadLink); 
    }
  });
});
'      
    )
  )
)

Upvotes: 5

Related Questions