Map Loading... πΊοΈππ¨
Experimenting with different vector map style loading times using maplibre-gl.
Introduction
When using a map on a digital device, it is important that it is fast to load and the map interactions are seamlessly smooth. A fast loading map will go by unnoticed as “everything works” leading to a natural feeling experience. A slow loading map will get in the way of a good user experience, leading to frustration, grief and a bad taste in the mouth.
Vector maps are being used more and more on the web. They offer a faster and more interactive experience and more ways of being styled.
Vector maps use vector data, made up of points, lines and polygons with accompanying meta-data. This is downloaded to the device and the map you end up seeing on the screen, is as a result of rendering on the client side and certain styling instructions.
Vector maps are the opposite of raster maps, which are made up of pixel data pre-rendered on a server. Raster maps are harder to manipulate and style.
The best resource out there to to have a refresh on web maps is mapschool.io. It explains the difference between raster and vector maps and much more.
I am using maplibre-gl
, which is a vector map library in a hobby project and interested in finding out which map style is the fastest to load.
Map drawing 101
A vector map library needs a recipe to draw a map on the screen. The recipe will have instructions telling the mapping library where to request the vector data from and how to render that data to the screen. Rendering instructions include what parts of the data to draw, what colors to use and what order to draw the layers of data in.
When you pan and zoom to a specific part of a vector map, the library will know based on this recipe, where to request the body of data that should fill up the screen and how to style it.
style
document, which is usually a json file conforming to a specification (in my case the Maplibre style spec).A good designer aka a cartograpaher, will design a style in a way that it shows off the best parts of the data with certain balance of space and color, producing something that looks appealing and allows easy reading of the data.
What makes things fast or slow?
The time taken to display a map on the screen will depend on where the data comes from and how complex the rendering instructions are.
It makes sense that a style that is simple and requests a little data from somewhere close to the user will load faster than a style that is complex and requests a lot of data from somewhere far away from the user.
A Peek inside a Style document
Here is a taste of a style Γ la MapTiler Basic Light**
(note: I have omitted most parts to simplify the example)
|
|
It a very simple style that only shows a few of the features you would expect of a map. It has a background color, grass and wood areas, water, buildings and some text.
There are two sources of data, one for the map data and one for the attribution. This informs the library where to request data from the tile server with address https://api.maptiler.com/tiles/v3/tiles.json?key={YOUR_API_KEY}
.
The layers key is where the rendering instructions are. Each layer has an id, a type, a source (in our case it is always the single openmaptiles
source) and some paint instructions.
The background gets loaded, polygons of grass gets drawn with a opaque green, water gets drawn in blue, but not when it goes through a tunnel, building footprints rise up.
Paint instructions can get quite complex, and contain many conditional rules and transformations. Things that can be controlled are the size lines, opacity of fills and the font of the text.
Where does the actual vector data get served from?
See the sources
key in the above style document. This is where the vector data is served from. The data is served in a format called vector tiles. These are small chunks of data that are ready to be drawn on the screen. The data is normally served in a format that is easy to draw and easy to style.
Mapbox created the Mapbox Vector Tile Specification.
The data is encoded in a format called Protocol Buffers. This is a fast to parse and is easy to compress binary format. This is why it is used for vector tiles.
There are many tools out there to generate and serve vector tiles. The Awesome vector tiles
The ideal place to get the data is the clients device storage. This is fast as the data is ready to be used straight away without requesting and downloading it over a internet connection. But this is not practical for most use cases.
The next best thing is a server vector tile server. This server can be hosted by a tile service provider, or it can be hosted by yourself. There are lots of tools out there to roll your own solution. The Awesome vector tiles repo on github is a good place to start.
Most people will use a third party provider for ease and other reasons instead of DIYing. These providers will have servers all over the world that will serve the data to the user close to where they are.
Where can you get one of these style recipe from?
There are many different places to get vector map styles. Providers offer them. Some of them are free, some of them are paid. Some of them are open source, some of them are closed source. Some of them result in a fast loading experience, some do not.
Different providers offer different styles and it is not always clear which one is the fastest, the Usain Bolt of map styles.
It is also possible to write a custom style, and there are many tools out there that can help you. Maplibre-gl has a style spec that you can use to write your own style. MapTiler has a online style editor that you can use to create your own style.
The Experiment
I used playwright, a browser automation library to launch a chromium browser, initialize a map with a style and time how long it took for the relevant loaded event to fire. This was done for a number of different styles.
The experiment was run on my local machine (A 10 year old HP Pavilion) with a 50mbps internet connection somewhere in Germany.
All the code is available in this repo if you want to replicate the experiment.
Note: Your mileage may vary depending on your hardware and internet connection.
Styles tested
The Open Street Map Wiki lists different vector tile providers. I tested the following:
Code used to profile the styles
|
|
All code is available in the mapStyleProfile github repository.
The Results
Provider - Style | Time to load (ms) |
---|---|
StadiaMaps - Stamen Watercolor | 709 |
Maptiler - Dataviz | 1702 |
Maptiler - Toner | 2156 |
StadiaMaps - Alidade Smooth | 2181 |
MapTiler - Basic | 2324 |
Maptiler - Satellite | 2368 |
StadiaMaps - Stamen Toner | 2573 |
MapTiler - Backdrop | 2692 |
Maptiler - Streets | 2694 |
StadiaMaps - OSM Bright | 2848 |
Maptiler - OpenStreetMap | 2954 |
StadiaMaps - Stadia Outdoors | 2990 |
Maptiler - Bright | 3005 |
StadiaMaps - Alidade Smooth Dark | 3169 |
Maptiler - Ocean | 3679 |
Maptiler - Outdoor | 4030 |
Maptiler - Landscape | 4513 |
Maptiler - Topo | 4629 |
StadiaMaps - Stamen Terrain | 5670 |
Maptiler - Winter | 5827 |
Conclusion
Now there are some numbers to quantify the different map styles speed.
Remember speed isn’t everything, and a good map experience is a combination of many things. A fast loading map is just one part of the puzzle, along with space and color, compromises may have to be made to get the best overall experience.
Don’t just take my word for it, test styles out yourself online now
I made a online tool that lets you paste a style url into it and it will time how long it takes to load the map.
All source code is available in the same github repository.
Future ideas
This was a simple experiment to get some numbers on the different map styles, only looking at two providers.
There are a few things that could be done to improve the experiment:
- Add more styles from different providers to get a better idea of the landscape.
- Profile the different parts of the map loading process to break down ingload time
- Add more “real world” interactions to the experiment and see how the styles perform under different conditions.
- Set up a github action to run the experiment on pull requests and provided a central place to see the results.