ramnathv / rMaps

Interactive Maps from R
http://rmaps.github.io
389 stars 194 forks source link

Issue with KML files for leaflet maps #53

Open johndharrison opened 10 years ago

johndharrison commented 10 years ago

In the /libraries/leaflet/config.yml file there is a reference to https://github.com/shramov/leaflet-plugins/blob/master/layer/vector/KML.js for cdn, for static there is no corresponding .js file in leaflet/external/ and no reference in the config file.

We can add the KML.js file using the addAssets method:

map1 = Leaflet$new()
map1$setView(c(37.422069, -122.087461), 13)
map1$tileLayer(provider = 'Stamen.TonerLite')
map1$addAssets(css = NULL, jshead = 'http://harrywood.co.uk/maps/examples/leaflet/leaflet-plugins/layer/vector/KML.js')
map1$addKML('http://kml-samples.googlecode.com/svn/trunk/kml/Placemark/placemark.kml')
map1

However now there is an issue with content:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://kml-samples.googlecode.com/svn/trunk/kml/Placemark/placemark.kml. This can be fixed by moving the resource to the same domain or enabling CORS.

I temporarily wrote the kml file to the rMaps library

require(rMaps)
map1 = Leaflet$new()
map1$setView(c(45.5236, -122.675), 13)
map1$tileLayer("http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png")
map1$addAssets(css = NULL, jshead = 'http://harrywood.co.uk/maps/examples/leaflet/leaflet-plugins/layer/vector/KML.js')
map1$addKML('leaflet/placemark.kml')
leafletLib <- file.path(find.package("rMaps"), "libraries", "leaflet")
sampleKml <- readLines('http://kml-samples.googlecode.com/svn/trunk/kml/Placemark/placemark.kml')
write(sampleKml, file.path(leafletLib, 'placemark.kml'))
# finally try the map
map1

# remove the temp file 
file.remove(file.path(leafletLib, 'placemark.kml'))

Is there a better method to get the kml working?

An example of the issue is here http://stackoverflow.com/questions/23618813/cant-display-leaflet-html-through-r-shiny-404-error-how-to-integrate-kml-fil/23628748#23628748

ramnathv commented 10 years ago

The key issue is to serve placemark.kml from the same directory as the html file. Currently, rCharts and rMaps are only set up to copy index.html and the chart libraries automatically. I have been toying with allowing more external files to be copied, which should simplify the task at hand, but currently that feature is missing.

Here is a workaround

# create your chart as usual adding KML.js
map1 = Leaflet$new()
map1$setView(c(37.422069, -122.087461), 13)
map1$tileLayer(provider = 'Stamen.TonerLite')
map1$addAssets(css = NULL, jshead = 'http://harrywood.co.uk/maps/examples/leaflet/leaflet-plugins/layer/vector/KML.js')

# create a temporary directory
td <- tempdir()

# copy leaflet library files to this directory
suppressMessages(copy_dir_(
  map1$LIB$url, file.path(td, map1$LIB$name))
)

# download placemark.kml to this directory
downloader::download(
  'http://kml-samples.googlecode.com/svn/trunk/kml/Placemark/placemark.kml',   
  file.path(td, 'placemark.kml')
)

# add placemark.kml and save 
map1$addKML('placemark.kml')
map1$save('index.html', static = F)

# view chart using rstudio viewer or servr package
rstudio::viewer(file.path(td, 'index.html'))
# servr::httd()
ramnathv commented 10 years ago

In the future, I will add an easier mechanism to achieve this. My current thinking is that you can pass a list of files that will be copied to a folder named resources that can then be referred to with the relative path resources. I am still firming up the API.

johndharrison commented 10 years ago

A resource folder sounds like a smart idea. Will that be an rCharts method? I would imagine the problem of serving files local to the index.html will crop up from time to time with other libraries.

ramnathv commented 10 years ago

Yes. I think it will be best to include it as a method, so that under the hood, I am free to figure out alternate implementations without upsetting the applecart. Taking a leaf out of the Shiny play book, I can just introduce an addResourcePath method. So you can do

map1$addResourcePath("path/to/placemark.kml", "placemark.kml")

In turn, rCharts will ensure that these resources are copied to the correct location.

I will still need to think through some nitty-gritty details, but I agree that there is need for such a method, so this feature will get added for sure.

johndharrison commented 10 years ago

@ramnathv there was a further question on getting this running with shiny http://stackoverflow.com/questions/23637902/networking-for-r-shiny-r-studio-rmaps-with-kml/23638824#23638824 . I hacked together an approach but would be interested for your views on how it might work.

ramnathv commented 10 years ago

As you correctly noted, the conflict between the Leaflet object in rCharts and rMaps creates a lot of problems. I will be removing Leaflet and Datamaps from the next version of rCharts and also commit a bug-fix that prevents rMaps from being used with Shiny seamlessly.

I will post a modified version of your code, once I push these changes, coz till then, anything will be just a quick hack.

chris-holcomb commented 10 years ago

I just wanted to add that with the geoJSON option, KML isn't that necessary, I was just trying to very quickly get a demo working when I posted those questions. Now we are using your great package rMaps and it's support of Leaflet through Shiny.