Skip to content
Mike Bostock edited this page Sep 20, 2017 · 2 revisions

Wiki β–Έ Introduction

TopoJSON is an extension of GeoJSON. TopoJSON introduces a new type, "Topology", that contains GeoJSON objects. A topology has an objects map which indexes geometry objects by name. These are standard GeoJSON objects, such as polygons, multi-polygons and geometry collections. However, the coordinates for these geometries are stored in the topology's arcs array, rather than on each object separately. An arc is a sequence of points, similar to a line string; the arcs are stitched together to form the geometry. Lastly, the topology has a transform which specifies how to convert delta-encoded integer coordinates to their native values (such as longitude & latitude).

Example

Here is a complete TopoJSON file with a single polygon geometry object representing Aruba:

{
  "type": "Topology",
  "transform": {
    "scale": [0.036003600360036005, 0.017361589674592462],
    "translate": [-180, -89.99892578124998]
  },
  "objects": {
    "aruba": {
      "type": "Polygon",
      "arcs": [[0]],
      "id": 533
    }
  },
  "arcs": [
    [[3058, 5901], [0, -2], [-2, 1], [-1, 3], [-2, 3], [0, 3], [1, 1], [1, -3], [2, -5], [1, -1]]
  ]
}

See the topology test suite for more examples.

Geometry Objects

Geometry objects in TopoJSON are similar to those in GeoJSON, except that a TopoJSON geometry object defines its coordinates as a sequence of the containing topology's arcs, as referenced by zero-based index. For example, a line string might be defined as

{"type": "LineString", "arcs": [42]}

where 42 refers to the arc topology.arcs[42]. Note that a line string's coordinates are defined as an array of arcs, rather than a single arc, so that multiple arcs may be concatenated to form the line string as necessary:

{"type": "LineString", "arcs": [42, 43]}

Similarly, a polygon with a hole might be defined as

{"type": "Polygon", "arcs": [[42, 43], [44]]}

When stitching together arcs to form geometries, the last coordinate of the arc must be the same as the first coordinate of the subsequent arc, if any. For example, if arc 42 represents the point sequence A β†’ B β†’ C, and arc 43 represents the point sequence C β†’ D β†’ E, then the line string [42, 43] represents the point sequence A β†’ B β†’ C β†’ D β†’ E.

In many cases, a shared arc may need to be reversed. For example, the shared border between California and Nevada proceeds southwards on the California side, but northwards on the Nevada side. A negative index indicates that the sequence of coordinates in the arc should be reversed before stitching. To avoid ambiguity with zero, the ones' complement is used; -1 (~0) represents the reversed arc 0, -2 (~1) represents the reversed arc 1, and so on.

Points and multi-point geometry objects are represented directly with coordinates, as in GeoJSON, rather than arcs. However, these coordinates are still represented as fixed integers, and should be converted in the same fashion as arcs, as described next.

Arcs and Coordinates

The topology's arcs array is, in effect, a multi-line string. As in GeoJSON, each point has at least two dimensions: x and y. However, unlike GeoJSON, each coordinate in TopoJSON is represented as an integer value relative to the previous point. The first point is relative to the origin, ⟨0,0⟩. To convert to latitude and longitude (or absolute coordinates), the topology defines a linear transform consisting of a scale and translate. For example:

"transform": {
  "scale": [0.035896033450880604, 0.005251163636665131],
  "translate": [-179.14350338367416, 18.906117143691233]
}

To convert from relative integer coordinates to fixed integer coordinates, keep a running sum while iterating over the arc. To convert from fixed integer coordinates to absolute coordinates, scale each coordinate, and then add the appropriate translation. In code:

function arcToCoordinates(topology, arc) {
  var x = 0, y = 0;
  return arc.map(function(point) {
    return [
      (x += point[0]) * topology.transform.scale[0] + topology.transform.translate[0],
      (y += point[1]) * topology.transform.scale[1] + topology.transform.translate[1]
    ];
  });
}

Arc coordinates may have additional dimensions beyond x and y; the meaning of these dimensions is outside the scope of this specification. For example, to support for dynamic simplification at different zoom levels, the visual importance of each point as computed by a simplification algorithm (e.g., Visvalingham) may be stored along with each point so that arcs can be rapidly filtered as needed.

While GeoJSON is agnostic about winding order, TopoJSON recommends that all sub-hemisphere polygons be in clockwise winding order; counterclockwise winding order indicates the polygon that covers an area greater than one hemisphere.

Features

TopoJSON does not support GeoJSON features, nor feature collections. Instead, these objects are converted to their respective geometries and geometry collections. In addition, TopoJSON allows optional identifiers (id) and properties to be stored directly on geometry objects. This simplified representation is equivalent but can be encoded more efficiently. Null geometry objects are still expressible as geometry objects with an undefined type (rather than the object itself being null, as in GeoJSON), and thus can retain an identifier and properties.