Persist sources and layers when switching a map's base style
This example shows how to persist sources and layers that were added via code when changing a map's style. Since there is no basemap in Mapbox GL JS, developers often instantiate a map with a Mapbox core style or a custom style created in Mapbox Studio, and then use addSource()
and addLayer()
to add additional data and layers.
Changing the style (For example switching from Streets to Satellite) is possible with setStyle()
, but any sources and layers added after the initial load are lost. This example listens for the style.load
event to trigger re-adding these additional sources and layers.
The base-style-switching menu comes from the example Change a map's style, while the GeoJSON and location selection comes from the example Add a line to a map using a GeoJSON source.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Persist sources and layers when switching a map's base style</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<link href="https://api.mapbox.com/mapbox-gl-js/v3.7.0/mapbox-gl.css" rel="stylesheet">
<script src="https://api.mapbox.com/mapbox-gl-js/v3.7.0/mapbox-gl.js"></script>
<style>
body { margin: 0; padding: 0; }
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
</style>
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<style>
#menu {
position: absolute;
background: #efefef;
padding: 10px;
font-family: 'Open Sans', sans-serif;
}
</style>
<div id="map"></div>
<div id="menu">
<input id="satellite-streets-v12" type="radio" name="rtoggle" value="satellite" checked="checked">
<!-- See a list of Mapbox-hosted public styles at -->
<!-- https://docs.mapbox.com/api/maps/styles/#mapbox-styles -->
<label for="satellite-streets-v12">satellite streets</label>
<input id="light-v11" type="radio" name="rtoggle" value="light">
<label for="light-v11">light</label>
<input id="dark-v11" type="radio" name="rtoggle" value="dark">
<label for="dark-v11">dark</label>
<input id="streets-v12" type="radio" name="rtoggle" value="streets">
<label for="streets-v12">streets</label>
<input id="outdoors-v12" type="radio" name="rtoggle" value="outdoors">
<label for="outdoors-v12">outdoors</label>
</div>
<script>
// TO MAKE THE MAP APPEAR YOU MUST
// ADD YOUR ACCESS TOKEN FROM
// https://account.mapbox.com
mapboxgl.accessToken = 'YOUR_MAPBOX_ACCESS_TOKEN';
const map = new mapboxgl.Map({
container: 'map', // container ID
// Choose from Mapbox's core styles, or make your own style with Mapbox Studio
style: 'mapbox://styles/mapbox/satellite-streets-v12', // style URL
center: [-122.486052, 37.830348],
zoom: 14,
projection: 'mercator'
});
// Add GeoJSON source and layer
function addAdditionalSourceAndLayer() {
map.addSource('routeSource', {
'type': 'geojson',
'data': {
'type': 'Feature',
'properties': {},
'geometry': {
'type': 'LineString',
'coordinates': [
[-122.48369693756104, 37.83381888486939],
[-122.48348236083984, 37.83317489144141],
[-122.48339653015138, 37.83270036637107],
[-122.48356819152832, 37.832056363179625],
[-122.48404026031496, 37.83114119107971],
[-122.48404026031496, 37.83049717427869],
[-122.48348236083984, 37.829920943955045],
[-122.48356819152832, 37.82954808664175],
[-122.48507022857666, 37.82944639795659],
[-122.48610019683838, 37.82880236636284],
[-122.48695850372314, 37.82931081282506],
[-122.48700141906738, 37.83080223556934],
[-122.48751640319824, 37.83168351665737],
[-122.48803138732912, 37.832158048267786],
[-122.48888969421387, 37.83297152392784],
[-122.48987674713133, 37.83263257682617],
[-122.49043464660643, 37.832937629287755],
[-122.49125003814696, 37.832429207817725],
[-122.49163627624512, 37.832564787218985],
[-122.49223709106445, 37.83337825839438],
[-122.49378204345702, 37.83368330777276]
]
}
}
});
map.addLayer({
'id': 'routeLayer',
'type': 'line',
'source': 'routeSource',
'layout': {
'line-join': 'round',
'line-cap': 'round'
},
'paint': {
'line-color': '#33bb6a',
'line-width': 8
}
});
}
// Add source and layer whenever base style is loaded
map.on('style.load', () => {
addAdditionalSourceAndLayer();
});
const layerList = document.getElementById('menu');
const inputs = layerList.getElementsByTagName('input');
for (const input of inputs) {
input.onclick = (layer) => {
const layerId = layer.target.id;
map.setStyle('mapbox://styles/mapbox/' + layerId);
};
}
</script>
</body>
</html>