iD Updates More Specifics on the Road to An Editor

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.

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 NOTES.md 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!