Map animation using JavaScript
In this tutorial, you’ll learn how to create a simple javascript map animation. Together we will make a simple MapLibre GL JS map and animate it to fly around set places. So you can use it for example as an animated showcase of a map you made or as a pretty background component of your front page.
The basic things needed for completing this tutorial:
- MapTiler API key. Your MapTiler account access key is on your MapTiler Cloud account page.
- MapLibre GL JS. Javascript library for building web maps.
- Experience with javascript. You’ll need basic knowledge of javascript.
- Test environment or an online editor. Somewhere where are you going to test your code. You can use the web app you are already working on, or just test out the code in an online editor like Codepen.
Setting up
In the first step, we’ll make a simple map using MapLibre GL GJ on a single HTML page. Include the JavaScript and CSS files in the <head>
of your HTML file.
<script src='https://unpkg.com/maplibre-gl@1.15.2/dist/maplibre-gl.js'></script>
<link href='https://unpkg.com/maplibre-gl@1.15.2/dist/maplibre-gl.css' rel='stylesheet' />
Now we will add your javascript map. You can either put it in a standalone .js
file and include it or put it into <script>
tags at the bottom of the page. You will need your MapTiler API key, so your map style works.
var map = new maplibregl.Map({
container: 'map',
style: 'https://api.maptiler.com/maps/streets/style.json?key=YOUR_MAPTILER_API_KEY',
center: [10, 32], // starting position [lng, lat]
zoom: 2 // starting zoom
});
Now we will add a map container HTML and simple CSS styling. In <body>
of your page add the container.
<div class="map-wrap">
<div id="map"></div>
</div>
And simple CSS styling. For this tutorial, we will make a fullscreen map, but you can style the map to your needs. We use position: absolute
on the map itself and position: relative
on the wrap around the map for more possibilities in future styling if needed.
.map-wrap {
position: relative;
height: 100vh;
width: 100%;
}
#map{
position: absolute;
width: 100%;
height: 100%;
}
Now you should see your beautiful map.
Creating an animation
Now we will start coding the animation itself. Our goal is to make simple animation visiting several places. You can see an example at MapLibre.
Theory
We’ll store our places as objects in an array and create playAnimation()
function to play our animation.
We’ll iterate through our array of places and use flyTo function fly to each place in our array. Each place will have location data and animation time data. The time data has two values start
time and duration
time.
lng
, lat
, zoom
- These are the position values of the place.
bearing
- Rotation of the position from -180 to 180
pitch
- Angle of the place camera view from 0 to 60.
duration
- How long will it take to fly to that place in milliseconds.
start
- when will flying to this place start in milliseconds.
After calling playAnimation()
function, ‘timeline’ will be created and played. Each place has set setTimeout using the start
value, this means at the set start
value of the place, the map will fly to set coordinates. duration
will set how long will it take to go to that place. With this logic, the following must always apply.
Important!
The start
time value of the place has to be equal to or bigger than start
+ duration
of the place before. When equal the map will fly the place as soon as it hits the previous place.
Code
Let’s start with an array of the places.
var mapAnimation = [{
"lng": 15.44385629163537, // place1
"lat": 41.56277698075792,
"zoom": 3.4916772106200415,
"bearing": -52.8,
"pitch": 29.5,
"duration": 5000, // it will take 5 sec to get to place1
"start": 1000 // camera will fly to place1 1 sec after calling the function
},
{
"lng": 5.388541216098361, // place2
"lat": 45.57339756361293,
"zoom": 6.15010124013107,
"bearing": -12,
"pitch": 41.5,
"duration": 8000, // it will take 8 seconds to get to place2
"start": 6000 // start is equal to start + duration of place1 before so the camera will fly to place2 as soon as it arrive to place1 which is 6 seconds after calling the function
},
{
"lng": 10, // place3 has the same position values as the map initial position, so we can loop the animation
"lat": 32,
"zoom": 2,
"bearing": 0,
"pitch": 0,
"duration": 8000, // it will take 8 seconds to get to place3
"start": 15000 // start is 1 second bigger than start + duration of place2 so the camera will wait 1 second in the place2 before flying to place3
}
];
For the animation function. Using forEach
we iterate through the array setting timeout for each flyTo
function.
function playAnimation() {
mapAnimation.forEach((item, index) => {
setTimeout(() => {
map.flyTo({
duration: item.duration,
center: ([item.lng, item.lat]),
zoom: item.zoom,
bearing: item.bearing,
pitch: item.pitch,
essential: true,
});
}, item.start)
});
}
Initializing the animation
Now that everything is set up, you can just call the playAnimation()
function the way you need. For our tutorial. We will call the function on windows load and make the animation repeat. First, we will declare a variable which is the last point of the array.
var lastPoint = mapAnimation[mapAnimation.length - 1];
After that, we’ll add a line to call animation on window load, and set an interval function.
var lastPoint = mapAnimation[mapAnimation.length - 1];
window.onload = playAnimation,
setInterval(playAnimation, lastPoint.start + lastPoint.duration);
lastPoint.start + lastPoint.duration
equals the time it takes to finish the whole animation, so the setInterval function will call the playAnimation()
function and the end of the ‘timeline’ when the animation finishes. The last point should be the same position as the initial map values so the animation repeats smoothly.
Get your own animation data
Time values you choose for yourself depending on how long you want the animation to be as explained before. As for position values, we will add a simple set of inputs that will show the current position on the map. Add these lines to your map-wrap
:
<div class="lnglat">
Lng:
<input type="text" placeholder="Lng" id="lngTo">
Lat:
<input type="text" placeholder="Lat" id="latTo">
Zoom:
<input type="text" placeholder="Zoom" id="zoomTo">
Bearing:
<input type="text" placeholder="Bearing" id="bearTo">
Pitch:
<input type="text" placeholder="Pitch" id="pitchTo">
</div>
Now we will add basic styling:
.lnglat{
position: absolute;
z-index: 10;
padding: 10px;
background-color: white;
border-radius: 4px;
margin-top: 10px;
}
Now we will add js code under our map variable declaration which will change input values on map move.
map.on('move', function() {
document.getElementById('bearTo').value = map.getBearing()
document.getElementById('pitchTo').value = map.getPitch()
document.getElementById('zoomTo').value = map.getZoom()
document.getElementById('lngTo').value = map.getCenter()["lng"]
document.getElementById('latTo').value = map.getCenter()["lat"]
});
You can add this to a separate HTML page with a map just for your local testing to get the values you want.
Conclusion
Congratulations you have finished your simple fullscreen map with repeating camera animation MapLibre. You can explore more about MapLibre GL JS for your map in the MapLibre API reference.
Useful links
Related guides
- Automatically created API key
- Check if MapLibre GL JS is supported
- Coordinates API
- Dataset upload - formats and limits
- Difference between 256x256, 512x512, and HiDPI/Retina rasterized tiles
- Disputed borders on your maps
- Exported Tiles Multiplier
- Generalization in maps
- How are the tile requests cached in web browser?
- How MapTiler map tiles are Generated and Delivered