package topojson

  1. Overview
  2. Docs

Introduction

The main API entrypoint is Topojson.

TopoJSON encodes geospatial data using topological information to improve how this data is encoded. In many ways it is similar to GeoJSON, using similar primitives like a Point or a Multipolygon. However, the primary way to use TopoJSON is with a shared Topology. This is an object that also contains arcs. An arcs field contains an array of an array of positions essentially a collection of linestrings. Other geometries can then index into this database of segments to build themselves up. This can help reduce the size of the data significantly as often geometries share segments (e.g. country borders).

TopoJSON vs. GeoJSON

TopoJSON and GeoJSON are very interlinked. Both use JSON as there data format to encode geospatial information. As mentioned, the difference between them is that TopoJSON uses topological information to improve this encoding.

Take a simple GeoJSON example where we have two linestrings.

{
  "type": "LineString",
  "coordinates": [ [100.0, 0.0], [101.0, 1.0] ]
}

We can convert this to TopoJSON by creating an index of the different arcs and then referencing those instead the linestring definitions.

{
  "type":"Topology",
  "objects":{"geo":{"type":"LineString","arcs":[0] }},
  "arcs":[[[100,0],[101,1]]],
  "bbox":[100,0,101,1]
}

At some point this library will let you do this, until then you can use the excellent topojson-server library.

This is a small example but hopefully hints at how useful this approach might be for larger examples (e.g. with polygons for each county in Ireland).

Why do I need to provide a JSON implementation?

In order to use the Topojson library, you must first instantiate an implementation using Topojson.Make which expects a simple JSON parser as an argument.

It is quite common to do geospatial JSON work in the browser with tools like Leaflet. Using a JSON parser written in OCaml and compiled to the browser instead of the built-in JSON parser is really bad for performance. If you are working in the browser I recommend using Brr.Json to provide and implementation that will work a lot faster. In normal OCaml you could using something like Ezjsonm or Yojson. Here is an example implementation using the former:

module Ezjsonm_parser = struct
  type t = Ezjsonm.value
  let catch_err f v =
    try Ok (f v) with Ezjsonm.Parse_error (_, s) -> Error (`Msg s)
  let find = Ezjsonm.find_opt
  let to_string t = catch_err Ezjsonm.get_string t
  let string = Ezjsonm.string
  let to_float t = catch_err Ezjsonm.get_float t
  let float = Ezjsonm.float
  let to_int t = catch_err Ezjsonm.get_int t
  let int = Ezjsonm.int
  let to_list f t = catch_err (Ezjsonm.get_list f) t
  let list f t = Ezjsonm.list f t
  let to_array f t = Result.map Array.of_list @@ to_list f t
  let array f t = list f (Array.to_list t)
  let to_obj t = catch_err Ezjsonm.get_dict t
  let obj = Ezjsonm.dict
  let null = `Null
  let is_null = function `Null -> true | _ -> false
end

module Topojson = Topojson.Make (Ezjsonm_parser)