Building web map applications with OpenLayers

Anders Innovations
5 min readMay 25, 2021

By Mingfeng Yu

When it comes to maps on the web, OpenLayers stands out with its feature-packed capabilities and wide-range support of different data sources, be it geo-referenced images, vector tiles, or open and proprietary vector data formats. With its powerful API, OpenLayers makes it easy to put up a simple web map application with little effort. At the same time, OpenLayers also provides more advanced tools that help you accomplish more complex requirements.

The following steps will show you how to create a simple web map with OpenLayers. We will also walk you through setting up a simple dev environment, which requires node to be installed. The data we are using is 2019 Finland road traffic accidents from Statistics Finland and OpenStreetMap background maps.

You can find the code for the example below at Github, and there is also a demo available for the application.

Let’s start by creating the application folder and let’s name it traffic-accidents:

mkdir traffic-accidents && cd traffic-accidents

And initialize the folder with npm:

npm init

Then install OpenLayers and a bundler tool (OpenLayers suggests parcel-bundler, but you can choose your own preferred tool)

npm install ol && npm install --save-dev parcel-bundler

Now let’s create an index.js file that will contain our application code. As a simple starting point, let's first add a OpenStreetMap background map. Note that OpenLayers provides a wrapper class OSM to make it easier to use OpenStreetMap in your application.

import 'ol/ol.css';
import {Map, View} from 'ol';
import TileLayer from 'ol/layer/Tile';
import OSM from 'ol/source/OSM';

const map = new Map({
target: 'map',
layers: [
new TileLayer({
source: new OSM()
})
],
view: new View({
center: [0, 0],
zoom: 0
})
});

And now let’s create an index.html file that will use the above script. For the sake of simplicity, we embed the css styling in the html file.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Finland Road Traffic Accidents</title>
<style>
html, body, #map {
height: 100%;
width: 100%;
margin: 0;
}
</style>
</head>
<body>
<div id="map"></div>
<script src="./index.js"></script>
</body>
</html>

Now let’s add two scripts items to package.json so that we can run and build the application. The whole package.json will look like this:

{
"name": "traffic-accidents",
"version": "1.0.0",
"description": "Finland road traffic accidents map",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "parcel index.html",
"build": "parcel build --public-url . index.html"
},
"author": "Mingfeng Yu <mingfeng.yu@anders.com>",
"license": "ISC",
"dependencies": {
"ol": "^6.5.0"
},
"devDependencies": {
"parcel-bundler": "^1.12.5"
}
}

By running the following command and open http://localhost:1234/ in your browser, you will see a full-screen map displayed.

npm run start

Now let’s add road traffic accident data to the map. Statistics Finland publishes the road traffic accidents data as open data (CC BY 4.0 license) through Web Feature Service (WFS). WFS is an Open Geospatial Consortium (OGC) standard that defines the operations to manipulate information about geographic features (point, lines, and polygons). We are not going to dive deep into WFS in this article, but you can find more information about WFS here.

OpenLayers uses vector layers to handle vector data sources, and we use the bbox loading strategy (based on current map view extent) to better optimize the performance. And since the data is located in Finland, let’s center the map to Finland also. The whole index.js file looks like this now:

import { Map, View } from 'ol';
import GeoJSON from 'ol/format/GeoJSON';
import TileLayer from 'ol/layer/Tile';
import VectorLayer from 'ol/layer/Vector';
import { bbox as bboxStrategy } from 'ol/loadingstrategy';
import 'ol/ol.css';
import OSM from 'ol/source/OSM';
import VectorSource from 'ol/source/Vector';

// creating vector source and vector layer that consumes WFS features
const trafficAccidentsSource = new VectorSource({
format: new GeoJSON(),
url: (extent) => {
return (
'https://geo.stat.fi/geoserver/tieliikenne/wfs?service=WFS&' +
'version=1.1.0&request=GetFeature&typename=tieliikenne:tieliikenne_2019&' +
'outputFormat=application/json&srsname=EPSG:3857&' +
'bbox=' +
extent.join(',') +
',EPSG:3857'
);
},
strategy: bboxStrategy,
});

const trafficAccidentsLayer = new VectorLayer({
source: trafficAccidentsSource,
});

// create OpenStreetMap layer
const osmLayer = new TileLayer({
source: new OSM(),
});

// create map
const map = new Map({
target: 'map',
layers: [osmLayer, trafficAccidentsLayer],
view: new View({
center: [2975296.098311, 9588260.828093],
zoom: 5,
}),
});

Rerun the application, and you can see road traffic accidents displayed as circles on the map. Those circles are the places where road traffic accidents took place. You can already see some patterns from the circles, but let’s make it more evident by creating a heat map for the traffic accident data.

...

const trafficAccidentsHeatmapLayer = new HeatmapLayer({
source: trafficAccidentsSource,
blur: 12,
radius: 8,
});

const map = new Map({
target: 'map',
layers: [osmLayer, trafficAccidentsHeatmapLayer],
view: new View({
center: [2975296.098311, 9588260.828093],
zoom: 5,
}),
});

...

Rerun the application, and you can see a heat-map that reveals the high-risk areas for road traffic accidents. This kind of map can provide insights and facilitate decision-making for stakeholders.

That's all required to get a simple web map application running. The example above only covers the very basics of OpenLayers. There's a myriad of controls, interactions, layers and formats that we haven't even mentioned. If you want to learn more about OpenLayers, you can find more information on their website. Also, don't forget to follow us, as we deliver more exciting content to you.

--

--

Anders Innovations

Anders is a Finnish IT company, whose mission is sustainable software development with the greatest colleagues of all time.