Unterschiedliche Karten mit Mapbox GL ermöglichen
Jeder hat seine Vorliebe. Mancher bevorzugt Satellitenaufnahmen. Ein anderer gemalte Karten. Zusätzlich bieten unterschiedliche Style je nach Anwendungszweck Vor- und Nachteile. Deshalb ist ideal, wenn es man es Websitebesuchern ermöglicht, die Lieblingskarte per Steuerelement auszuwählen. Hier ein Beispiel für einen Kartentypwechsler oder Style-Switcher:
<!-- https://raw.githubusercontent.com/astridx/maplibreexamples/main/plugins/maplibre-style-switcher.html -->
<html>
<head>
<title>Mapbox style switcher</title>
<meta charset="UTF-8" />
<script src="../.env"></script>
<script src="https://unpkg.com/maplibre-gl@1.14.0-rc.1/dist/maplibre-gl.js"></script>
<link
href="https://unpkg.com/maplibre-gl@1.14.0-rc.1/dist/maplibre-gl.css"
rel="stylesheet"
/>
<script>
class MapboxStyleSwitcherControl {
constructor(styles, defaultStyle) {
this.styles = styles || MapboxStyleSwitcherControl.DEFAULT_STYLES
this.defaultStyle =
defaultStyle || MapboxStyleSwitcherControl.DEFAULT_STYLE
this.onDocumentClick = this.onDocumentClick.bind(this)
}
getDefaultPosition() {
const defaultPosition = 'top-right'
return defaultPosition
}
onAdd(map) {
this.map = map
this.controlContainer = document.createElement('div')
this.controlContainer.classList.add('mapboxgl-ctrl')
this.controlContainer.classList.add('mapboxgl-ctrl-group')
this.mapStyleContainer = document.createElement('div')
this.styleButton = document.createElement('button')
this.styleButton.type = 'button'
this.mapStyleContainer.classList.add('mapboxgl-style-list')
for (const style of this.styles) {
const styleElement = document.createElement('button')
styleElement.type = 'button'
styleElement.innerText = style.title
styleElement.classList.add(style.title.replace(/[^a-z0-9-]/gi, '_'))
styleElement.dataset.uri = JSON.stringify(style.uri)
styleElement.addEventListener('click', (event) => {
const srcElement = event.srcElement
if (srcElement.classList.contains('active')) {
return
}
this.map.setStyle(JSON.parse(srcElement.dataset.uri))
this.mapStyleContainer.style.display = 'none'
this.styleButton.style.display = 'block'
const elms =
this.mapStyleContainer.getElementsByClassName('active')
while (elms[0]) {
elms[0].classList.remove('active')
}
srcElement.classList.add('active')
})
if (style.title === this.defaultStyle) {
styleElement.classList.add('active')
}
this.mapStyleContainer.appendChild(styleElement)
}
this.styleButton.classList.add('mapboxgl-ctrl-icon')
this.styleButton.classList.add('mapboxgl-style-switcher')
this.styleButton.addEventListener('click', () => {
this.styleButton.style.display = 'none'
this.mapStyleContainer.style.display = 'block'
})
document.addEventListener('click', this.onDocumentClick)
this.controlContainer.appendChild(this.styleButton)
this.controlContainer.appendChild(this.mapStyleContainer)
return this.controlContainer
}
onRemove() {
if (
!this.controlContainer ||
!this.controlContainer.parentNode ||
!this.map ||
!this.styleButton
) {
return
}
this.styleButton.removeEventListener('click', this.onDocumentClick)
this.controlContainer.parentNode.removeChild(this.controlContainer)
document.removeEventListener('click', this.onDocumentClick)
this.map = undefined
}
onDocumentClick(event) {
if (
this.controlContainer &&
!this.controlContainer.contains(event.target) &&
this.mapStyleContainer &&
this.styleButton
) {
this.mapStyleContainer.style.display = 'none'
this.styleButton.style.display = 'block'
}
}
}
// https://cloud.maptiler.com/maps/
MapboxStyleSwitcherControl.DEFAULT_STYLE = 'Streets'
MapboxStyleSwitcherControl.DEFAULT_STYLES = [
{
title: 'Baisc',
uri:
'https://api.maptiler.com/maps/basic/style.json?key=' +
config.MAPTILER_TOKEN,
},
{
title: 'Light',
uri:
'https://api.maptiler.com/maps/bright/style.json?key=' +
config.MAPTILER_TOKEN,
},
{
title: 'Outdoors',
uri:
'https://api.maptiler.com/maps/outdoor/style.json?key=' +
config.MAPTILER_TOKEN,
},
{
title: 'Satellite Hybrid',
uri:
'https://api.maptiler.com/maps/hybrid/style.json?key=' +
config.MAPTILER_TOKEN,
},
{
title: 'Streets',
uri:
'https://api.maptiler.com/maps/streets/style.json?key=' +
config.MAPTILER_TOKEN,
},
]
</script>
<style>
.mapboxgl-style-list {
display: none;
}
.mapboxgl-ctrl-group .mapboxgl-style-list button {
background: none;
border: none;
cursor: pointer;
display: block;
font-size: 14px;
padding: 8px 8px 6px;
text-align: right;
width: 100%;
height: auto;
}
.mapboxgl-style-list button.active {
font-weight: bold;
}
.mapboxgl-style-list button:hover {
background-color: rgba(0, 0, 0, 0.05);
}
.mapboxgl-style-list button + button {
border-top: 1px solid #ddd;
}
.mapboxgl-style-switcher {
background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+PHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJDYXBhXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB3aWR0aD0iNTQuODQ5cHgiIGhlaWdodD0iNTQuODQ5cHgiIHZpZXdCb3g9IjAgMCA1NC44NDkgNTQuODQ5IiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA1NC44NDkgNTQuODQ5OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+PGc+PGc+PGc+PHBhdGggZD0iTTU0LjQ5NywzOS42MTRsLTEwLjM2My00LjQ5bC0xNC45MTcsNS45NjhjLTAuNTM3LDAuMjE0LTEuMTY1LDAuMzE5LTEuNzkzLDAuMzE5Yy0wLjYyNywwLTEuMjU0LTAuMTA0LTEuNzktMC4zMThsLTE0LjkyMS01Ljk2OEwwLjM1MSwzOS42MTRjLTAuNDcyLDAuMjAzLTAuNDY3LDAuNTI0LDAuMDEsMC43MTZMMjYuNTYsNTAuODFjMC40NzcsMC4xOTEsMS4yNTEsMC4xOTEsMS43MjksMEw1NC40ODgsNDAuMzNDNTQuOTY0LDQwLjEzOSw1NC45NjksMzkuODE3LDU0LjQ5NywzOS42MTR6Ii8+PHBhdGggZD0iTTU0LjQ5NywyNy41MTJsLTEwLjM2NC00LjQ5MWwtMTQuOTE2LDUuOTY2Yy0wLjUzNiwwLjIxNS0xLjE2NSwwLjMyMS0xLjc5MiwwLjMyMWMtMC42MjgsMC0xLjI1Ni0wLjEwNi0xLjc5My0wLjMyMWwtMTQuOTE4LTUuOTY2TDAuMzUxLDI3LjUxMmMtMC40NzIsMC4yMDMtMC40NjcsMC41MjMsMC4wMSwwLjcxNkwyNi41NiwzOC43MDZjMC40NzcsMC4xOSwxLjI1MSwwLjE5LDEuNzI5LDBsMjYuMTk5LTEwLjQ3OUM1NC45NjQsMjguMDM2LDU0Ljk2OSwyNy43MTYsNTQuNDk3LDI3LjUxMnoiLz48cGF0aCBkPSJNMC4zNjEsMTYuMTI1bDEzLjY2Miw1LjQ2NWwxMi41MzcsNS4wMTVjMC40NzcsMC4xOTEsMS4yNTEsMC4xOTEsMS43MjksMGwxMi41NDEtNS4wMTZsMTMuNjU4LTUuNDYzYzAuNDc3LTAuMTkxLDAuNDgtMC41MTEsMC4wMS0wLjcxNkwyOC4yNzcsNC4wNDhjLTAuNDcxLTAuMjA0LTEuMjM2LTAuMjA0LTEuNzA4LDBMMC4zNTEsMTUuNDFDLTAuMTIxLDE1LjYxNC0wLjExNiwxNS45MzUsMC4zNjEsMTYuMTI1eiIvPjwvZz48L2c+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjwvc3ZnPg==);
background-position: center;
background-repeat: no-repeat;
background-size: 70%;
}
</style>
</head>
<body>
<h2 style="font-family: sans-serif">Mapbox style switcher</h2>
<div id="map" style="height: 60%"></div>
<script>
const map = new maplibregl.Map({
container: 'map',
style:
'https://api.maptiler.com/maps/streets/style.json?key=' +
config.MAPTILER_TOKEN,
center: [-122.4194, 37.7788],
zoom: 12,
})
var styles = (MapboxStyleDefinition = [
{
title: 'Basic',
uri:
'https://api.maptiler.com/maps/streets/style.json?key=' +
config.MAPTILER_TOKEN,
},
{
title: 'Light',
uri:
'https://api.maptiler.com/maps/bright/style.json?key=' +
config.MAPTILER_TOKEN,
},
{
title: 'Satellite Hybrid',
uri:
'https://api.maptiler.com/maps/hybrid/style.json?key=' +
config.MAPTILER_TOKEN,
},
{
title: 'Outdoors',
uri:
'https://api.maptiler.com/maps/outdoor/style.json?key=' +
config.MAPTILER_TOKEN,
},
])
map.addControl(new MapboxStyleSwitcherControl(styles))
</script>
</body>
</html>
Demo
Quellcode
Gatsby Starter mit dieser Funktion - Gatsby Starter Demo