Geotagging is easy. OpenLayers
12 min read January 14, 2025 #openlayers #javascript #mapsI've always found it tedious and difficult to display stuff on maps. To understand the API, you need examples that aren't always accessible because they require a token to display and interact with the map. The token has to be obtained and hidden from other people's eyes.
But then I thought, why do I need proprietary Google Maps when there is OpenStreetMaps? I searched for APIs, came across OpenLayers, opened examples and was surprised by their number and simplicity.
In this series of articles, we will explore OpenLayers, display photo thumbnails on a map, add clustering, and finally create a Rust application that collects geodata and thumbnails from photos and generates a map.
Layer 1. OpenStreetMap
Let's start with the first layer, the map. We'll use OpenStreetMap since it doesn't require any tokens.
Let's add the OpenLayers library and its styles to HTML:
Then, create an OpenStreetMap layer and a map object in JS:
;
;
In the map parameters, in target
we need to specify the id of the HTML element, list the layers in layers
, and customize the view
.
The code is very simple, except for this line:
center: , 'EPSG:4326', 'EPSG:3857',
Here I'm centering the map on Europe, namely 47° North latitude and 20° East longitude from EPSG:4326 projection to the web map standard - EPSG:385 projection. Every time you work with the GPS coordinate system, you'll have to do this conversion.
That's enough to display the map:
Layer 2. Photo thumbnails
Let's add a container for the marker objects. This will be an ol.source.Vector:
;
Let's create a layer with thumbnails:
;
// -- icon styles --
;
This layer will take thumbnails from the photosSource
vector and display them in the style defined in the thumbStyle
function.
Styling is needed to specify what exactly we'll draw and with what size. In this case, we will draw icons with a certain URL taken from feature
.
;
// ..
cache = new ol.style.Style
What isfeature
? ol.Feature is a geographic object displayed on the map (position, area, territory). It can be linked to a layer and contains attributes, styles, and geometry.
To display a photo, we need the following data:
- Marker coordinates.
- Image URL (optional, you can just draw circles).
- Details (optional) that will be displayed when the marker is selected.
We'll handle data collection in the next articles, but for now, let's look at an example:
This is a JSON array with one element. We'll load it directly from the code:
;
;
In handleMapDataLoaded
we iterate through the loaded features, create an ol.Feature
object, transform the coordinates into the map projection and set the geometry to a single point ol.geom.Point
. Then add the object to photosSource
.
All that's left is to add a layer to the map:
Demo
Details on click
Small thumbnails aren't very convenient to look at, so let's collect a bit more data. For example, the camera model, original photo URL, and creation date:
;
When clicking on a photo on the map, we'll show the details in a separate panel:
Using ol.interaction.Select we can add selection handlers for the map objects and define their styles:
;
thumbSelector;
The selection will be configured for layerThumbs
layer, and the scale of the selected photo will be slightly increased.
Now, let's add selection and deselection handlers:
;
'add', ;
'remove',;
When a marker is selected, we insert HTML to #photo-details
with the replaced parameters listed in the array const keys = ['name', 'preview', 'date', 'lat', 'lon', 'make', 'model', 'path'];
.
Demo
As you can see, if there are a lot of photos, they overlap, so we'll add clustering in the next article.