Shared posts

10 Apr 12:07

Hack Your Maps

Web maps have come a long way. Improved data, cleaner design, better performance, and more intuitive controls have made web maps a ubiquitous and critical component of many apps. They’ve also become one of the mobile space’s most successful transplants as more and more apps are powered by location-aware devices. The core web map UI paradigm itself—a continuous, pannable, zoomable surface—has even spread beyond mapping to interfaces everywhere.

Despite all this, we’ve barely begun to work web maps into our design practice. We create icon fonts, responsive grids, CSS frameworks, progressive enhancement strategies, and even new design processes. We tear down old solutions and build new ones, and even take an extra second to share battle stories in prose and in person. Yet nearly five years since Paul Smith’s article, “Take Control of Your Maps,” web maps are still a blind spot for most designers.

Have you ever taken apart a map? Worked with a map as a critical part of your design? Developed tricks, hacks, workarounds, or progressive enhancements for maps?

This article is a long overdue companion to Paul’s piece. Where he goes on a whirlwind survey of the web mapping stack at 10,000 feet, we’re going to walk through a single design process and implement a modern-day web map. By walking this path, I hope to begin making maps part of the collective conversation we have as designers.

Opinionated about open

Paul makes a strong case for why you might want to use open mapping tools instead of the established incumbent. I won’t retread his reasons here, but I would like to expand on his last: Open tools are the ones we hack best.

There is nothing mysterious about web maps. Take any spatial plane, split it up into discrete tiles, position them in the DOM, and add event handlers for panning and zooming. The basic formula can be applied to Portland, Mars, or Super Mario Land. It works for displaying large street maps, but nothing stops us from tinkering with it to explore galleries of art, create fictional game worlds, learn human anatomy, or simply navigate a web page. Open tools bare the guts of this mechanism to us, allowing us to see a wider range of possibilities.

The variety of web maps: character navigation, Mars, and Super Mario Land.
The mechanics of web maps are not limited to street maps.

We should know the conditions under which map images are loaded and destroyed; we should argue whether map tiles are best positioned with CSS transforms or not; and we should care whether vector elements are drawn with SVG or Canvas. Open tools let us know and experiment with these working details of our maps. If you wouldn’t have it any other way with your HTML5, CSS, or JavaScript libraries, then you shouldn’t settle for less when it comes to maps.

In short, we’ll be working with a fully open mapping stack. MapBox, where I work, has pulled together several open source libraries into a single API that we publish under mapbox.js. Other open mapping libraries that are worth your time include Leaflet and D3.js.

Starting out

I’m a big fan of Sherlock Holmes. Between the recent Hollywood movies starring Robert Downey Jr. and the BBC’s contemporary series, I’m hooked. But as someone who has never been to London, I know I’m missing the richness of place and setting that Sir Arthur Conan Doyle meant to be read into his short stories.

A typical approach would be to embed a web map with pins of various locations alongside one of the Sherlock stories. With this approach the map becomes an appendix—a dispensable element that plays little part in Doyle’s storytelling. Instead, we’re going to expand the role of our map, integrating it fully into the narrative. It will set the stage, provide pace, and affect the mood of our story.

Comparing a map used as embedded media versus one used as a critical design element.

A tale of places

To establish a baseline for our tale, I restructured The Adventure of the Bruce-Partington Plans to be told around places. I picked eight key locations from the original text, pulled out the essential details of the mystery, and framed them out with HTML, CSS, and JavaScript.

Text only demo.
A Sherlock Holmes story in text only. View Demo 1.
  • The story is broken up into section elements for each key location. A small amount of JavaScript implements a scrolling flow that highlights a single section at a time.
  • Our page is not responsive yet, but it contains scaffolding to guard against bad choices that could thwart us. The main text column is fluid at 33.33% and pins to a min-width: 320px. If our content and design flow reasonably within these constraints, we’re in good shape.

Next, we’ll get started mapping. Initially we’ll work on our map separately from our story page to focus on learning key elements of a new technology.

Maps are data

The mapping equivalent of our abridged Sherlock story is a dataset of eight geographic points. GeoJSON, a format for describing geographic data in JSON, is the perfect starting point for capturing this data:

{
    "geometry": { "type": "Point", "coordinates": [-0.15591514, 51.51830379] },
    "properties": { "title": "Baker St." }
}, {
    "geometry": { "type": "Point", "coordinates": [-0.07571203, 51.51424049] },
    "properties": { "title": "Aldgate Station" }
}, {
    "geometry": { "type": "Point", "coordinates": [-0.08533793, 51.50438536] },
    "properties": { "title": "London Bridge Station" }
}, {
    "geometry": { "type": "Point", "coordinates": [0.05991101, 51.48752939] },
    "properties": { "title": "Woolwich Arsenal" }
}, {
    "geometry": { "type": "Point", "coordinates": [-0.18335806, 51.49439521] },
    "properties": { "title": "Gloucester Station" }
}, {
    "geometry": { "type": "Point", "coordinates": [-0.19684993, 51.5033856] },
    "properties": { "title": "Caulfield Gardens" }
}, {
    "geometry": { "type": "Point", "coordinates": [-0.10669358, 51.51433123] },
    "properties": { "title": "The Daily Telegraph" }
}, {
    "geometry": { "type": "Point", "coordinates": [-0.12416858, 51.50779757] },
    "properties": { "title": "Charing Cross Station" }
}

