cloudtec Stack: Coordinate Picker with open source
Looking up coordinates in a third-party map, copying them and pasting them blindly into the target system: we have replaced this detour with our own widget based on OpenLayers.
A feature that looks like little but involves a fair amount of detailed work: our Coordinate Picker, based on the open-source library OpenLayers. It is built directly into our platforms, so nobody has to leave the application when entering a location.
Why we built the Coordinate Picker
Many of our projects include a map: company locations, appointments per location, hikes, activities. For a point to appear on that map, its coordinates have to be entered, and that is exactly where the detour began. Search for the location in a map service, copy the coordinates, paste them into the form. Afterwards, the target system no longer showed whether the point was really correct. On top of that, we had to explain where the values come from and in which order they belong, so that longitude and latitude would not be swapped.
That is an unnecessary break in usability. Instead of explaining further, we built our own widget for selecting coordinates that sits directly in the form in our platforms.
What OpenLayers is
OpenLayers is an open-source JavaScript library for interactive maps in web applications. What makes it useful for us:
- Open source. Free to use, adapt and pass on, as long as the licence terms are complied with.
- Interactive maps. Multiple layers, markers, popups as well as zooming and panning are part of the library.
- Free choice of base map. OpenStreetMap, the federal swisstopo maps and other WMS, WMTS or XYZ sources can be integrated, plus your own layers.
- Geodata formats. Vector data such as GeoJSON and KML can be displayed directly; raster data is added via WMS or WMTS.
- Extensible. Custom functions, custom styling and adapted interactions are designed in, not retrofitted.
- Mobile-friendly. The maps work on different screen sizes and with touch input.
- Documentation and community. Extensive examples and an active developer community, as is usual with open source.
How the Coordinate Picker is implemented
From the outside, the function is simple: a widget with a map in which you can zoom and set a point. The point is saved and can be displayed again anywhere else in the application. There is a little more behind it.
Basics
For the map material we use the swisstopo pixel map. That limits the Coordinate Picker to Switzerland. For our projects that is the right scope; for other areas you swap the map source. The widget offers three interactions: zoom, reset and delete. In the background there are two input fields for longitude and latitude, which are filled as soon as the point is set.
The feature is implemented in standard JavaScript plus jQuery. Global settings define the zoom level and map section when it is opened. A bounding box limits the map to Swiss territory, so that no point can be set outside the map material; at the same time it keeps the aspect ratio when the size of the widget changes.
Then there are event listeners, for example on the click that sets the pin. The OpenLayers event is translated into a dedicated Coordinate Picker event, to which further actions can be attached, such as saving the point directly. When the widget is opened, mechanisms ensure that it does not initialise twice and that actions are not executed twice. Existing data is loaded and the buttons are shown accordingly.
Two coordinate systems
Two projections run side by side in the background. The swisstopo map delivers EPSG:3857, that is WGS 84 / Pseudo-Mercator, the usual Web Mercator grid for tiled maps. Towards the outside, however, the widget works with EPSG:4326: WGS 84 in longitude and latitude, the way GPS devices output it and the way we store the values. Conversion between the two is needed; OpenLayers comes with the function for it. If the projection is configured wrongly, the points end up off target, and debugging becomes tedious because the widget otherwise works normally.
Code
For anyone curious, and very much in the spirit of open source: the defaults and the conversion, which show the principle.
class CoordinatePicker extends EventTarget {
// global defaults
static options = {
center: [915000, 5910000], // center of switzerland
boundingBox: [670433, 5744676, 1162476, 6078756], // swiss extent in EPSG:3857
zoom: 14, // used when there is already a coordinate set
backgroundLayerUrl: 'https://wmts.geo.admin.ch/1.0.0/ch.swisstopo.pixelkarte-farbe/default/current/3857/{z}/{x}/{y}.jpeg',
};
// expects coordinates in GPS (WGS84, EPSG:4326) format
setData(long, lat) {
// set data on input fields
let inputs = this.getInputs();
inputs.long.val(long);
inputs.lat.val(lat);
inputs.long.trigger("change");
inputs.lat.trigger("change");
// convert to map coordinates and set the marker
let coords = ol.proj.transform([long, lat], 'EPSG:4326', 'EPSG:3857');
this.markerSource.clear();
this.markerSource.addFeature(new ol.Feature({
geometry: new ol.geom.Point(coords)
}));
}
}