For the last few weeks, I’ve been working on building iD, along with John Firebaugh and with lots of help from Richard Fairhurst.

We’re all learning a lot: here are some specifics.

Making iD Fast

iD has to be fast. If the experience of moving the map, drawing roads, and so forth isn’t satisfying, it won’t be adopted.

There’s no single ingredient that makes maps fast: it’s essentially a combination of:

  • Javascript performance, like the speed of projecting data to screen coordinates, grabbing data from the local datastore, and assorted code like styling and processing mouse and touch events. In the case of canvas, maintaining a scenegraph is a big javascript performance task.
  • Network performance, or how quickly you can grab data from an API to display on-page
  • DOM Performance, like drawing to a Canvas element or updating attributes of an SVG element.

The clearest ‘first load’ issue for iD is network performance: data is coming down from OSM’s servers in untiled WMS-style queries and the servers we’re dealing with are not blazingly fast. We plan to resolve this partially by using tiled requests with smart caching, and otherwise handle expectations by making it clear when map data is loading.

Javascript performance isn’t a big bottleneck at this point, though there are certain inefficiencies that would be great to address, mainly in the finer points of d3.

The biggest bottleneck that I’m currently seeing is the DOM. iD uses SVG for rendering maps because it gives a clear path to styling data and handling interactivity. While it’s possible to use Canvas with a scenegraph, it’s likely to be more error-prone as far as hit-detection with multi-layered maps.

And so the biggest performance problem with, for instance, dragging the map, is the cost of reassigning the d attribute to all svg paths in order to move them onscreen.

There are ways around this:

  • Project vector features to a certain ‘zero origin’ and transform them into place onscreen
  • Handle pan behaviors by setting a transform on the entire map object

Both of these have tradeoffs: data on the map is not static, and so d3 needs to handle the case of a user dragging a line segment extremely well. And thus a heuristic like setting transforms on the entire map element will require a fallback for correctly calculating the position of transformed paths.

To fill in some background information: this is referring to CSS transforms, which have the positive effect of limiting browser repaints and reflows, the biggest performance hit of changing elements onscreen.

SVG’s performance relative to Canvas is a popular topic: canvas is generally faster for drawing many objects while SVG is better for large canvases. But the main consideration in this project is not raw drawing performance, but the ability of the rendering layer to support interactivity and updates: existing map renderers like KothicJS do fast canvas rendering, but static rendering like Mapnik.

Measuring Fast

I’m mostly developing in Chrome - there doesn’t seem to be a very good profiler for Firefox, unfortunately. The main metric for debugging performance problems is the Javascript CPU Profile option of the WebKit debugger.

Setting attributes, pulling data, and projecting points (‘mercator’) all contribute to the performance profile of iD.

Another dimension we’re paying close attention to is memory usage, or heap size. While much of iD uses the module pattern - for instance, the main iD.Map object - for highly allocated objects, we’re using Javascript prototype-based objects, which cut down on the size of closures in the heap.

Heap size is and should be dominated by the actual data of the map, stored in coordinate arrays and so on.

The Size of iD

The size of Javascript code has varying importance - often, it is cached after first load and doesn’t effect performance in any real way. However, given non-shared caches and large libraries (OpenLayers comes to mind) code size is a real performance consideration.

We’re using uglifyjs for code compression, and a simple Makefile & cat system for building a big iD.js file.

Right now d3 is the majority of the iD payload. This is relatively acceptable, since iD itself is very small, and would likely be much larger if it didn’t depend on d3 for specifics like map projection, event binding, and so on.

Making iD Friendly

iD has to be friendly. Meaning that it needs to be as self-explanatory as possible, and then fall back to help quickly.

First this is a question of interaction paradigms. The map should be some combination of an Adobe Illustrator experience and a Google Maps experience, without being too confusing. This means that, unlike Potlatch 2, we’re planning on having, essentially, modes.

One big difference will also be the separation of drawing ‘roads’ versus drawing ‘areas’. In the OSM data model, ways can represent both buildings - closed loops with area - and streets. There’s very little distinction on a technical level, but a very large distinction in most users minds, so we’re going to mirror the mental model.

The next big ‘what’ in OSM is the tagging model: while it’s flexible, it’s not clear.

iD is going to have a system of presets which has solid visual cues and good descriptions. Behind this is strong integration with TagInfo or similar: an index of commonly used tag combinations which leads users to make correct choices.

In order to make that work, we’re going to need to help out a lot on editing OSM wiki help - improving the descriptions of tag combinations to make them both distinct and descriptive.

Making iD Correct

OpenStreetMap is filled with corner cases. A few pathological conditions I’ve listed in the file which has been developed along with iD:

  • Ways with one node
  • Relations which contain themselves (circular references)
  • Nodes with no tags and no way attached
  • Ways which contain only nodes that are subsets of the nodes of other ways
  • Paths with intersecting boundaries (invalid geometries)

Handling each of these cases correctly is essential to iD: this editor cannot be destructive, or make design decisions that puts data integrity at risk.

What’s Next

We’re working on the meat of the problem currently: the ability to draw, edit, and remove map features, have those operations be reversable as undo operations and create changesets from that.

The data model has progressed greatly: an immutable graph, a simple history representation, and lightweight data objects are complete. There’s a lot around the edges, like entering and exiting drawing states, that needs work.

And the issue of iterating through the graph and generating a changeset is just about to be started.

If you’re interested in contributing, take a look at the repository on github, the current notes and open issues. We’re keeping a very open contributing process - pull requests are merged quickly, everything happens in the master branch, and issues are discussed in GitHub issues or in the #osm-dev IRC channel. Join us!

Devlogging work on the OpenStreetMap project by the MapBox team.

Much of this work is currently focused on improvements to OpenStreetMap funded by the Knight Foundation

Follow our work here on this blog or subscribe to our Twitter feed. You can subscribe to this blog’s feed or follow us at