Download or view mapTimezones.frink in plain text format
/** This program draws a map of the world's timezones. It requires the GeoJSON
file from:
https://github.com/evansiroky/timezone-boundary-builder/releases
The GeoJSON format is defined in RFC 7946:
https://tools.ietf.org/html/rfc7946
*/
// This allows us to attach visualvm for profiling
input=input["Press start", ""]
// The location you've extracted the file to:
s1 = now[]
s = now[]
println["Reading file."]
f = read["file:/home/eliasen/builds/timezones/combined-with-oceans.json"]
e = now[]
println["Finished in " + format[e-s, "s", 1] + "\n"]
s = now[]
b = parseJSON[f]
println["JSON parsed."]
e = now[]
println["Finished in " + format[e-s, "s", 1] + "\n"]
// The "type" key indicates what the top-level container is, hopefully a
// FeatureCollection
filetype = b@"type"
println["This file contains a $filetype"]
g = new graphics
g.font["SansSerif", 2]
if filetype == "FeatureCollection"
plotFeatureCollection[b, g]
else
if filetype == "Feature"
plotFeature[b, g]
println["Writing svg"]
s=now[]
g.write["timezones.svg", 1920, undef]
e=now[]
println["Finished in " + format[e-s, "s", 1] + "\n"]
println["Writing svgz"]
s=now[]
g.write["timezones.svgz", 1920, undef]
e=now[]
println["Finished in " + format[e-s, "s", 1] + "\n"]
println["Writing HTML5"]
s=now[]
g.write["timezones.html", 1920, undef]
e=now[]
println["Finished in " + format[e-s, "s", 1] + "\n"]
println["Writing png"]
s=now[]
g.write["timezones.png", 1920, undef]
e=now[]
println["Finished in " + format[e-s, "s", 1] + "\n"]
e1 = now[]
println["Total time: " + format[e1-s1, "s", 1] + "\n"]
g.show[]
/** This plots a FeatureCollection, whose "features" key should contain an
array of Feature objects. */
plotFeatureCollection[fc, g is graphics] :=
{
for feature = fc@"features"
plotFeature[feature, g]
}
/** This plots a Feature object. A Feature has a "properties" key that
contains a dictionary that describes stuff (in this case, the "tzid" field
may be the only member,) and a key called "geometry" which contains the
object (in this case, a Polygon or MultiPolygon.)
*/
plotFeature[feature, g is graphics] :=
{
for [key, value] = feature
{
print["$key:\t"]
if key == "type" // This is a string, hopefully "Feature"
print[value]
if key == "properties" // This contains a dictionary of key-value
// pairs. We most likely want the "tzid" pair
print["tzid: " + value@"tzid"]
g.color[randomFloat[0,1], randomFloat[0,1], randomFloat[0,1]]
// A Feature has a key called "geometry" which describes the type
if key == "geometry"
{
type = value@"type"
print[type]
if (type == "Polygon")
{
coordinates = value@"coordinates"
g.add[makePolygon[coordinates]]
} else
if (type == "MultiPolygon")
{
coordinates = value@"coordinates"
g.add[makeMultiPolygon[coordinates]]
} else
println["Unknown type $type"]
}
println[]
}
println[]
}
/** Make a "polygon", given an object containing a GeoJSON coordinates array.
In the GeoJSON specification, a "polygon" may actually be an array of
concentric disconnected polygons with the first one being a surrounding
polygon and the latter ones being "holes" in this object. If there are
no holes, then this is returned as a Polygon object, otherwise as a
GeneralPath.
*/
makePolygon[coordinates] :=
{
length = length[coordinates]
// If length == 1, this can be a simple polygon with no holes
if length == 1
{
ret = new filledPolygon
for [x,y] = coordinates@0
ret.addPoint[x, -y]
return ret
}
// Otherwise, this is a complex GeneralPath with holes
ret = new filledGeneralPath
outer = coordinates@0
for [x, y] = outer // Draw the outer polygon
ret.addPoint[x, -y]
ret.close[]
for inner = slice[coordinates, 1, undef] // Draw all the inner polygons
{
for [x, y] = inner
ret.addPoint[x, -y]
ret.close[]
}
return ret
}
// This draws a set of polygons and returns it as a graphics.
makeMultiPolygon[coordinates] :=
{
g = new graphics
for polygon = coordinates
g.add[makePolygon[polygon]]
return g
}
Download or view mapTimezones.frink in plain text format
This is a program written in the programming language Frink.
For more information, view the Frink
Documentation or see More Sample Frink Programs.
Alan Eliasen was born 20217 days, 23 hours, 50 minutes ago.