Hi there!
I wish write about known common problem with mapbox-gl
.
At the moment there are some proposals for a solution and some workarounds.
In this article, we see the typical scenario and going to go to implement it.
Conditions of the problem
Let's describe a simple case:
- We need to add to the map our own
GeoJSON
source and corresponding layer, before the text labels. - When switching the base style, our layer should remain on the map.
We use a straightforward approach with mapbox-gl events.
Define the source
// constants.js
const GEOJSON_FEATURE = {
type: "Feature",
properties: {},
geometry: {
type: "Polygon",
coordinates: [
[
[-66.96466, 44.8097],
[-67.79035274928509, 47.066248887716995],
[-69.23708614772835, 47.44777598732787],
[-71.08482, 45.3052400000002],
[-70.64573401557249, 43.090083319667144],
[-66.96466, 44.8097],
],
],
},
};
Create the map
// index.js
mapboxgl.accessToken = <your token here>;
var map = new mapboxgl.Map({
container: "map",
style: "mapbox://styles/mapbox/streets-v11",
center: [-68.13734351262877, 45.137451890638886],
zoom: 5,
});
Improve addLayer
function
If we use beforeId
that not exists already on the map, we get an error
Let's create addLayerBefore function to escape this
function addLayerBefore(addLayerFn, layer, beforeId) {
// check beforeId defined and exists on the map
const beforeLayer = Boolean(beforeId) && map.getLayer(beforeId);
if (beforeLayer && beforeId === beforeLayer.id) addLayerFn(layer, beforeId);
else {
console.warn(
`Not found layer with id '${beforeId}'.\nLayer '${layer.id}' added without before.`
);
addLayerFn(layer);
}
}
Define add data function
Add's GeoJSON
source with fill layer, before waterway-label
in current example it places polygon before the map text labels
function addMaineLayer() {
map.addSource("maine", {
type: "geojson",
data: {
type: "Feature",
geometry: GEOJSON_FEATURE
});
// define the function to add layer
const addLayer = (layer, beforeId) => map.addLayer(layer, beforeId);
addLayerBefore(
addLayer,
{
id: "maine",
type: "fill",
source: "maine",
layout: {},
paint: {
"fill-color": "#088",
"fill-opacity": 0.8
}
},
"waterway-label"
);
}
Setup events
We should call addMaineLayer function when:
- map initially loads with
load
event - map changes the style with
styledata
event
map.on("load", function () {
// add layer to the map on load
addMaineLayer();
const layerList = document.getElementById("menu");
const inputs = layerList.getElementsByTagName("input");
function switchLayer(layer) {
// addMaineLayer fn will be called once on layer switched
map.once("styledata", addMaineLayer);
const layerId = layer.target.id;
map.setStyle("mapbox://styles/mapbox/" + layerId);
}
// set toggle base style events
for (let i = 0; i < inputs.length; i++) {
inputs[i].onclick = switchLayer;
}
});
Let's check the result
That is!
In the next article we going to go implement this with RxJS!
Top comments (0)