I Am using API to access spatial data collected using kobotoolbox. the api returns spatial data either as geoshape/geotrace/geopoint, but I need to covert that data to Geojson so that I can display them on my map using leaflet.
here is sample string of geoshape '-6.725577650887138 39.10606026649475 0.0 0.0;-6.72631550943841 39.10506717860699 0.0 0.0;-6.727484560110362 39.10561669617891 0.0 0.0;-6.727484560110362 39.10561669617891 0.0 0.0;-6.725577650887138 39.10606026649475 0.0 0.0;'
thanks a lot in advance!
That "geoshape" doesn't look like any well-known vector data format but rather looks like a string of
;
-separated 4-element vectors, which in turn are space-separated numbers.Some naïve parsing is in order.
Start by splitting the string into an array of strings with
String.prototype.split()
:Now
points
is anArray
ofString
s. We can turn each of those strings into anArray
ofNumber
s by providing a function that splits it by spaces:...and another function that coerces a
String
containing the textual representation of a number into aNumber
, like......and now let's put in some
Array.prototype.map()
magic and some method chaining magic, to make a function in which the input is a space-separated string and the output is anArray
ofNumber
s:Sometimes it's nicer to define those auxiliary functions passed to
map()
(orreduce()
orfilter()
or etc) as anonymous lambda-functions, like:You can use arrow function syntax instead if you want:
And since we're using
Number
as a function, we can directly use that as the parameter ofmap()
:Now that we have that function, let's go back to the beginning, and apply that function to each of the
;
-separated substrings:Let's change that to add even more lambda and method chaining and arrow syntax:
Also, since the GeoJSON format expects each coordinate as a 2-component vector instead of a 4-component vector, let's
map
each vector again to keep only the first two components. This uses array destructuring:See? I defined a lambda-function that takes a single argument, assumes it's an array (of numbers) with length 4, destructures the array, then returns a new array containing the first two elements. It can also work like:
Your sample data ends with a
;
, and that causes an empty string, so I'll filter that out as well:I'm gonna assume that you're working in Dar es-Salaam and not in Badajoz, so let's flip latitude and longitude (see https://macwright.com/lonlat/ as well) by swapping
x
andy
in([x,y])=>[y,x]
:Now head over to geojson.org and read RFC 7946 to see how GeoJSON data structures are specified. We already have the coordinates of a LineString geometry, so all it needs is some wrapping:
If your sample dataset is meant to be a polygon with an outer hull and no inner hulls (read OGC SFA to know what "hull" means in this context), then you can wrap the coordinates in an extra inline array and specify
Polygon
as the geometry type:Now you can feed it to
L.geoJson
, e.g.And finally, I'm gonna compact everything together just for the sake of it:
See a working example here. And please, please, don't copy-paste code blindly. Do read the linked documentation and resources, and understand what's going on.