I am developing a map via Mapbox GL JS that display coordinate data as a geojson, and displays a variety of environmental layers as either Mapbox Studio layers, or a WMS layer.
I have however just run into an issue. All my points and layers display properly upon load. But when I click "satellite" to change the basemap, the Wetlands, Aquifers and Floodzone layers stop working. The buttons do not function whatsoever and the error I get is:
style.js:788 Uncaught TypeError: Cannot read property 'getLayoutProperty' of undefined
at i.getLayoutProperty (style.js:788)
at o.getLayoutProperty (map.js:1315)
at HTMLAnchorElement.link.onclick ((index):1309)
i.getLayoutProperty @ style.js:788
o.getLayoutProperty @ map.js:1315
link.onclick @ (index):1309
You can see a functioning demo here. /
And all code is below:
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<title></title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script src='.50.0/mapbox-gl.js'></script>
<link href='.50.0/mapbox-gl.css' rel='stylesheet' />
<script src='.2.0/mapbox-gl-geocoder.min.js'></script>
<link rel='stylesheet' href='.2.0/mapbox-gl-geocoder.css' type='text/css' />
<link href="+Sans" rel="stylesheet">
<link href="" rel="stylesheet">
<style>
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<style>
.marker {
background-image: url('data/marker.svg');
background-size: cover;
width:20px;
height: 20px;
cursor: pointer;
padding: 0px;
}
.markerUnit {
background-image: url('.svg');
background-size: cover;
width:20px;
height: 20px;
cursor: pointer;
padding: 0px;
}
.mapboxgl-popup {
max-width: 300px;
}
.mapboxgl-popup-content {
text-align: center;
font-family: 'Open Sans', sans-serif;
}
#infoButton {
position: fixed;
right:10px;
top: 10px;
width: 30px;
height: 20px;
box-shadow:0px 0px 3px rgba(0, 0, 0, 0.10);
border: none;
border-radius: 3px;
font-size: 12px;
font-family: 'Inconsolata';
color: #fff;
background: #ee8a65;
cursor:pointer;
}
#centerMap {
position: fixed;
right: 45px;
top: 10px;
width: 80px;
height: 20px;
box-shadow:0px 0px 3px rgba(0, 0, 0, 0.10);
border: none;
border-radius: 3px;
font-size: 12px;
font-family: 'Inconsolata';
text-align: center;
color: #fff;
background: #ee8a65;
cursor:pointer;
}
/* The Modal (background) */
.modal {
display: none;
position: fixed;
z-index: 1;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgb(0,0,0);
background-color: rgba(0,0,0,0.4);
}
/* Modal Content/Box */
.modal-content {
background-color: #fefefe;
margin: 15% auto;
padding: 20px;
border-radius: 4px;
width: 60%;
font-family: 'Open Sans', sans-serif;
font-size: 14px;
animation-name: animatetop;
animation-duration: 0.4s;
}
@keyframes animatetop {
from {top: -300px; opacity: 0}
to {top: 0; opacity: 1}
}
/* The Close Button */
.close {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
}
.close:hover,
.close:focus {
color: black;
text-decoration: none;
cursor: pointer;
}
#menu {
background: #fff;
position: absolute;
z-index: 1;
top: 60px;
left: 10px;
width: 120px;
box-shadow:0px 0px 3px rgba(0, 0, 0, 0.10);
border-radius: 3px;
font-size: 12px;
font-family: 'Inconsolata';
color: #fff;
cursor:pointer;
}
#menu a {
font-size: 13px;
color: #404040;
display: block;
margin: 0;
padding: 0;
padding: 10px;
text-decoration: none;
border-bottom: 1px solid rgba(0,0,0,0.25);
text-align: center;
}
#menu a:last-child {
border: none;
}
#menu a:hover {
background-color: #f8f8f8;
color: #404040;
}
#menu a.active {
background-color: #3887be;
color: #ffffff;
}
#menu a.active:hover {
background: #3074a4;
}
#menuLayer {
position: fixed;
bottom:10px;
right:45px;
height: 15px;
width: 140px;
box-shadow:0px 0px 3px rgba(0, 0, 0, 0.10);
border-radius: 3px;
background: #fff;
padding: 10px;
font-family: 'Inconsolata';
font-size: 12px;
text-align: center;
}
</style>
<div id='map'></div>
<div id='menuLayer'>
<input id='cjneuzsr492wx2tqw6ngm0zug' type='radio' name='rtoggle' value='light' checked='checked'>
<label for='light'>light</label>
<input id='cjnxbj1503m302sp7bkpcxt4w' type='radio' name='rtoggle' value='satellite'>
<label for='satellite'>satellite</label>
</div>
<nav id="menu"></nav>
<div class='map-overlay top'>
<div class='map-overlay-inner'>
</div>
</div>
<button id="centerMap">Center Map</button>
<button id="infoButton">i</button>
<div id="myModal" class="modal">
<div class="modal-content">
<span class="close">×</span>
<h4>Insert text </h4>
</div>
</div>
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoiZHlhdnJvbSIsImEiOiJjamZsZGl0dnIwMHUwMnhvNDB4N2o0cnB6In0.AqxOgFJXuLgFMiwkPutaLA';
var bounds = [
[-137.3,14.3], // west-south coordinates
[-41.6, 67.4] // Northeast coordinates
];
if (!mapboxgl.supported()) {
alert('Your browser does not support Mapbox GL. Please try and different browser.');
} else {
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/dyavrom/cjneuzsr492wx2tqw6ngm0zug',
center: [-105, 47],
zoom: 2.75,
// maxBounds: bounds,
attributionControl:false
});
}
//add second layer of data
map.on('load', function() {
// Floodzome Mapbox Studio layer
map.addLayer({
"id": "Floodzones",
"type": "fill",
"source": {
type: 'vector',
url: 'mapbox://dyavrom.d7g97071'
},
'source-layer': 'selected_layer',
'minzoom':8,
'layout': {
'visibility': 'none'
},
"paint": {
"fill-color": "#2ee6da",
"fill-opacity": .5
}
});
//Aquifer Mapbox Studio layer
map.addLayer({
"id": "Aquifers",
"type": "fill",
"source": {
type: 'vector',
url: 'mapbox://dyavrom.6i5kjh12'
},
'source-layer': 'aquifersSingleColor-9baxdg',
'minzoom':5,
'layout': {
'visibility': 'none'
},
"paint": {
"fill-color": "#7e5cee",
"fill-opacity": .25
}
});
// wetlands WMS layer
map.addLayer({
'id': 'Wetlands',
'type': 'raster',
'source': {
'type': 'raster',
'tiles': [
'={bbox-epsg-3857}&bboxSR=EPSG%3A3857&layers=28&layerDefs=&size=256%2c256&imageSR=&format=png&transparent=true&dpi=&time=&layerTimeOptions=&dynamicLayers=&gdbVersion=&mapScale=&f=image'
],
'tileSize': 256,
},
'minzoom':5,
'layout': {
'visibility': 'none'
}
});
});
var layerList = document.getElementById('menuLayer');
var inputs = layerList.getElementsByTagName('input');
function switchLayer(layer) {
var layerId = layer.target.id;
map.setStyle('mapbox://styles/dyavrom/' + layerId);
}
for (var i = 0; i < inputs.length; i++) {
inputs[i].onclick = switchLayer;
}
//fit to center button
document.getElementById('centerMap').addEventListener('click', function() {
map.fitBounds([[
-167.3,14.3
], [
-41.6,67.4
]]);
});
var geojsonUnit = {
"type": "FeatureCollection",
"name": "latlon2",
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
"features": [
{ "type": "Feature", "properties": { "Code": -999, "Name": "Place", "address": "xxx", "city": "xxx", "state": "xx", "zip": 12345, "lat": 38.79381, "lon": -91.9854, "unitType": "xxx" }, "geometry": { "type": "Point", "coordinates": [ -91.9854, 38.79381 ] } }
]
}
//add markers to map
geojsonUnit.features.forEach(function(markerUnit) {
// create a HTML element for each feature
var el = document.createElement('div');
el.className = 'markerUnit';
// make a marker for each feature and add to the map
new mapboxgl.Marker(el)
.setLngLat(markerUnit.geometry.coordinates)
.addTo(map);
//add popups
new mapboxgl.Marker(el)
.setLngLat(markerUnit.geometry.coordinates)
.setPopup(new mapboxgl.Popup({ offset: 25,
closeButton: (true) })
.setHTML('<h3>' + markerUnit.properties.plantName + '</h3><h5>' +
markerUnit.properties.address +
', ' +
markerUnit.properties.city +
' ' +
markerUnit.properties.state +
', ' +
markerUnit.properties.zip +
'</h5><h5>'+
'Type: '+
markerUnit.properties.unitType +
'</h5>'))
.addTo(map);
});
// Add Geocoder and buttons
map.addControl(new MapboxGeocoder({
accessToken: mapboxgl.accessToken,
}), 'top-left');
// Add zoom and rotation controls to the map.
map.addControl(new mapboxgl.NavigationControl({
showCompass: (false),
}), 'bottom-right');
// Add geolocate control to the map.
map.addControl(new mapboxgl.GeolocateControl({
positionOptions: {
enableHighAccuracy: true
},
trackUserLocation: true,
fitBoundsOptions: {maxZoom:11},
}), 'bottom-right');
// Info button
var modal = document.getElementById('myModal');
// Get the button that opens the modal
var btn = document.getElementById("infoButton");
// Get the <span> element that closes the modal
var span = document.getElementsByClassName("close")[0];
// When the user clicks on the button, open the modal
btn.onclick = function() {
modal.style.display = "block";
}
// When the user clicks on <span> (x), close the modal
span.onclick = function() {
modal.style.display = "none";
}
// When the user clicks anywhere outside of the modal, close it
window.onclick = function(event) {
if (event.target == modal) {
modal.style.display = "none";
}
}
//toggle layers
var toggleableLayerIds = [ 'Wetlands', 'Floodzones', 'Aquifers' ];
for (var i = 0; i < toggleableLayerIds.length; i++) {
var id = toggleableLayerIds[i];
var link = document.createElement('a');
link.href = '#';
link.className = '';
link.textContent = id;
link.onclick = function (e) {
var clickedLayer = this.textContent;
e.preventDefault();
e.stopPropagation();
var visibility = map.getLayoutProperty(clickedLayer, 'visibility');
if (visibility === 'visible') {
map.setLayoutProperty(clickedLayer, 'visibility', 'none');
this.className = '';
} else {
this.className = 'active';
map.setLayoutProperty(clickedLayer, 'visibility', 'visible');
}
};
var layers = document.getElementById('menu');
layers.appendChild(link);
}
</script>
</body>
</html>
I am developing a map via Mapbox GL JS that display coordinate data as a geojson, and displays a variety of environmental layers as either Mapbox Studio layers, or a WMS layer.
I have however just run into an issue. All my points and layers display properly upon load. But when I click "satellite" to change the basemap, the Wetlands, Aquifers and Floodzone layers stop working. The buttons do not function whatsoever and the error I get is:
style.js:788 Uncaught TypeError: Cannot read property 'getLayoutProperty' of undefined
at i.getLayoutProperty (style.js:788)
at o.getLayoutProperty (map.js:1315)
at HTMLAnchorElement.link.onclick ((index):1309)
i.getLayoutProperty @ style.js:788
o.getLayoutProperty @ map.js:1315
link.onclick @ (index):1309
You can see a functioning demo here. https://bl.ocks/dyavromEPA/raw/4576726c459e654ff5e2664f096aaba1/
And all code is below:
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<title></title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script src='https://api.tiles.mapbox./mapbox-gl-js/v0.50.0/mapbox-gl.js'></script>
<link href='https://api.tiles.mapbox./mapbox-gl-js/v0.50.0/mapbox-gl.css' rel='stylesheet' />
<script src='https://api.mapbox./mapbox-gl-js/plugins/mapbox-gl-geocoder/v2.2.0/mapbox-gl-geocoder.min.js'></script>
<link rel='stylesheet' href='https://api.mapbox./mapbox-gl-js/plugins/mapbox-gl-geocoder/v2.2.0/mapbox-gl-geocoder.css' type='text/css' />
<link href="https://fonts.googleapis./css?family=Open+Sans" rel="stylesheet">
<link href="https://fonts.googleapis./css?family=Inconsolata" rel="stylesheet">
<style>
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<style>
.marker {
background-image: url('data/marker.svg');
background-size: cover;
width:20px;
height: 20px;
cursor: pointer;
padding: 0px;
}
.markerUnit {
background-image: url('https://cdn.rawgit./dyavromEPA/a71f02aca7cade0d26a90344e61738f4/raw/aca54e7f1f8eb8c87c6719feb23c8fe2198baea3/map.svg');
background-size: cover;
width:20px;
height: 20px;
cursor: pointer;
padding: 0px;
}
.mapboxgl-popup {
max-width: 300px;
}
.mapboxgl-popup-content {
text-align: center;
font-family: 'Open Sans', sans-serif;
}
#infoButton {
position: fixed;
right:10px;
top: 10px;
width: 30px;
height: 20px;
box-shadow:0px 0px 3px rgba(0, 0, 0, 0.10);
border: none;
border-radius: 3px;
font-size: 12px;
font-family: 'Inconsolata';
color: #fff;
background: #ee8a65;
cursor:pointer;
}
#centerMap {
position: fixed;
right: 45px;
top: 10px;
width: 80px;
height: 20px;
box-shadow:0px 0px 3px rgba(0, 0, 0, 0.10);
border: none;
border-radius: 3px;
font-size: 12px;
font-family: 'Inconsolata';
text-align: center;
color: #fff;
background: #ee8a65;
cursor:pointer;
}
/* The Modal (background) */
.modal {
display: none;
position: fixed;
z-index: 1;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgb(0,0,0);
background-color: rgba(0,0,0,0.4);
}
/* Modal Content/Box */
.modal-content {
background-color: #fefefe;
margin: 15% auto;
padding: 20px;
border-radius: 4px;
width: 60%;
font-family: 'Open Sans', sans-serif;
font-size: 14px;
animation-name: animatetop;
animation-duration: 0.4s;
}
@keyframes animatetop {
from {top: -300px; opacity: 0}
to {top: 0; opacity: 1}
}
/* The Close Button */
.close {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
}
.close:hover,
.close:focus {
color: black;
text-decoration: none;
cursor: pointer;
}
#menu {
background: #fff;
position: absolute;
z-index: 1;
top: 60px;
left: 10px;
width: 120px;
box-shadow:0px 0px 3px rgba(0, 0, 0, 0.10);
border-radius: 3px;
font-size: 12px;
font-family: 'Inconsolata';
color: #fff;
cursor:pointer;
}
#menu a {
font-size: 13px;
color: #404040;
display: block;
margin: 0;
padding: 0;
padding: 10px;
text-decoration: none;
border-bottom: 1px solid rgba(0,0,0,0.25);
text-align: center;
}
#menu a:last-child {
border: none;
}
#menu a:hover {
background-color: #f8f8f8;
color: #404040;
}
#menu a.active {
background-color: #3887be;
color: #ffffff;
}
#menu a.active:hover {
background: #3074a4;
}
#menuLayer {
position: fixed;
bottom:10px;
right:45px;
height: 15px;
width: 140px;
box-shadow:0px 0px 3px rgba(0, 0, 0, 0.10);
border-radius: 3px;
background: #fff;
padding: 10px;
font-family: 'Inconsolata';
font-size: 12px;
text-align: center;
}
</style>
<div id='map'></div>
<div id='menuLayer'>
<input id='cjneuzsr492wx2tqw6ngm0zug' type='radio' name='rtoggle' value='light' checked='checked'>
<label for='light'>light</label>
<input id='cjnxbj1503m302sp7bkpcxt4w' type='radio' name='rtoggle' value='satellite'>
<label for='satellite'>satellite</label>
</div>
<nav id="menu"></nav>
<div class='map-overlay top'>
<div class='map-overlay-inner'>
</div>
</div>
<button id="centerMap">Center Map</button>
<button id="infoButton">i</button>
<div id="myModal" class="modal">
<div class="modal-content">
<span class="close">×</span>
<h4>Insert text </h4>
</div>
</div>
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoiZHlhdnJvbSIsImEiOiJjamZsZGl0dnIwMHUwMnhvNDB4N2o0cnB6In0.AqxOgFJXuLgFMiwkPutaLA';
var bounds = [
[-137.3,14.3], // west-south coordinates
[-41.6, 67.4] // Northeast coordinates
];
if (!mapboxgl.supported()) {
alert('Your browser does not support Mapbox GL. Please try and different browser.');
} else {
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/dyavrom/cjneuzsr492wx2tqw6ngm0zug',
center: [-105, 47],
zoom: 2.75,
// maxBounds: bounds,
attributionControl:false
});
}
//add second layer of data
map.on('load', function() {
// Floodzome Mapbox Studio layer
map.addLayer({
"id": "Floodzones",
"type": "fill",
"source": {
type: 'vector',
url: 'mapbox://dyavrom.d7g97071'
},
'source-layer': 'selected_layer',
'minzoom':8,
'layout': {
'visibility': 'none'
},
"paint": {
"fill-color": "#2ee6da",
"fill-opacity": .5
}
});
//Aquifer Mapbox Studio layer
map.addLayer({
"id": "Aquifers",
"type": "fill",
"source": {
type: 'vector',
url: 'mapbox://dyavrom.6i5kjh12'
},
'source-layer': 'aquifersSingleColor-9baxdg',
'minzoom':5,
'layout': {
'visibility': 'none'
},
"paint": {
"fill-color": "#7e5cee",
"fill-opacity": .25
}
});
// wetlands WMS layer
map.addLayer({
'id': 'Wetlands',
'type': 'raster',
'source': {
'type': 'raster',
'tiles': [
'https://www.fws.gov/wetlands/arcgis/rest/services/Wetlands/MapServer/export?bbox={bbox-epsg-3857}&bboxSR=EPSG%3A3857&layers=28&layerDefs=&size=256%2c256&imageSR=&format=png&transparent=true&dpi=&time=&layerTimeOptions=&dynamicLayers=&gdbVersion=&mapScale=&f=image'
],
'tileSize': 256,
},
'minzoom':5,
'layout': {
'visibility': 'none'
}
});
});
var layerList = document.getElementById('menuLayer');
var inputs = layerList.getElementsByTagName('input');
function switchLayer(layer) {
var layerId = layer.target.id;
map.setStyle('mapbox://styles/dyavrom/' + layerId);
}
for (var i = 0; i < inputs.length; i++) {
inputs[i].onclick = switchLayer;
}
//fit to center button
document.getElementById('centerMap').addEventListener('click', function() {
map.fitBounds([[
-167.3,14.3
], [
-41.6,67.4
]]);
});
var geojsonUnit = {
"type": "FeatureCollection",
"name": "latlon2",
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
"features": [
{ "type": "Feature", "properties": { "Code": -999, "Name": "Place", "address": "xxx", "city": "xxx", "state": "xx", "zip": 12345, "lat": 38.79381, "lon": -91.9854, "unitType": "xxx" }, "geometry": { "type": "Point", "coordinates": [ -91.9854, 38.79381 ] } }
]
}
//add markers to map
geojsonUnit.features.forEach(function(markerUnit) {
// create a HTML element for each feature
var el = document.createElement('div');
el.className = 'markerUnit';
// make a marker for each feature and add to the map
new mapboxgl.Marker(el)
.setLngLat(markerUnit.geometry.coordinates)
.addTo(map);
//add popups
new mapboxgl.Marker(el)
.setLngLat(markerUnit.geometry.coordinates)
.setPopup(new mapboxgl.Popup({ offset: 25,
closeButton: (true) })
.setHTML('<h3>' + markerUnit.properties.plantName + '</h3><h5>' +
markerUnit.properties.address +
', ' +
markerUnit.properties.city +
' ' +
markerUnit.properties.state +
', ' +
markerUnit.properties.zip +
'</h5><h5>'+
'Type: '+
markerUnit.properties.unitType +
'</h5>'))
.addTo(map);
});
// Add Geocoder and buttons
map.addControl(new MapboxGeocoder({
accessToken: mapboxgl.accessToken,
}), 'top-left');
// Add zoom and rotation controls to the map.
map.addControl(new mapboxgl.NavigationControl({
showCompass: (false),
}), 'bottom-right');
// Add geolocate control to the map.
map.addControl(new mapboxgl.GeolocateControl({
positionOptions: {
enableHighAccuracy: true
},
trackUserLocation: true,
fitBoundsOptions: {maxZoom:11},
}), 'bottom-right');
// Info button
var modal = document.getElementById('myModal');
// Get the button that opens the modal
var btn = document.getElementById("infoButton");
// Get the <span> element that closes the modal
var span = document.getElementsByClassName("close")[0];
// When the user clicks on the button, open the modal
btn.onclick = function() {
modal.style.display = "block";
}
// When the user clicks on <span> (x), close the modal
span.onclick = function() {
modal.style.display = "none";
}
// When the user clicks anywhere outside of the modal, close it
window.onclick = function(event) {
if (event.target == modal) {
modal.style.display = "none";
}
}
//toggle layers
var toggleableLayerIds = [ 'Wetlands', 'Floodzones', 'Aquifers' ];
for (var i = 0; i < toggleableLayerIds.length; i++) {
var id = toggleableLayerIds[i];
var link = document.createElement('a');
link.href = '#';
link.className = '';
link.textContent = id;
link.onclick = function (e) {
var clickedLayer = this.textContent;
e.preventDefault();
e.stopPropagation();
var visibility = map.getLayoutProperty(clickedLayer, 'visibility');
if (visibility === 'visible') {
map.setLayoutProperty(clickedLayer, 'visibility', 'none');
this.className = '';
} else {
this.className = 'active';
map.setLayoutProperty(clickedLayer, 'visibility', 'visible');
}
};
var layers = document.getElementById('menu');
layers.appendChild(link);
}
</script>
</body>
</html>
Share
Improve this question
asked Oct 31, 2018 at 18:11
Deeba YavromDeeba Yavrom
911 silver badge12 bronze badges
1
- You need to demonstrate that you have tried to solve the problem yourself, not just paste your entire application here. – Steve Bennett Commented Nov 12, 2018 at 12:43
1 Answer
Reset to default 5When you change the map style, all your layer is removed. This is due to the fact all you layer is create on the map style https://docs.mapbox./mapbox-gl-js/style-spec/. You just have to recreate them all.