Tuesday, 4 February 2014

Load KML, GPX or GeoJSON traces into a leaflet.js map with the Leaflet.FileLayer plugin


The following post is a portion of the Leaflet Tips and Tricks book which is free to download. To use this post in context, consider it with the others in this blog or just download the the book as a pdf / epub or mobi .
----------------------------------------------------------

The Leaflet.FileLayer plugin adds the ability to load a gps trace in the form of a KML, GPX or GeoJSON file to a Leaflet map. The idea being that if you have gone on a journey and captured the trip using a gps it can be loaded easily onto a map for viewing.
The plugin was developed by Mathieu Leplatre and is hosted on GitHub where it can be downloaded from.

Leaflet.FileLayer code description

The following is a code listing that we will use to describe the required changes from our simple-map.html example to enable Leaflet.FileLayer. There is also an online version on bl.ocks.org and GitHub.
<!DOCTYPE html>
<html>
<head>
    <title>LeafletFileLayer Plugin</title>
    <meta charset="utf-8" />
    <link 
        rel="stylesheet" 
        href="http://cdn.leafletjs.com/leaflet-0.7/leaflet.css"
    />
    <link 
        rel="stylesheet" 
        href="http://makinacorpus.github.io/Leaflet.FileLayer/Font-Awesome/css/font-awesome.min.css"
    />
</head>
<body>
    <div id="map" style="width: 600px; height: 400px"></div>

    <script
        src="http://cdn.leafletjs.com/leaflet-0.7/leaflet.js">
    </script>
    <script
        src="http://makinacorpus.github.io/Leaflet.FileLayer/leaflet.filelayer.js">
    </script>
    <script
        src="http://makinacorpus.github.io/Leaflet.FileLayer/togeojson/togeojson.js">
    </script>

    <script>
        var map = L.map('map').setView([-41.2858, 174.78682], 14);
        mapLink = 
            '<a href="http://openstreetmap.org">OpenStreetMap</a>';
        L.tileLayer(
            'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
            attribution: '&copy; ' + mapLink + ' Contributors',
            maxZoom: 18,
            }).addTo(map);

        var style = {color:'red', opacity: 1.0, fillOpacity: 1.0, weight: 2, clickable: false};
        L.Control.FileLayerLoad.LABEL = '<i class="fa fa-folder-open"></i>';
        L.Control.fileLayerLoad({
            fitBounds: true,
            layerOptions: {style: style,
                           pointToLayer: function (data, latlng) {
                              return L.circleMarker(latlng, {style: style});
                           }},
        }).addTo(map);

    </script>
</body>
</html>
There are three ‘blocks’ that have changed in the code from our simple map example.
The first is an additional link to load more CSS code;
<link 
    rel="stylesheet" 
    href="http://makinacorpus.github.io/Leaflet.FileLayer/Font-Awesome/css/font-awesome.min.css"
/>
(Because of the length of the URL for the file, the formatting may make cutting and pasting from the ebook problematic. For a more reliable snippet of code, download the live version from GitHub)
This loads the css file directly from the Leaflet.FileLayer repository on GitHub, so if you are loading from a local file you will need to adjust the path appropriately.
The second is the block that loads the leaflet.filelayer.js script and an additional script togeojson.js that was written by Tom MacWright to perform the internal conversion of the GPX and KML traces to GeoJSON.
<script
    src="http://makinacorpus.github.io/Leaflet.FileLayer/leaflet.filelayer.js">
</script>
<script
    src="http://makinacorpus.github.io/Leaflet.FileLayer/togeojson/togeojson.js">
</script>
(Again because of the length of the URL for the file, the formatting may make cutting and pasting from the ebook problematic. For a more reliable snippet of code, download the live version from GitHub).
leaflet.filelayer.js exists as a separate block of JavaScript code and we are loading the file directly from the Leaflet.FileLayer repository on GitHub (as per the earlier advice, if you are loading from a local file you will need to adjust the path appropriately). Likewise we are also loading the togeojson.js file from GitHub.
The last change to the file is the block of code that runs and configures Leaflet.FileLayer.
var style = {color:'red', opacity: 1.0, fillOpacity: 1.0, weight: 2, clickable: false};
L.Control.FileLayerLoad.LABEL = '<i class="fa fa-folder-open"></i>';
L.Control.fileLayerLoad({
    fitBounds: true,
    layerOptions: {style: style,
                   pointToLayer: function (data, latlng) {
                      return L.circleMarker(latlng, {style: style});
                   }},
}).addTo(map);
The fist line (starting with var style =) sets the styles for the control and the loaded gps traces. Then the icon to initiate the file opening process is declared (L.Control.FileLayerLoad.LABEL = '<i class="fa fa-folder-open"></i>';).
The script then sets the options for Leaflet.FileLayer. The first is the fitBounds option which will present a loaded gps trace in a window that is zoomed to show its full extent. The second is the layerOptions option which will apply the styling to the trace based on our previously declared values (this included the shortpointToLayer function that makes circles from point values in the traces).
Lastly we add the layer to our map with .addTo(map).
So when we load our page we can see the folder icon in the top left hand corner.
Leaflet.FileLayer plugin
If we click on this folder we will be presented with a dialogue box where we can select a file to load and when we do…
Leaflet.FileLayer plugin with gps trace from Hanmer Springs
Our gps trace is automatically zoomed and panned to present our trace to its full extent.
A copy of this file and a copy of all the files that appear in the book can be downloaded (in a zip file) when youdownload the book from Leanpub


The description above (and heaps of other stuff) is in the Leaflet Tips and Tricks book that can be downloaded for free (or donate if you really want to :-)).

7 comments:

  1. This is great. Thanks for the write up. On mine example though the nodes are huge.

    I'd also like it to be able to remember the last uploaded kml/gpx etc..

    ReplyDelete
    Replies
    1. Sorry for the delay and I'm not really sure why the nodes would be different. Remembering the last loaded kml file would be tricky-ish. That's starting to head down the road of being an application. Not strictly difficult, but a little beyond ordinary IMHO.

      Delete
  2. Hi there! A good tool for converting kml to gpx files I recommend trying is this free online program http://kml2gpx.com/ that doesn't need installation; just upload files and you'll get fast results. It also works from gpx to kml format.

    ReplyDelete
  3. I'm interested to have the ability to use the leaflet editing tools once the layer is uploaded. At the moment it seems to overlay, but cannot be used as a leaflet layer. Any ideas how this can be done?

    ReplyDelete
    Replies
    1. Sorry for the really late reply :-(. And equally sorry to say that I don't have an answer for you. This is something that I have no experience with. The place I would start is with one of the overlay editing plugins available here (http://leafletjs.com/plugins.html#edit-geometries). Best of luck.

      Delete
  4. There is some limit for kml sizes? I am trying with a 1mb kml file and its not open, another with 6mb as well. But, when I open a 100kb kml file these test works. How can I open those biggers, is a different process or there is a true limitation for that way?

    ReplyDelete
    Replies
    1. That's an interesting question. The only limit that I'm aware of in this respect would be the one that would cause the browser difficulty. This would vary from browser to browser (http://stackoverflow.com/questions/1076622/browser-limitation-with-maximum-page-length), but would be independent of file type (i.e. it shouldn't be affected by a kml file in particular). In your case however, the problem is't the size of the file, but it might be caused by the type of data that the browser has to render causing it to have a problem. That's just a guess, but I'd put a 30% chance on it of being right.

      Delete