Each object in our JSON array has a geometry—data that describe where this object is in space—and properties—freeform data of our own choosing to describe what this object is. Now that we have this data, we can create a very basic map.

Basic web mapping demo.
The basics of web mapping. View Demo 2.
  • Note that the coordinates are a pair of latitude and longitude degrees. In the year 2013, it is still not possible to find a consistent order for these values across mapping APIs. Some use lat,lon to meet our expectations from grade-school geography. Others use lon,lat to match x,y coordinate order: horizontal, then vertical.
  • We’re using mapbox.js as our core open source mapping library. Each map is best understood as the key parameters passed into mapbox.map():
    1. A DOM element container
    2. One or more Photoshop-like layers that position tiles or markers
    3. Event handlers that bind user input to actions, like dragging to panning
  • Our map has two layers. Our tile layer is made up of 256x256 square images generated from a custom map on MapBox. Our spots layer is made up of pin markers generated from the GeoJSON data above.

This is a good start for our code, but nowhere near our initial goal of using a map to tell our Sherlock Holmes story.

Beyond location

According to our first map, the eight items in our GeoJSON dataset are just places, not settings in a story full of intrigue and mystery. From a visual standpoint, pins anonymize our places and express them as nothing more than locations.

To overcome this, we can use illustrations for each location—some showing settings, others showing key plot elements. Now our audience can see right away that there is more to each location than its position in space. As a canvas for these, I’ve created another map with a custom style that blends seamlessly with the images.

Web map with illustrations.
Illustrations and a custom style help our map become part of the storytelling. View Demo 3, and then read the diff.
  • The main change here is that we define a custom factory function for our markers layer. The job of the factory function is to take each GeoJSON object and convert it to a DOM element—an a, div, img, or whatever—that the layer will then position on the map.
  • Here we generate divs and switch from using a title attribute in our GeoJSON to an id. This provides us with useful CSS classes for displaying illustrations with our custom markers.

Bringing it all together

Now it’s time to combine our story with our map. By using the scroll events from before, we can coordinate sections of the story with places on the map, crafting a unified experience.

Web map coordinated to story text by a scroll handler.
As the user reads each section, the map pans to a new location. View Demo 4, then read the diff.
  • The bridge between the story and the map is a revamped setActive() function. Previously it only set an active class on a particular section based on scrolling position. Now it also finds the active marker, sets an active class, and eases the map to the marker’s location.
  • Map animation uses the easey library in the mapbox.js API, which implements animations and tweening between geographic locations. The API is dead simple—we pass it the lon,lat of the marker we want to animate to, and it handles the rest.
  • We disable all event handlers on our map by passing an empty array into mapbox.map(). Now the map can only be affected by the scrolling position. If users wanted to deviate from the storyline or explore London freeform, we could reintroduce event handlers—but in this case, less is more.

Displaying our fullscreen map together with text presents an interesting challenge: our map viewport should be offset to the right to account for our story on the left. The solution I’m using here is to expand our map viewport off canvas purely using CSS. You could use JavaScript, but as we’ll see later, a CSS-only approach gives us elegant ways to reapply and adjust this technique on mobile devices.

Using an off-canvas map width to offset the viewport center.

At this stage, our map and story complement each other nicely. Our map adds spatial context, visual intrigue, and an interesting temporal element as it eases between long and short distances.

Maps in responsive design

The tiled, continuous spatial plane represented by web maps is naturally well-suited to responsive design. Web maps handle different viewport sizes easily by showing a bit more or a bit less map. For our site, we adjust the layout of other elements slightly to fit smaller viewports.

Adding a responsive layout.
Tweaking layout with web maps. View Demo 5, then read the diff.
  • With less screen real estate, we hide non-active text sections and pin the active text to the top of the screen.
  • We use the bottom half of the screen for our map and use media queries to adjust the map’s center point to be three-fourths the height of the screen, using another version of our trick from Demo 4.

With a modest amount of planning and minimal adjustments, our Sherlock story is ready to be read on the go.

Solve your own case

If you’ve been following the code between these steps, you’ve probably noticed at least one or two things I haven’t covered, like the parameters of ease.optimal(), or how tooltips picked up on the title attribute of our GeoJSON data. The devil’s in the details, so post to this GitHub repository, where you will find the code and the design.

You should also check out:

  • The MapBox site, which includes an overview of tiling and basic web map concepts, and MapBox.js docs and code examples.
  • Leaflet, another powerful open source mapping library.
  • D3.js, a library for powering data-driven documents that has a broad range of applications, including mapping.

This example shows just one path to integrating web maps into your designs. Don’t stick to it. Break it apart. Make it your own. Do things that might be completely genius or utterly stupid. Even if they don’t work out, you’ll be taking ownership of maps as a designer—and owning something is the only way we’ll improve on it.