This week, I'm heading to Kansas University for the annual GIS Day @ KU where I will be speaking about mapping and JavaScript. If you're at the event or if you are an educator and looking to integrate MapBox in your syllabus, get in touch.
MapBox at Kansas University GIS Day
Jeff Hurlock joins MapBox
A big welcome to Jeff Hurlock, who has just joined the MapBox team. He'll be working with our business development team bringing on new subscribers, customizing plans for large users, and helping existing subscribers as their needs change. Jeff will also support our operations team, specifically around special projects and internal processes.
Jeff comes to us from DCSeats, a company he started four years ago to broker tickets to concerts and sporting events.
Drone Imagery for OpenStreetMap
Last weekend we captured 100 acres of aerial imagery at 4cm resolution. It took less than an hour to fly, and it was easy to publish the imagery on the web using TileMill and then trace in OpenStreetMap. Autonomous flying platforms like Sensefly's eBee paired up with a nimble software stack are changing aerial mapping. Drones like the eBee can cheaply and accurately photograph medium-sized areas, and then the imagery can be made immediately available to everyone.
Baptiste Tripard from Sensefly preparing and flying a Sensefly eBee at Lost Creek Winery, Virginia
The drone operates less like an RC plane and more like a Roomba. You can define an area of interest on a laptop, beam it to the eBee, and then just toss the drone in the air where it will autonomously collect imagery. Within 40 minutes, the drone took 225 photos covering 100 acres from an altitude of 120 meters. Larger areas of 2,500 acres and more are possible, but this was sufficient for our needs.
Within 40 minutes we collected about 100 acres worth of imagery. Image resolution is about 4cm - zoom in to explore.
As soon as the drone landed, the images were loaded into Postflight/Pix4D for georeferencing and mosaicing and then into TileMill for resampling and tiling for the web. Afterward the imagery is easily added as a custom layer in OpenStreetMap's iD editor for tracing.
Adding drone imagery as reference layer to OpenStreetMap for editing
Tracing features from drone imagery on OpenStreetMap
The high resolution of the stitched mosaic is really useful for editing in iD. As you can tell, we're excited about what Sensefly's eBee means for the future of open-source mapping. Small autonomous aircraft are excellent for capturing timely imagery or where other aerial imagery is not available.
Hit up me (@bobws) or Alex (@lxbarth) on Twitter if you'd like to talk more about mapping with drones.
Why our Australia is red
We’re putting out some very saturated pixels. Why? Simple: The world really looks like that. When I demonstrate this I like to pull up photos of the Australian outback on Flickr, for example:
Red sand by Rupert Ganzer.
Here’s another:
Simpson Desert Scrub by John Benwell. It looks exaggerated at first, but notice that the sky and leaves are normal hues. The sand is truly that colorful.
We show interior Australia as bright red-orange because interior Australia is bright red-orange. And the same goes for everywhere that other mapmakers tend to artificially subdue — we show what’s there:
Arches National Park, in Eastern Utah by faungg, and our imagery:
Or take the Alaskan tundra. It isn’t quite as vivid, but it still has more numerous and delicate colors than many people would imagine (perhaps because of traditional satellite maps that “correct” it to greenish gray):
Take a Big Deep Breath by Western Arctic National Parklands.
Our goal is to show the earth’s colors exactly as they are.
Of course it’s not always so easy. As Ian’s work on satellite labels shows, it can be very tricky to layer text and other design elements over bright satellite imagery. But that’s why there’s a saturation control built into our editing interface. If you need a more muted basemap, you can simply drag the slider. Radical customizability is what lets us get away with radical accuracy.
Glowing tweets
Yeah, we've done this before, but there's nothing like playing more with design, and I don't think I'll ever get tired of staring at geotagged tweets and marveling at all they reveal about the forms of human settlement and activity.
Singapore
Istanbul
Osaka
Mexico City
Bangkok
GoPro video maps
We've been playing with mapping GoPro video, most recently using some of Bobby's biking footage and overlaying it with his Strava GPX track. We synced up the video track using MapBox.js that embeds a video in a marker's popup and moves it along a route. Similar to the Marker Movement example, a popup with the video in an iframe is bound to the marker's track so it can go along for the ride. We have similar examples on the new MapBox.js examples page and I also pulled together this tutorial, starting with an initial route and marker from your GPX data, and then show how to set a marker along the vertices of a route to animate it along a line and then showing how to bind a popup to a marker so the video traverses the route.
Setting up the map
We start by setting up our basic map, position, and zoom level. The popup is also set to stay open in case it is clicked to close.
varmap=L.mapbox.map('map','examples.map-20v6611k',{closePopupOnClick:false}).setView([38.95,-77.01459],12);
Loading the JSON
Tracks recorded by Strava can be easily exported as a GPX file and loaded into geojson.io for conversion into a GeoJSON format that's easy for MapBox.js to consume.
There are other ways to include GeoJSON, but for this example, we're
including it as the variable ride
from an external JavaScript file <script src='ridelapse.js'></script>
in the header.
varride={type:'FeatureCollection',features:[{type:'Feature',id:0,properties:{name:'Team MapBox'},geometry:{type:'LineString',coordinates:[[-77.012451,38.912549],
a snippet of ridelapse.js
Next, we make a style for the line then add the ride
variable into our
example as the GeoJSON. A marker is also added to indicate the current
position starting at the beginning coordinates of the ride.
functionstyle(feature){return{weight:7,opacity:1,color:'#0d8709',opacity:0.7};}varline=L.geoJson(ride,{style:style}).addTo(map);varmarker=L.marker([0,0],{icon:L.mapbox.marker.icon({type:'Feature',geometry:{type:'Point',coordinates:[-77,37.9]},properties:{'marker-symbol':'star'}})}).addTo(map);
Following the route
We create a function, tick()
, that moves the marker by setting its placement on each point in the list of coordinates
that form the route's line.
The synchronization of the video's time over the total distance of the path is an estimate since the video has small variations.
// a shortcut to accessing the line's coordinate listvarcoords=ride.features[0].geometry.coordinates,i=0;functiontick(){marker.setLatLng([coords[i][1],coords[i][0]]);// ensure the marker doesn't fall off the end of // the list of coordinates.// 18ms is the time interval between pointsif(++i<coords.length)setTimeout(tick,18);}// start the animationtick();
Binding the popup
Finally, we bind the video to the marker's popup and set the popup's latitude and longitude to pan with the marker.
marker.bindPopup('<iframe src="https://player.vimeo.com/video/69426498?title=0&byline=0&portrait=0&autoplay=1" width="200" height="150" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>',{keepInView:false,autoPan:false,closeButton:false,maxWidth:1000}).openPopup();marker._popup.setLatLng=function(latlng){this._latlng=L.latLng(latlng);this._updatePosition();this._adjustPan();};
The marker._popup.setLatLng
is a minor hack to prevent the video from resetting when changing the popup position - a quirk that will be fixed in the next MapBox.js version.
Wrap up
You can continue to extend this example with time sliders, custom popups, and clean styles for routes and markers. Check out a complete example on our expanding examples page and start adding some new perspectives to your routes.
High-availability features added to OSRM
We just released OSRM v0.3.7 with huge improvements for running OSRM in a high-availability production environment. OSRM now handles data updates very transparently through the use of a new memory management sub-system and does not require the shutdown of the routing process. These are huge requirements for MapBox Directions, set to launch in early 2014. With this new of OSRM release, we're embracing the shared memory paradigm. Our all-new, process-independent data management allows you to load and replace data sets without any downtime or noticeable delay.
Routing on OpenStreetMap data is very similar to aiming at a moving target. The data is constantly changing and improving. For example, there is the impressive number of about 100,000 new road segments added each day. While it takes some time to process the data, the underlying data set has already changed as soon as you can begin to actually compute any route. On the OSRM demo site we are constantly reprocessing everything and updating the routing data twice a day. Previously this required a shutdown of the old routing process, and a start up of a new one with the updated routing data. It took about five minutes to do so because of the sheer size of the data. All of that is a thing of the past now.
In short while the routing process is happily serving requests, new data is loaded into a separate memory region. Once this is done, the process is notified of the new data. It puts new requests on hold and immediately switches to the new data, and resumes processing requests. The old data is de-allocated on the first request to the new data. And all of this happens virtually without any noticeable delay to the user. As you may have already guessed, this is only a very simplified picture of the entire story. Under the hood we apply sophisticated synchronization schemes and allocation algorithms to deliver seamless integration — one of the corner stones of OSRM's design.
And the best thing? We bring you all of this without introducing any breaking changes. If you are happy with how OSRM was handling data loading and data storage before, you can go on and use it as before. But if you want to run OSRM in a high-availability environment, this new and exciting feature gives a number of important improvements:
- load new routing data without any downtime
- attach any number of query processes to the same set of data
- instant restart of any failing routing process
The last item on this list is especially important. No software is perfect and error-free. In case your software has a fatal error and dies unexpectedly, you want to recover from it more or less instantly. Since we load all the data independently of any application process, the time to restart a failed routing process is a matter of significantly less than a single second instead of minutes.
For an in-depth explanation on how to use and configure shared memory in your environment, have a look at the corresponding page on our Wiki.
Using Shared Memory
With all these changes, you should load all the shared memory directly into your RAM. It's as easy as:
$ ./osrm-datastore /path/to/data.osrm
If there is insufficient available RAM (or not enough space configured), you will receive the following warning when loading data with osrm-datastore
:
[warning] could not lock shared memory to RAM
In this case, data will be swapped to a cache on disk, and you will still be able to run queries. But note that caching comes at the prices of disk latency. Again, consult the Wiki for instructions on how to configure your production environment. Starting the routing process and pointing it to shared memory is also very, very easy:
$ ./osrm-routed --sharedmemory=yes
And that's it. Surprisingly simple, isn't it?
Pinterest: Scaling Beautiful Maps
Pinterest now has maps! Gorgeous maps, designed by our friends at Stamen using our open source map design studio TileMill and our new vector tiles– all hosted on MapBox.com.
This stack gives Pinterest a map that matches their unique brand and that scales for their millions of users - so it's fast on every device, anywhere in the world. Like any other map hosted on MapBox.com, Pinterest's map gets live data updates every minute as new data is added and improved by the OpenStreetMap community. Now, Pinterest users have the ability to edit the map on OpenStreetMap.org and see the updates almost immediately, anywhere on the site.
"Every day people Pin about 1.5 million places, and now there are more than 750 million Pins of these destinations on Pinterest."
Read more about the feature from Pinterest. We're incredibly Pinterested to see where they go from here.
MapBox.js v1.5.0
MapBox.js keeps getting better: version 1.5.0 updates Leaflet to 0.7, bumping up performance and fixing bugs.
varmap=L.mapbox.map('map','examples.map-9ijuk24y',{shareControl:true,infoControl:{editLink:true}}).setView([41.891304,12.48621940],17);
A new info control makes it easier to properly credit datasources and even easier to connect users to OpenStreetMap so they can improve the global community map.
Setting editLink: true
adds a callout to 'Improve this map' that automatically opens
OpenStreetMap for editing, with the map in exactly in the place you were viewing.
We've also tuned the aesthetic improvements introduced in v1.4.2 to mix better with third-party extensions and Leaflet Plugins like Leaflet.draw and leaflet-fullscreen.
<linkhref='//api.tiles.mapbox.com/mapbox.js/v1.5.0/mapbox.css'rel='stylesheet'/><script src='//api.tiles.mapbox.com/mapbox.js/v1.5.0/mapbox.js'></script>
Updating to v1.5.0 is simple, and there's updated documentation and examples for all functionality.
Golf course maps
We're working on a new golf course style in our vector terrain map for outdoor apps that makes golf courses look amazing — so it's easier to see features like fairways, greens, tees, and hole numbers. Not only do they look clean, but these are designed in a way so that the right data stands out to golfers who are increasingly using GPS and mobile apps on the course. If your local course is not yet represented then add it to OpenStreetMap!
Indian Hills, East Lansing MI. A short amateur course located near Michigan State University - MapBox Satellite
Starr Pass, Tucson AZ. Three unique desert-lined courses - MapBox Satellite
Pebble Beach, Monterey CA. Regarded as one of the top public courses in America - MapBox Outdoors
Augusta National, Augusta GA. Hosts The Masters every year - MapBox Outdoors
Augusta National, Augusta GA - MapBox Satellite
Kiawah Island Golf Resort, SC. 90 holes of golf - MapBox Outdoors
Doral Great White, Miami FL. Designed by golf legend Greg Norman - MapBox Streets
Doral Great White, Miami FL - MapBox Outdoors
Doral Great White, Miami FL - MapBox Satellite
Starr Pass, Tucson AZ - MapBox Outdoors
Aaron Lidman Joins MapBox
Aaron Lidman joins the MapBox team! Aaron has amazing experience on both the product side and data side. He's created projects like Toner for TileMill, a custom CartoCSS style for anyone to make cool black and white maps like Stamen, and OSM and GeoJSON, a JavaScript module for converting between OSM XML and GeoJSON data. Most recently, he launched OSMLY— a tool that makes importing data into OpenStreetMap more straightforward through a simple user interface. Aaron is also a regular contributor to OpenStreetMap.
Aaron will be working on our core engineering team across various projects. Right now Aaron is working with me building out new features on iD, our open source map editor, and improving the main OpenStreetMap.org website by making the project easier to understand for new users and introducing a modern look and feel.
New office space in San Francisco
We just got an amazing new office space in San Francisco, right in SOMA at 9th and Howard. We're sticking to our roots and continuing to work alongside our friends at Code for America, who we LOVE. MapBox SF is just moving to the top floor of the building.
Our team is growing fast, and we need space that is going to grow with us over the next few years. This means we have a little extra room for the next 18 months and are looking for 1 - 2 cool companies to sublease part of our MapBox SF space. We can fit ~15 people on the sublease. We don't just mean geo folks. We want a diverse space with crazy energy and people who are passionate about random and exciting project __________. You tell us ; )
Interested in 3,000 square feet of open space and a view from the fourth floor that's filled with disruptive innovators? Here is the floor plan. Ping me on Twitter @m_wanee if you have questions or want to talk. Move in is January 2nd.
Party before the TechLady Hackathon
We're hosting the pre-party for the TechLady Hackathon + Training Day! Come party with us on Friday, December 6 at the MapBox garage.
We want to bring together developers and wannabe developers to talk about code, how to learn to code, and how to make programming fun for everyone. Trainings the following day will focus on learning and doing - covering the basics of everything from GitHub to HTML/CSS to JavaScript. The weekend is all about bringing together smart people who want to see more people - and more women - love coding. Hope to see you there.
We unit test our blog at MapBox
We blog using Jekyll at MapBox, which means that all of our blog posts are written in code. Sometimes we make mistakes though, and missing or invalid metadata can cause layout quirks or unexpected errors. To catch these problems earlier, we decided to treat our blog like we do our code - automated unit tests now run after every commit.
Jekyll is a static site generator. We keep all content in simple text files and Jekyll reads each file and transforms it into HTML. We use Jekyll for all static content on our site - the blog, developer docs, help pages and much more.
Each bit of content, like a blog post or a help document, is a file composed of two parts: metadata stored in YAML, and content written in Markdown.
Here's what the YAML part of this blog post looks like:
---layout:blogcategory:blogtitle:"WeunittestourblogatMapBox"permalink:/blog/unit-test-blogimage:https://farm4.staticflickr.com/3710/10732224274_a4c27f21fc.jpgtags:-Mike Morris---
If we forget the author tag, the blog layout breaks. If we write invalid YAML, the blog won't rebuild and the post will stay in limbo.
Content testing prevents these failures ahead of time. Every blog post is submitted as a pull request on GitHub, and with pull request testing hooked up to Travis CI, every change is run through a test suite that gives the green light.
If there's a problem, we know immediately.
Travis-CI supports plenty of languages for test suites, and we ended up writing ours in Node.js. Since Jekyll is a Ruby project, Travis installs Jekyll for the compilation and Node for the test runner. We use mocha
and assert
for our content tests.
Here's our .travis.yml
file:
language:node_jsbefore_install:-gem install liquid -v 2.5.1 --no-rdoc --no-ri-gem install jekyll -v 1.0.2 --no-rdoc --no-ri-gem install rdiscount -v 1.6.8 --no-rdoc --no-riscript:-./node_modules/.bin/mocha test/test.metadata.js-jekyll build
One important consideration is that all tests must be created (but not necessarily run) synchronously in Mocha, which necessitates using the synchronous variants of some Node functions to build tests dynamically. While writing some of the more complex tests, we found that it was more efficient to load all posts using fs.readFileSync
before any tests were run, rather than loading each post asynchronously during its corresponding test. This approach allows for testing one-to-many relationships between posts (such as unique permalinks) while minimizing the time spent loading files from disk.
We first construct a posts
object and create a test for each post.
varpaths={blog:'_posts/blog/',team:'_posts/team/'},dirs=Object.keys(paths);varposts=dirs.reduce(function(prev,dir,index,list){varpath=paths[dir];describe(path,function(){prev[dir]=readDir(path);});returnprev;},{});dirs.forEach(function(dir){varpath=paths[dir];describe(path,function(){posts[dir].forEach(function(post){it(post.name,tests[dir](post));});});});
The metadata parsing is wrapped in a try/catch statement because js-yaml
throws an error when parsing invalid YAML.
functionreadPost(dir,filename){varbuffer=fs.readFileSync(dir+filename),file=buffer.toString('utf8');try{varparts=file.split('---'),frontmatter=parts[1];it(filename,function(){assert.doesNotThrow(function(){jsyaml.load(frontmatter);});});return{name:filename,file:file,metadata:jsyaml.load(frontmatter),content:parts[2]};}catch(err){}}functionreadDir(dir){returnfs.readdirSync(dir).map(function(filename){returnreadPost(dir,filename);});}
tests['blog']
asserts each necessary property of a blog post: all image links and iframes are HTTPS, exactly the expected metadata keys are present, and the metadata is valid. The date
key, if it exists, must be a valid JavaScript Date
object, the permalink must begin with /blog/
and each post needs to contain a <!--more-->
tag for generating post excerpts with the excerpt.rb
Jekyll plugin.
vartests={'blog':function(dir,file){returnfunction(){varfile=post.file,metadata=post.metadata,content=post.content,keys=['published','date','layout','category','title','image','permalink','tags'];// HTTPS images & iframes in blogvarurls=file.match(/https?:\/\/[\w,%-\/\.]+\/?/g);if(urls)urls.forEach(function(url){assert.ok(!(/http:[^'\"]+\.(jpg|png|gif)/).test(url),url+' should be https');});variframes=file.match(/<iframe [^>]*src=[\"'][^\"']+/g);if(iframes)iframes.forEach(function(iframe){assert.ok(!(/<iframe [^>]*src=[\"']http:/).test(iframe),iframe+' should be https');assert.ok(!(/<iframe [^>]*src=[\"']https:\/\/[abcd]\.tiles\.mapbox\.com.*\.html[^\?]/).test(iframe),iframe+' is insecure embedded map (add ?secure=1)');});assert.equal(typeofmetadata,'object');assert.ok('layout'inmetadata,missing('layout'));assert.ok('category'inmetadata,missing('category'));assert.ok('title'inmetadata,missing('title'));assert.ok('image'inmetadata,missing('image'));assert.ok('permalink'inmetadata,missing('permalink'));assert.ok('tags'inmetadata,missing('tags'));if(metadata.date){assert.ok(metadata.dateinstanceofDate,invalid('date',metadata.date));}assert.equal(metadata.category,'blog',invalid('category',metadata.category));assert.ok(isImage(metadata.image),invalid('image',metadata.image));assert.ok(/^\/blog\//.test(metadata.permalink),invalid('permalink',metadata.permalink));assert.ok(content.indexOf('<!--more-->')!==-1,missing('<!--more-->'));varextraKeys=Object.keys(metadata).diff(keys);assert.deepEqual(extraKeys,[],extraneous(extraKeys));};}};
We also check the integration between different posts and confirm that the author of each blog post matches the title of a post in _posts/team/
.
// Build a list of team member namesvarteam=posts.team.map(function(post){returnpost.metadata.title;});// Later, in a test assertion, make sure that that// the author of a blog post is a team member.assert.ok(team.indexOf(author)!==-1,'no team post found for author '+author);
We've saved ourselves a lot of frustration by automating this little part of our publishing workflow. The integration between Travis CI and GitHub lets everyone on our team, not just developers, benefit from tests and push new posts with confidence.
Finacial Times: London’s renting crisis.
The data team at FT.com is killing it. Publishing a few maps a week, their latest is on London's renting market crisis. The map visualization shows affordability across different properties at different salary levels across London — all done using their signature pink map tiles.
Financial Times: London’s renting crisis.
The data team at FT.com is killing it. Publishing a few maps a week, the latest is on London's renting market crisis. The map visualization shows affordability across different properties at different salary levels across London — all done using their signature pink map tiles.
Katie Wandtke joins MapBox!
Katie Wandtke has joined the MapBox team! She will be taking care of our subscribers, making sure their MapBox experience is awesome from day one and that all goes smoothly on the contracts and administrative end. She'll also be running out logistics to support our growing team.
Katie has experience creating efficient systems, nailing the details, and even opening new offices from her field work as a project manager running international development projects around the world. She is an awesome addition as we expand both our subscribers and our team.
Mapping a golf course
It's fast to add a golf course to a map by tracing satellite imagery - an entire course layout takes less than 30 minutes. Fact: that's roughly 1/8th the time it takes to play 18 holes, and you're 97% less likely to throw your putter into a lake. Check out the OpenStreetMap golf wiki for more details about adding specific golf features, like sand traps, greens, and holes etc, and take an early look at these beautiful golf maps that are coming to our maps soon.
MapBox Outdoors before and after - only took 25 minutes.
Mozilla's Custom Branded Maps
Mozilla's flagship web site Mozilla.org just relaunched including new custom maps. The maps use Mozilla's colors, typography and design to fit seamlessly into the new web site. In keeping with Mozilla's open source culture, all maps are based on OpenStreetMap data and Vector Tiles to implement custom design at scale.
Mozilla's new maps reflect the brand's playful attitude down to the street level.
Major labels are set in Mozilla's characteristic Open Sans Light font face and street level labels are set in Open Sans.
The light wave texture in the water bodies adds liveliness.
The map uses Mozilla's color palette. While much more muted in colors, it plays a seamless role in Mozilla's web site.
Head over to Mozilla's new web site to check the new maps. You can find them for instance on the contact page.
New Sharing Interface
We've released a new sharing interface that not only makes it easier to customize interactions on the map, but writes the code you'll need to get started. Map embeds now have toggles for interface elements and developers can take advantage of our "Starter file" - a simple HTML file built for your map with everything you need to develop with MapBox.js.