Mapbox for Jekyll posts
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:
- full width map
- automatically fit markers to map
- customize the look and feel
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!
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:' ','+' }}&markers=color:blue%7C{{location | replace:' ','+' }}{% else %}&markers=color:blue%7C{{location | replace:' ','+' }}{% endif %}{% endfor %}&zoom={% if page.zoom %}{{page.zoom}}{% else %}13{% endif %}&size=1280x180&scale=2&sensor=false&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.