Is there a way to use Esri World Imagery tiles offline in leaflet map in shiny?
Asked Answered
H

1

0

I've managed to get OSM tiles downloaded using:

for (zoom in 8:9)
GetMapTiles(lonR = xlim, latR = ylim, zoom = zoom, nTiles = round(c(20,20)/(17-zoom)),
        verbose = 1, type = "osm", tileDir = "mapTiles/OSM/", CheckExistingFiles = TRUE)

And I can get them to display in shiny using:

# Start serving working folder on port 8000 in demon mode
deamon_id <- servr::httd(dir = "mapTiles", port = 8000, daemon = TRUE)

# Plot with leaflet

#shiny ui 
ui = fluidPage(leafletOutput("map"))

#create basic map, load tiles from directory and set view to centre of downloaded tiles
server = function(input, output, server){
  
  addResourcePath("mytiles", "mapTiles")
  
  # m = leaflet() %>% 
  #   addTiles( urlTemplate = "http:/localhost:8000/C:/GitHub/culturalmapper/mapTiles/OSM/{z}_{x}_{y}.png")
  output$map = renderLeaflet({
    leaflet() %>%
      addTiles(urlTemplate = "/mytiles/OSM/{z}_{x}_{y}.png") %>%
      setView(115.6, -31.63, zoom = 8)
  })
}

But I would also like to download ESRI worldimagery tiles to display offline. (Like adding this to a leaflet map):

   addProviderTiles('Esri.WorldImagery')

This is the only example I can find of someone downloading ESRI tiles to use offline. But he doesn't show the code downloading the tiles, only displaying them.

This is the link to the map server I would like to use

Harmonize answered 20/4, 2022 at 2:36 Comment(0)
I
0

I haven't done this in a while, but I found my old code, edited it slightly and it still seems to work. It requires the RgoogleMaps package as well as jpeg and png.

Essentially, I took the code from RgoogleMaps::GetMapTiles and just modified it some to work with https://services.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer. Like I said, I did this a while ago so the code in RgoogleMaps::GetMapTiles now, might be slightly different. But, if you have questions about the function arguments, that's where you should look (?RgoogleMaps::GetMapTiles).

Here is the code for the function (make sure you have the three required packages).

library(RgoogleMaps)

