Library
Module
Module type
Parameter
Class
Class type
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 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).
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)