Getting bounding box from leaflet in R

Viewed 3488

I am using R, RStudio and the leaflet package to visualise a map.

I would like to get the the min and max lat-longs of of the bounding box of a leaflet object. I think this can be done using Shiny (by using something like input$mapobj_bounds) but is there a non-shiny method to do this.

m <- leaflet(width=500,height=400) %>% 
   addTiles() %>% 
   setView(lng = -0.106831, lat = 51.515328, zoom = 18) %>%
   addCircleMarkers(lng = -0.106831, lat = 51.515328)

What i need is a function to get the bounding box using the input argument m.

Can this be done?

Also, the parameter values when looking into the object m look incorrect.

e.g.

> m$x$limits
$lat
[1] 51.51533 51.51533

$lng
[1] -0.106831 -0.106831

EDIT

I think the javascript function map.getBounds() may be of help here...as suggested here (Get the bounding box of the visible leaflet map?), but do not know how to apply this to our problem. Any help on this would be much appreciated.

3 Answers

This is an old question but it recently [29 Apr 2022] assisted me in finding a solution to a problem I was faced with. To say thanks I combined the approaches of @TonioLiebrand and @JeremyVoisey into a single self-contained (neatly rounded-off) function as follows:

# Self-contained function to calculate 'Leaflet Map Widget' Bounding Box co-ordinates ...
"f.calc.leaflet.bounding.box.coords" <- function(objLeafletMap=NULL) {
  FUNC_ID_SHORT <- "fCLBBC"; FUNC_ID_FULL <- "f.calc.leaflet.bounding.box.coords";
  boundNorth_ <- NULL; boundWest_ <- NULL; boundSouth_ <- NULL; boundEast_ <- NULL;
  if (is.null(objLeafletMap) || is.null(objLeafletMap$width) || is.null(objLeafletMap$height)) {
    base::message(base::paste0(" --> ", FUNC_ID_SHORT, " - Line 4 ", "| LEAFLET MAP WIDTH & HEIGHT NOT SPECIFIED ( FUNC ID: '", FUNC_ID_FULL, "' )."))
    base::stop(base::paste0(" --> ", FUNC_ID_SHORT, " - Line 5 ", " | Function Execution Terminated [ reason: REQUIRED PARAMS are NULL ] !!"))
  } else {
    
    # Extract Leaflet Map Widget 'x' property list values ( i.e. [center 'lat' & 
    # 'lon'], 'zoom' and 'options' widget property values )...
    view_ <- objLeafletMap$x$setView;
    zoom_ <- view_[[2]]; lon_ <- view_[[1]][2]; lat_ <- view_[[1]][1];
    
    # Extract Leaflet Map Widget 'width' and 'height' values ...
    width_ <- objLeafletMap$width; height_ <- objLeafletMap$height;
    
    # Calculate Leaflet Map Widget peripheral extent in co-ordinate dimensions ...
    lon_width_ <- 360 * width_ / 2 ^ (zoom_ + 8);
    lat_height_ <- 360 * height_ * cos(lat_ / 180 * base::pi) / 2 ^ (zoom_ + 8);
    
    # Calculate Leaflet Map Widget peripheral extent ( i.e. Bounding Box ) in co-ordinate values ...
    boundEast_ <- lon_ + lon_width_ / 2; boundWest_ <- lon_ - lon_width_ / 2;
    boundNorth_ <- lat_ + lat_height_ / 2; boundSouth_ <- lat_ - lat_height_ / 2;
  }
  return(list(top=boundNorth_, right=boundEast_, bottom=boundSouth_, left=boundWest_, zoom=zoom_))
}

This might be a bit of an overkill for some, but might also be a boon for others looking for a quick [highly-time-efficient] solution (as I did). Simply copy & paste the entire function into your R script, and once the function is read into your R Session Memory extract your Leaflet Map Widget bounding co-ordinates as follows:

# Simply call the function from wherever you need in your R script ...
mapBounds <- f.calc.leaflet.bounding.box.coords(m);   # <- 'm' == Leaflet Map Widget (with 'width' and 'height' defined) !!


# ... and extract the results as follows:
mapBounds$top
> -5.83050217387398

mapBounds$right
> 38.25046875 

mapBounds$bottom
> -40.209497826126 

mapBounds$left
> -9.21046875

I also added the zoom value as an output (because it seems wasteful to calculate it inside the function but not return it to the function call as a result). So now you can easily easily get the zoom value by calling ...

mapBounds$zoom
> 5

... after every map zoom change - if you really, really need to do that.

Lastly, I concur with @JeremyVoisey, there is an accuracy issue with the results from this approach - but this code snippet was sufficient in resolving the problem I had (and I was a bit time-pressed) ... so I didn't look into fixing the accuracy issue at this time.

Related