0

I would like to produce a shiny app that asks for two addresses, maps an efficient route, and calculates the total distance of the route. This can be done using the Leaflet Routing Machine using the javascript library, however I would like to do a bunch of further calculations with the distance of the route and have it all embedded in a shiny app.

You can produce the map using rMaps by following this demo by Ramnathv here. But I'm not able to pull out the total distance travelled even though I can see that it has been calculated in the legend or controller. There exists another discussion on how to do this using the javascript library - see here. They discuss using this javascript code:

alert('Distance: ' + routes[0].summary.totalDistance);

Here is my working code for the rMap. If anyone has any ideas for how to pull out the total distance of a route and store it, I would be very grateful. Thank you!

# INSTALL DEPENDENCIES IF YOU HAVEN'T ALREADY DONE SO
library(devtools)
install_github("ramnathv/rCharts@dev")
install_github("ramnathv/rMaps")

# CREATE FUNCTION to convert address to coordinates
library(RCurl)
library(RJSONIO)

construct.geocode.url <- function(address, return.call = "json", sensor = "false") {
  root <- "http://maps.google.com/maps/api/geocode/"
  u <- paste(root, return.call, "?address=", address, "&sensor=", sensor, sep = "")
  return(URLencode(u))
}

gGeoCode <- function(address,verbose=FALSE) {
  if(verbose) cat(address,"\n")
  u <- construct.geocode.url(address)
  doc <- getURL(u)
  x <- fromJSON(doc)
  if(x$status=="OK") {
    lat <- x$results[[1]]$geometry$location$lat
    lng <- x$results[[1]]$geometry$location$lng
    return(c(lat, lng))
  } else {
    return(c(NA,NA))
  }
}

# GET COORDINATES
x <- gGeoCode("Vancouver, BC")
way1 <- gGeoCode("645 East Hastings Street, Vancouver, BC")
way2 <- gGeoCode("2095 Commercial Drive, Vancouver, BC")

# PRODUCE MAP
library(rMaps)
map = Leaflet$new()
map$setView(c(x[1], x[2]), 16)
map$tileLayer(provider = 'Stamen.TonerLite')

mywaypoints = list(c(way1[1], way1[2]), c(way2[1], way2[2]))

map$addAssets(
  css = "http://www.liedman.net/leaflet-routing-machine/dist/leaflet-routing-machine.css",
  jshead = "http://www.liedman.net/leaflet-routing-machine/dist/leaflet-routing-machine.js"
)

routingTemplate = "
 <script>
 var mywaypoints = %s
 L.Routing.control({
  waypoints: [
    L.latLng.apply(null, mywaypoints[0]),
    L.latLng.apply(null, mywaypoints[1])
  ]
 }).addTo(map);
 </script>"

map$setTemplate(
  afterScript = sprintf(routingTemplate, RJSONIO::toJSON(mywaypoints))
)
# map$set(width = 800, height = 800)
map
Community
  • 1
  • 1
cnmillar
  • 327
  • 2
  • 13

1 Answers1

1

You can easily create a route via the google maps api. The returned data frame will have distance info. Just sum up the legs for total distance.

library(ggmap)
x <- gGeoCode("Vancouver, BC")
way1txt <- "645 East Hastings Street, Vancouver, BC"
way2txt <- "2095 Commercial Drive, Vancouver, BC"
route_df <- route(way1txt, way2txt, structure = 'route')
dist<-sum(route_df[,1],na.rm=T) # total distance in meters
#
qmap(c(x[2],x[1]), zoom = 12) +
   geom_path(aes(x = lon, y = lat),  colour = 'red', size = 1.5, data = route_df, lineend = 'round') 
jcplum
  • 26
  • 2
  • This is great. Thank you! Although, I wish that I could interact with the map more (e.g., zoom in and out) and have the map position itself and zoom depending on the route. Also, qmap does seem a bit slow, which may be problematic when packaged in Shiny. But otherwise, this does exactly what I need. – cnmillar Apr 17 '15 at 22:45
  • I just added the qmap as a quick example plot. But yeah, it is limited. You should be able to take the coordinate info from the route_df and plot a similar line on a leaflet map. – jcplum Apr 20 '15 at 14:38
  • That's a good idea, re: take route_df and plot in leaflet. Thanks! – cnmillar Apr 21 '15 at 15:07