Mapbox for Jekyll posts

code • January 26, 2014

As of 7/26/2014, this site has moved to the Mapbox static API.

A few months ago, I began playing around with the Google Static Maps API. I integrated it with my Static Google Maps Image for Jekyll Posts and created a Static Map Maker.

Since then, the Google maps have worked great with my posts. All I need to do is add locations to my front-matter and Jekyll logic handles the rest. It was sometimes annoying having to fiddle with the zoom to make all the map markers fit on the map, but other than that Google maps worked.

I started playing with the Mapbox API this weekend. The API has so many features that I started a wish list for my posts with maps:

I decided to roll Mapbox into my site, much like I did with Google maps.

Starting out

After skimming through the Mapbox.js examples, I knew that I wanted to focus on the Fit Map to Markers example. In this example, the markers are saved as GeoJSON and then that data is loaded into the marker layer. But, I want to define my locations in the front-matter of my Jekyll post, not create a GeoJSON file. To make this happen, I needed to find a way to define my locations in the flesh.

I clicked around the examples, until I found what I was looking for in Load GeoJSON example. This example uses the variable geojson to hold all the map marker data.

My next step was to marry the two examples:

var map = L.mapbox.map("map", "katydecorah.h41bj3lj"),
  geoJson = [
    {
      type: "FeatureCollection",
      features: [
        {
          type: "Feature",
          properties: {
            title: "DC",
            "marker-color": "#2A2B26",
          },
          geometry: {
            type: "Point",
            coordinates: [-77.03887939453125, 38.89530825492018],
          },
        },
      ],
    },
  ],
  markerLayer = L.mapbox.markerLayer().setGeoJSON(geoJson).addTo(map);
map.fitBounds(markerLayer.getBounds());

It worked!

See the Pen Mapbox -- Testing by Katy DeCorah (@katydecorah) on CodePen.

Demonstration with more than one location.

Jekyll and Mapbox

Now that I had the map working, I was confident that I could integrate Mapbox into my Jekyll posts.

In the front-matter of this post, I added locations, just like I have done in earlier posts to generate a Google map (I’m using coordinates until I have time to crack geocoding). I added a new flag to this post, mapType: Mapbox, which will let Jekyll know that I want to use Mapbox and not Google maps.

The following is this page’s front-matter to generate the map:

mapType: Mapbox
locations:
  - "-73.7629483,42.6539068"
  - "-73.7254484,43.2440284"
  - "-82.5525523,35.5908429"

Since I’m still exploring and learning the Mapbox API, I’m not 100% ready to break up with Google maps on my posts. For now I will allow Google maps on older posts, but I will use the flag to let Jekyll know when to use Mapbox.

I altered my Google map code to consider the new Mapbox flag:

{% if page.locations %}
<div{% if page.mapType %} id="map"{% endif %} class="post-map-header">
{% if page.mapType %}{% else %}
{% include img.html width="1280" height="180" src="http://maps.googleapis.com/maps/api/staticmap?{% include img.html width="1280" height="180" src="http://maps.googleapis.com/maps/api/staticmap?{% for location in page.locations %}{% if forloop.first %}center={{location | replace:' ','+' }}&amp;markers=color:blue%7C{{location | replace:' ','+' }}{% else %}&amp;markers=color:blue%7C{{location | replace:' ','+' }}{% endif %}{% endfor %}&amp;zoom={% if page.zoom %}{{page.zoom}}{% else %}13{% endif %}&amp;size=1280x180&amp;scale=2&amp;sensor=false&amp;visual_refresh=true" class="post-location-image" alt="untitled" %}
{% endif %}
</div>
{% endif %}

If the post has mapType, then Jekyll will add id="map" and it will not load the Google map. For this page, which has mapeType, the logic above will output:

<div id="map" class="post-map-header"></div>

In my end.html include, that wraps up every post and page, I added a new include, mapbox.html. This include has the following logic:

{% if page.mapType %}
<link
  href="//api.tiles.mapbox.com/mapbox.js/v1.6.1/mapbox.css"
  rel="stylesheet"
/>
<script src="//api.tiles.mapbox.com/mapbox.js/v1.6.1/mapbox.js"></script>
<script>
  var geoJson = [{"type":"FeatureCollection","features":[{% for location in page.locations %}{"type":"Feature","properties":{"marker-color":"#2A2B26"},"geometry":{"type":"Point","coordinates":[{{location}}]}}{% if forloop.last == false %},{% endif %}{% endfor %}]}],
  map = L.mapbox.map('map', 'katydecorah.h41bj3lj',{zoomControl: false}),
  markerLayer = L.mapbox.markerLayer().setGeoJSON(geoJson).addTo(map);
  map.fitBounds(markerLayer.getBounds());
  map.dragging.disable();
  map.touchZoom.disable();
  map.doubleClickZoom.disable();
  map.scrollWheelZoom.disable();
  if (map.tap) map.tap.disable();
</script>
{% endif %}

If the page has mapType, then it will load Mapbox and create the geoJson variable. The geoJson variable is constructed using a loop on the current page locations.

Finalizing

I decided to disable dragging and zooming because for posts, the map is more supplemental and for context. I didn’t want my visitors to get lost in a scroll. I also overrode the cursor: move on .leaflet-container,.leaflet-clickable to default to not confuse visitors since the dragging and zooming is disabled.

I added opacity to .leaflet-tile-pane to allow the map to slightly recede.

I added an animation to the .leaflet-marker-icon to allow the map markers to glide onto the map. I love how the tiles transition in and I wanted to see if I could push it a little further.

I didn’t do too much to customize the look and feel of the map, but I definitely plan on growing into it.

Geocoding

It wasn’t until after I finished all this, that I found the Initially Position Map with Geocode example. I had assumed that I would need to collect the coordinates for the locations, instead of using a string. I studied the example and played around with it for a while. I was able to set the bounds of a map based on an array, but I just didn’t have the time to figure out adding map markers. I will have to return to this later, because string locations are much easier to work with when creating posts on the fly. Plus, it would give me the opportunity to roll Mapbox into my past posts.

Conclusions

I realize this might not be a typical use case for Mapbox, considering that I pretty much neutered the map into a static map. Still, I love automating features and it was still cool to figure out. I’m excited to develop this feature more into my posts.

Mapbox produces gorgeous maps and has great documentation to help you show them off.

Keep reading code