Vector maps for the web with MapLibre GL JS¶
Free
Starter
Standard
Professional
MapLibre GL JS is a robust, fully free and open-source library with 3D rendering, dynamic styling, and many other features. Stadia Maps is a founding member of the MapLibre project, which facilitates the ongoing development of MapLibre GL JS and other rendering technologies.
In this tutorial, you'll learn how to add a map to your webpage and fill it with markers representing your store locations, delivery trucks, or whatever else you're mapping.
Drawing a map¶
Let's dive in with some example code on how to use our vector tiles in MapLibre GL JS.
For local development on a web server at localhost
or 127.0.0.1
,
you can get started without any API keys or domain setup!
For mobile, backend, and non-local web development, you'll need either domain auth or an API key. If you don't already have a Stadia Maps account, sign up for a free to get started.
Domain-based authentication
Domain-based authentication is the easiest form of authentication for production web apps. No additional application code is required, and you don't need to worry about anyone scraping your API keys. We recommend this for most browser-based applications.
- Sign in to the client dashboard.
- Click "Manage Properties."
- Under "Authentication Configuration," click the button to add your domain.
API key authentication
Authenticating requests via API key¶
You can authenticate your requests by adding an API key to the query string or HTTP header.
The simplest is to add a query string parameter api_key=YOUR-API-KEY
to your request URL.
For example, to access the /tz/lookup
API endpoint, your request URL might look like this.
https://api.stadiamaps.com/tz/lookup/v1?lat=59.43696&lng=24.75357&api_key=YOUR-API-KEY
You can also use an Authorization
HTTP header instead of a query string
as shown below.
Don't forget the Stadia-Auth
prefix!
Authorization: Stadia-Auth YOUR-API-KEY
How to get an API key¶
Don't have an API key yet? Follow these easy steps!
- Sign in to the client dashboard. (If you don't have an account yet, sign up for free; no credit card required!)
- Click "Manage Properties."
- If you have more than one property (ex: for several websites or apps), make sure you have selected the correct property from the dropdown at the top of the page.
- Under "Authentication Configuration," you can generate, view or revoke your API key.
Video: How to generate your API key¶
To make experimenting even easier, we've packaged the example code as a JSFiddle playground. Click the "Try it in JSFiddle" button to start experimenting right from your web browser.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Vector Map Demo</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script type="text/javascript" src="//unpkg.com/maplibre-gl@4.0.2/dist/maplibre-gl.js"></script>
<link href="//unpkg.com/maplibre-gl@4.0.2/dist/maplibre-gl.css" rel="stylesheet" />
<style type="text/css">
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<script type="text/javascript">
var map = new maplibregl.Map({
container: 'map',
style: 'https://tiles.stadiamaps.com/styles/alidade_smooth.json', // Style URL; see our documentation for more options
center: [12, 53], // Initial focus coordinate
zoom: 4
});
// MapLibre GL JS does not handle RTL text by default,
// so we recommend adding this dependency to fully support RTL rendering if your style includes RTL text
maplibregl.setRTLTextPlugin('https://unpkg.com/@mapbox/mapbox-gl-rtl-text@0.2.3/mapbox-gl-rtl-text.min.js');
// Add zoom and rotation controls to the map.
map.addControl(new maplibregl.NavigationControl());
</script>
</body>
</html>
Code Walkthrough¶
First, we'll add some opening HTML content that will make the document standard compliant:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<title>Vector Map Demo</title>
Next, we'll include the MapLibre library files:
<script type="text/javascript" src="//unpkg.com/maplibre-gl@3.6.2/dist/maplibre-gl.js"></script>
<link href="//unpkg.com/maplibre-gl@3.6.2/dist/maplibre-gl.css" rel="stylesheet" />
Now, we'll add CSS to handle the size of the body, the map ID, and then close the <head>
tag:
<style type="text/css">
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
</style>
</head>
With the <head>
details in, we can now add the body for our page. This is where we'll create the map element:
<body>
<div id="map"></div>
Next, we'll add the JavaScript for:
- initializing the map, specifying the
container
,style
,center
, andzoom
:
<script type="text/javascript">
var map = new maplibregl.Map({
container: 'map',
style: 'https://tiles.stadiamaps.com/styles/alidade_smooth.json', // Style URL; see our documentation for more options
center: [12, 53], // Initial focus coordinate
zoom: 4
});
- adding RTL support:
// MapLibre GL JS does not handle RTL text by default,
// so we recommend adding this dependency to fully support RTL rendering if your style includes RTL text
maplibregl.setRTLTextPlugin('https://unpkg.com/@mapbox/mapbox-gl-rtl-text@0.2.3/mapbox-gl-rtl-text.min.js');
- and adding navigation controls:
// Add zoom and rotation controls to the map.
map.addControl(new maplibregl.NavigationControl());
</script>
Finally, we'll close up the <body>
and <html>
tags:
</body>
</html>
And that's it. Congratulations.
All the code, put together, will match the same as the code at the start of this section.
Adding marker pins to the map¶
Once you have a map, you probably want to add some markers to it! The example below can serve as a starting point,
and covers all the main components. You can easily substitute your own branded markers, style the popup (or remove it),
etc. Please refer to the Marker
documentation
for additional details.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Vector Map Demo</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script type="text/javascript" src="//unpkg.com/maplibre-gl@4.0.2/dist/maplibre-gl.js"></script>
<link href="//unpkg.com/maplibre-gl@4.0.2/dist/maplibre-gl.css" rel="stylesheet" />
<style type="text/css">
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
/* We recommend using an icon that is 2x the intended display size, so that it renders nicely on retina displays. */
.marker {
/* The following icon is owned by Stadia Maps. While you maintain an account with us, we grant you royalty-free use of
* this image when displayed on our maps.
*/
background-image: url('data:image/png;base64,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');
background-size: cover;
width: 27px;
height: 42px;
cursor: pointer;
}
</style>
</head>
<body>
<div id="map"></div>
<script type="text/javascript">
var map = new maplibregl.Map({
container: 'map',
style: 'https://tiles.stadiamaps.com/styles/alidade_smooth_dark.json', // Style URL; see our documentation for more options
center: [6.942373, 50.332852], // Initial focus coordinate (long, lat)
zoom: 14
});
// Add zoom and rotation controls to the map.
map.addControl(new maplibregl.NavigationControl());
// First, we define our marker locations. You can use whatever format you want when
// working with custom markers, but we have chosen to use GeoJSON for this example, as
// a lot of geospatial data comes in this form. If you have a lot of data, you may want to
// put it in another file that is loaded separately.
var markerCollection = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Point",
// NOTE: in GeoJSON notation, LONGITUDE comes first. GeoJSON
// uses x, y coordinate notation
"coordinates": [6.940046, 50.333947]
},
"properties": {
"title": "Nürburgring"
}
}]
};
// Next, we can add markers to the map
markerCollection.features.forEach(function(point) {
// Since these are HTML markers, we create a DOM element first, which we will later
// pass to the Marker constructor.
var elem = document.createElement('div');
elem.className = 'marker';
// Now, we construct a marker and set it's coordinates from the GeoJSON. Note the coordinate order.
var marker = new maplibregl.Marker(elem);
marker.setLngLat(point.geometry.coordinates);
// You can also create a popup that gets shown when you click on a marker. You can style this using
// CSS as well if you so desire. A minimal example is shown. The offset will depend on the height of your image.
var popup = new maplibregl.Popup({ offset: 24, closeButton: false });
popup.setHTML('<div>' + point.properties.title + '</div>');
// Set the marker's popup.
marker.setPopup(popup);
// Finally, we add the marker to the map.
marker.addTo(map);
});
</script>
</body>
</html>
Code Walkthrough¶
To set up the page, we'll need the same initial code we used to draw the map:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Vector Map Demo</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script type="text/javascript" src="//unpkg.com/maplibre-gl@4.0.2/dist/maplibre-gl.js"></script>
<link href="//unpkg.com/maplibre-gl@4.0.2/dist/maplibre-gl.css" rel="stylesheet" />
<style type="text/css">
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
Next, we'll add the marker
class, along with a base64 blob of the image we want to display for the marker:
/* We recommend using an icon that is 2x the intended display size, so that it renders nicely on retina displays. */
.marker {
/* The following icon is owned by Stadia Maps. While you maintain an account with us, we grant you royalty-free use of
* this image when displayed on our maps.
*/
background-image: url('data:image/png;base64,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');
background-size: cover;
width: 27px;
height: 42px;
cursor: pointer;
}
Then we'll close up the <style>
and <head>
tag:
</style>
</head>
Next, we'll add the <body>
tag and map element:
<body>
<div id="map"></div>
And then we'll add the JavaScript to create the map, style
and center
it, along with setting the zoom
level and
controls:
<script type="text/javascript">
var map = new maplibregl.Map({
container: 'map',
style: 'https://tiles.stadiamaps.com/styles/alidade_smooth.json', // Style URL; see our documentation for more options
center: [6.942373, 50.332852], // Initial focus coordinate (long, lat)
zoom: 14
});
// Add zoom and rotation controls to the map.
map.addControl(new maplibregl.NavigationControl());
With the map
element created, we can now create our markerCollection
object, which will store the coordinates for
our markers as GeoJSON in this example:
// You can use whatever format you want when working with custom markers, but we have chosen
// to use GeoJSON for this example, as a lot of geospatial data comes in this form. If you
// have a lot of data, you may want to put it in another file that is loaded separately.
var markerCollection = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Point",
// NOTE: in GeoJSON notation, LONGITUDE comes first. GeoJSON
// uses x, y coordinate notation
"coordinates": [6.940046, 50.333947]
},
"properties": {
"title": "Nürburgring"
}
}]
};
Next, we'll write a function to handle the market components:
- iterating through each feature in the
markerCollection
:
// Next, we can add markers to the map
markerCollection.features.forEach(function(point) {
// Since these are HTML markers, we create a DOM element first, which we will later
// pass to the Marker constructor.
var elem = document.createElement('div');
elem.className = 'marker';
- constructing a marker and setting its coordinates from the GeoJSON object we created earlier:
var marker = new maplibregl.Marker(elem);
marker.setLngLat(point.geometry.coordinates);
- adding a popup that will display the title we defined earlier:
Note
The offset value will depend on the height of your image.
var popup = new maplibregl.Popup({ offset: 24, closeButton: false });
popup.setHTML('<div>' + point.properties.title + '</div>');
// Set the marker's popup.
marker.setPopup(popup);
- and then adding the marker to the map:
// Finally, we add the marker to the map.
marker.addTo(map);
});
Finally, we'll close up the <script>
, <body>
, and <html>
tags:
</script>
</body>
</html>
And that's it. Congratulations.
All the code, put together, will match the code at the start of this section.
Next Steps¶
This tutorial doesn't even begin to show what's possible with MapLibre GL JS. Now that you have a map and some markers, you can get inspiration from what others have built at the MapLibre GL JS Examples page. They have in-depth examples covering everything from GeoJSON lines to interactive time sliders. And don't forget to check out the plugins and the rest of the MapLibre GL JS documentation either.
Once you're ready to move beyond localhost
testing, sign up for a free Stadia Maps account,
and we'll walk through the next steps.