Geodata in ABS
==============
The Model API of ABS lets us display information in various ways. This
example shows how to display geo-annotated ABS data on a map. To
display the map in a browser, we use `OpenStreetmap
`__ via the `Leaflet
`__ library.
The complete code for this example is at
``__.
In OpenStreetmap, coordinates are expressed as a ``(lat, long)`` pair
of floating point numbers. We model map data as ``MapData(Float lat,
Float long, String description)``, which is then returned from the
Model API. The complete code of the ABS part is as follows::
module MapObjects;
data MapData = MapData(Float lat, Float long, String description);
interface OMap {
[HTTPCallable] Pair getInitialCoordinates();
[HTTPCallable] List getMapObjects();
}
class OMap implements OMap {
Pair getInitialCoordinates() {
return Pair(59.90, 10.73);
}
List getMapObjects() {
return list[MapData(59.91115, 10.7357, "City Hall"),
MapData(59.90758, 10.75197, "Opera House")];
}
}
{
[HTTPName: "map"] OMap m = new OMap();
}
Accessing and displaying coordinates
------------------------------------
When the running model is accessed from a browser, the ``createMap``
function in the model's `index.html
`__
file is called. This function creates a map, sets its initial location
according to the ``getInitialCoordinates`` method (Lines 6-12), then
adds the objects returned by the ``getMapObjects`` method (Lines
14-17). Both of these ABS methods are called from JavaScript code in
``createMap`` (Lines 2, 3):
.. code:: javascript
function createMap() {
Promise.all([fetch("/call/map/getInitialCoordinates"),
fetch("/call/map/getMapObjects")])
.then((values) => values.map(p => p.json())).then((p) => Promise.all(p))
.then(([coords, objects]) => {
var mymap = L.map('mapid').setView([coords.result.fst, coords.result.snd], 13);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© OpenStreetMap contributors'
}).addTo(mymap);
L.control.scale().addTo(mymap);
objects.result.forEach(item =>
L.marker([item.lat, item.long])
.addTo(mymap)
.bindPopup(item.description));
var popup = L.popup();
function onMapClick(e) {
popup.setLatLng(e.latlng)
.setContent("You clicked the map at " + e.latlng.toString())
.openOn(mymap);
}
mymap.on('click', onMapClick);
});
}
Running the example
-------------------
Because the model includes a custom html page and support library, the
compiler needs to run with the ``--modelapi-index-file`` and
``--modelapi-static-dir`` arguments. See the `Makefile
`__
for the commands to compile and run the example on the Erlang or Java
backend.
After starting the model, the map can be accessed at
``http://localhost:8080``.
.. figure:: images/geo-abs.png
:alt: A map of Oslo with two points of interest
A map of Oslo with two points of interest