I recently (about 6 months ago) had an interview with WeFunder during which they asked me to put together a map of their active campaigns. While I ultimately didn’t take the job, the interview gave me a chance to update myself on the current state of web based mapping solutions and, specifically, on GeoJSON which didn’t exist the last time I looked at the space. Having long wanted to add a map to this site, this newfound knowledge seemed like a wonderful opportunity to do finally do exactly that.

MapBox can render a wonderful 3D globe with full support for touch devices

The process was incredibly simple: I added a new template to my website that generates a GeoJSON feed containing all posts and photos with a location in their metadata, and pointed MapBox at that feed. It’s been fun to see my content in this new form and is definitely something I hope to make the most of as the world opens up and we can travel again. You can check out the results for yourself on the Places page.


Development Notes

This website is published using my static site builder, InContext, which uses Jinja for templating. Since generating JSON is one of the least elegant aspects of Jinja, I thought I’d publish the GeoJSON template here for future reference:

{% set locations = [] %}
{% for post in site.posts(include=page.include, ascending=False) | rejectattr("location", "none") %}
  {% if post.location.latitude and post.location.longitude %}
    {% set details = {
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [post.location.longitude, post.location.latitude]
      }
    } %}
    {% set properties = {} %}
    {% set _ = properties.__setitem__("url", post.url) %}
    {% if post.title %}
      {% set _ = properties.__setitem__("title", post.title) %}
    {% endif %}
    {% if post.thumbnail %}
      {% set _ = properties.__setitem__("icon", post.thumbnail.url) %}
    {% endif %}
    {% set _ = details.__setitem__("properties", properties) %}
    {% set _ = locations.append(details) %}
  {% endif %}
{% endfor %}
{% set collection = {
  "type": "FeatureCollection",
  "features": locations
  } %}
{{ collection | json | safe }}

As you can see, this takes advantage of the side effects of the Jinja set command to build up a dictionary containing the GeoJSON structure which I then serialize with a json filter. Perhaps in the future I will add some extensions that enable direct dictionary manipulation. For example, I think the following might be clearer:

{% set details = {
       "type": "Feature",
       "geometry": {
           "type": "Point",
           "coordinates": [post.location.longitude, post.location.latitude]
       }
   } %}

{% set properties = {} %}
{% dictionary_set(properties, "url", post.url) %}
{% dictionary_set_if(properties, "title", post.title) %}
{% dictionary_set_if(properties, "icon", post.thumbnail) %}
{% dictionary_set(details, "properties", properties) %}

The introduction of the conditional command, dictionary_set_if seems somewhat messy, but would also significantly simplify the control flow when generating the kind of data structures you might typically want to serialize.