getmaptiles <- function (center = c(lat = 52.431635, lon = 13.194773),
  lonR, latR,
  nTiles = c(3, 3), zoom = 13,
  urlBase = "http://services.arcgisonline.com/arcgis/rest/services/World_Topo_Map/MapServer",
  CheckExistingFiles = TRUE, 
  TotalSleep = NULL, tileExt = ".png",
  tileDir= "~/mapTiles/WorldTopoMap/", 
  returnTiles = FALSE, verbose = 1) 
{ 
    require(png)
    require(jpeg)
    if (is.character(center)) {
        if (verbose) 
            cat("geocoding ", center, "\n")
        center = getGeoCode(center, verbose)
        if (verbose) 
            cat("result:", center, "\n")
    }
    if (all(c("lat", "lon") %in% names(center))) 
        center = center[c("lat", "lon")]
    else names(center) = c("lat", "lon")
    fakeZoom = zoom
    if (!missing(lonR) & !missing(latR)) {
        XYmin = RgoogleMaps::LatLon2XY(lat = latR[1], lon = lonR[1], zoom = zoom)
        XYmax = RgoogleMaps::LatLon2XY(lat = latR[2], lon = lonR[2], zoom = zoom)
        nTiles[1] = abs(XYmax$Tile[1, 1] - XYmin$Tile[1, 1]) + 
            1
        nTiles[2] = abs(XYmax$Tile[1, 2] - XYmin$Tile[1, 2]) + 
            1
        center = c(lat = mean(latR), lon = mean(lonR))
        if (verbose) {
            cat("nTiles=", nTiles, ", center=", round(center, 
                3), "\n")
        }
    }
    XY = RgoogleMaps::LatLon2XY(lat = center["lat"], lon = center["lon"], 
        zoom = zoom)
    tileXY = XY$Tile + as.numeric(XY$Coords > 256)
    if (nTiles[1]%%2 == 0) {
        X = (tileXY[1, 1] - nTiles[1]/2):(tileXY[1, 1] + nTiles[1]/2 - 
            1)
    }
    else {
        X = (tileXY[1, 1] - (nTiles[1] - 1)/2):(tileXY[1, 1] + 
            (nTiles[1] - 1)/2)
    }
    if (nTiles[2]%%2 == 0) {
        Y = (tileXY[1, 2] - nTiles[2]/2):(tileXY[1, 2] + nTiles[2]/2 - 
            1)
    }
    else {
        Y = (tileXY[1, 2] - (nTiles[2] - 1)/2):(tileXY[1, 2] + 
            (nTiles[2] - 1)/2)
    }
    if (verbose > 1) 
        browser()
    if (!dir.exists(tileDir)) {
        if (verbose) 
            cat("trying to create dir", tileDir, "\n")
        dir.create(tileDir, recursive = TRUE)
    }
    if (CheckExistingFiles) 
        ExistingFiles = list.files(path = tileDir)
    NumTiles = length(X) * length(Y)
    if (verbose) 
        cat(NumTiles, "tiles to download \n")
    DOWNLOAD = TRUE
    k = 1
    tiles = list()
    for (x in X) {
        for (y in Y) {
            if(is.null(urlBase)){
              cat("Not downloading any tiles. No url provided. \n")
            }
            else if (grepl("ESRI", urlBase)) {
                url <- paste0(urlBase, zoom, "/", x, "/", y, ".jpeg")
            }
            else if (grepl("openstreetmap", urlBase)) {
                url <- paste0(urlBase, zoom, "/", x, "/", y, ".png")
            }
            else if (grepl("google", urlBase)) {
                url <- paste0(urlBase, "&x=", x, "&y=", y, "&z=", zoom)
            }
            else if (grepl("arcgis", urlBase)) {
                url <- paste0(urlBase, "/tile/", zoom, "/", x, "/", y)
            }
            f = paste(zoom, x, y, sep = "_")
            if (CheckExistingFiles) 
                if (paste0(f, tileExt) %in% ExistingFiles) {
                  if (verbose) 
                    cat("NOT downloading existing file ", f, 
                      tileExt, "\n", sep = "")
                  DOWNLOAD = FALSE
                }
                else {
                  DOWNLOAD = TRUE
                }
            destfile = file.path(tileDir, f)
            mapFile = paste0(destfile, tileExt)
            if (DOWNLOAD) {
                if (!is.null(TotalSleep)) {
                  Sys.sleep(round(runif(1, max = 2 * TotalSleep/NumTiles), 
                    1))
                }
                if(is.null(urlBase)){ ######################################
                  NULL
                } else {
                  download.file(url, mapFile, mode = "wb", quiet = TRUE)
                }###########################################################
            }
            if (returnTiles) {
                res = try(readPNG(mapFile, native = TRUE))

                if (class(res) == "try-error") {
                  res = try(readJPEG(mapFile, native = TRUE))
                }
                else if (class(res) == "try-error") {
                  download.file(url, mapFile, mode = "w", quiet = TRUE)
                }
                else tiles[[k]] = res
            }
            k = k + 1
        }
    }
    mt = list(X = X, Y = Y, zoom = zoom, tileDir = tileDir, tileExt = tileExt, 
        tiles = tiles)
    class(mt) = "mapTiles"
    invisible(mt)
}

Here's an example of downloading some map tiles from the given urlBase into my working directory, in the tileDir subfolders.

getmaptiles(center = c(lat = 52.431635, lon = 13.194773), 
  #lonR, latR, 
  nTiles = c(3, 3), zoom = 13,
  urlBase = "http://services.arcgisonline.com/arcgis/rest/services/World_Topo_Map/MapServer",
  CheckExistingFiles = FALSE, 
  TotalSleep = NULL, tileExt = ".jpg",
  tileDir= "~/mapTiles/WorldTopoMap/", 
  returnTiles = FALSE, verbose = 1)

If you wanted to directly download a specific map tile, something like this might work.

download.file("http://services.arcgisonline.com/arcgis/rest/services/World_Topo_Map/MapServer/tile/13/4397/2690",
  "~/mapTiles/WorldTopoMap//13_4397_2690.jpg", mode = "wb")
Illfated answered 20/4, 2022 at 19:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.