I used to display gpx traces of my running using a Jekyll/Octopress plugin I made quite some time ago, but after the migration to pure Jekyll I preferred to display GPX traces with no plugin at all.

I just declare traces as a Jekyll collection, drop .gpx files in _traces to which I set a custom layout in add yaml front-matter. The custom layout which imports Leaflet and parses the xml in javascript directly in the browser.

## Collection

The collection is declared in _config.yml and set to generate standalone content:

collections:
  traces:
    output: true

Then I drop .gpx files in _traces and simply add a front-matter with the custom layout:

---
layout: trace
title: "Marathon des Alpes Maritimes 2013"
---
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<gpx xmlns="http://www.topografix.com/GPX/1/1" creator="byHand" version="1.1"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">
  <trk>
    <name>Marathon des Alpes Maritimes 2013</name>
    <trkseg>
      <trkpt lat="43.695063" lon="7.269926">
        <ele>60.5</ele>
        <time>2013-11-10T06:56:37.267Z</time>
      </trkpt>
      <!-- more -->
    </trkseg>
  </trk>
</gpx>

## Layout

The layout is a bit more complex, it needs to

  • import Leaflet (which I personally checkin in my blog repository rather than using the hosted version to be standalone)
  • drop content (which is the gpx trace) in a script tag rather than in the body
  • display the expected page with an empty div in where the map is to appear
  • include javascript code to initialize the map from the embedded gpx content
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>{{ page.title }}</title>
    <meta name="viewport" content="width=device-width">

    <!-- Leaflet -->
    <link rel="stylesheet" href="/css/leaflet-0.7.3.css"">
    <script src="/js/leaflet-0.7.3.js"></script>
    <script type="application/gpx+xml" id="gpx-source">{{ content }}</script>

    <!-- Custom CSS -->
    <link rel="stylesheet" href="/css/main.css">
  </head>
  <body>

    {% include header.html %}

    <div class="page-content">
      <div class="wrap">
        <div class="post">
          <header class="post-header">
            <h1>{{ page.title }}</h1>
          </header>
          <article class="post-content">
            <div id="map" style="height: 40em;"></div>
          </article>
        </div>
      </div>
    </div>

    {% include footer.html %}

    <script>
(function () {
  function htmlCollectionMap(collection, cb) {
    var transformed = new Array(collection.length);
    for (var i = 0; i < collection.length; i++) {
      transformed[i] = cb(collection.item(i), i);
    }
    return transformed;
  }

  function pointToLatLng(point) {
    return [parseFloat(point.getAttribute('lat')), parseFloat(point.getAttribute('lon'))];
  }

  var gpxSource = document.getElementById('gpx-source').textContent;
  var parser = new DOMParser();
  var gpx = parser.parseFromString(gpxSource, "text/xml");
  var colors = ['red', 'blue', 'green'];

  var bounds;
  var map = L.map('map');
  htmlCollectionMap(gpx.getElementsByTagName('trkseg'), function (segment, idx) {
    var points = htmlCollectionMap(segment.getElementsByTagName('trkpt'), pointToLatLng);
    bounds = bounds ? bounds.extend(points) : new L.LatLngBounds(points);
    L.polyline(points, { color: colors[idx % colors.length] }).addTo(map);
  });
  map.fitBounds(bounds);
  L.tileLayer('http://otile3.mqcdn.com/tiles/1.0.0/map/{z}/{x}/{y}.png', {
    attribution: 'Tiles Courtesy of <a href="http://www.mapquest.com/" target="_blank">MapQuest</a> <img src="http://developer.mapquest.com/content/osm/mq_logo.png">',
    maxZoom: 18
  }).addTo(map);
})();
    </script>
  </body>
</html>

For my case I also added custom tags in the front-matter like the duration and the type of race. The layout displays them directly in the served HTML and it is indexed.

## Github pages

Not using a custom plugin theorically allows to directly use Github pages to generate the site and simply push sources to there. Though the version of Jekyll currently supported by Github pages is too old so in the meantime I use the following makefile to manually push to it:

init:
  test -d _gh-pages || git clone --depth 1 -b gh-pages git@github.com:xxx/yyy _gh-pages

build:
  cd _gh-pages && git rm -rf .
  jekyll build
  cp -R _site/* _gh-pages
  cd _gh-pages && git add .

deploy:
  cd _gh-pages && git commit -m "Update" && git push

## Likes

What I really like in this solution is being able to display traces with natively in Jekyll, no real hack there. An important aspect to the solution is that the gpx track itself is embedded in the page, not need to fetch it asynchronously.

On the bad side, it may be harder to use that to include a trace in the middle of a post, in my case traces are standalone items, but the solution may not apply if mixed with text.