Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changing map style causes plugin to throw errors #190

Open
ryanhamley opened this issue Jul 25, 2018 · 4 comments · May be fixed by #236
Open

Changing map style causes plugin to throw errors #190

ryanhamley opened this issue Jul 25, 2018 · 4 comments · May be fixed by #236

Comments

@ryanhamley
Copy link

This bug was initially filed as mapbox/mapbox-gl-js#7019 but I'm moving it here because the bug is in the plugin.

When you change a map's style, the route feature is removed causing this line to throw the error Error: The layer 'directions-route-line-alt' does not exist in the map's style and cannot be queried for features.

const features = this._map.queryRenderedFeatures(e.point, {
layers: [
'directions-route-line-alt',
'directions-route-line',
'directions-origin-point',
'directions-destination-point',
'directions-hover-point'
]
});

Steps to Trigger Behavior

  1. Add directions route to map
  2. Change base map style
  3. Move mouse around the map

Link to Demonstration

https://plnkr.co/edit/M8mj1WTH1KjDa1dhiUKw?p=preview

Expected Behavior

The plugin should be able to handle this situation so that no errors are thrown.

Actual Behavior

Errors are thrown.

cc @mikeomeara1

@weifageo
Copy link

weifageo commented Jul 24, 2019

I was experiencing the same issue as described in the OP and came up with this hack work around which involves removing all the Directions Layers and Source, changing the map style, then re-adding the Source and Layers once again. It is a tedious process and the user will have to query the directions control once again to show a route after the style has changed. Since no one has responded to this thread I thought this might be helpful for others suffering from this same issue.

function removeDirectionsLayers(){
map.removeLayer('directions-route-line-alt');
map.removeLayer('directions-route-line-casing');
map.removeLayer('directions-route-line');
map.removeLayer('directions-hover-point-casing');
map.removeLayer('directions-hover-point');
map.removeLayer('directions-waypoint-point-casing');
map.removeLayer('directions-waypoint-point');
map.removeLayer('directions-origin-point');
map.removeLayer('directions-origin-label');
map.removeLayer('directions-destination-point');
map.removeLayer('directions-destination-label');
map.removeSource('directions');
}

function addDirectionsLayers(){
// directions hack
map.addSource('directions', {
"type": "geojson",
"data": {
"type": "FeatureCollection",
"features": []
}
});
// these layers were found in the following source code: https://github.com/mapbox/mapbox-gl-directions/blob/master/src/directions_style.js
map.addLayer({
'id': 'directions-route-line-alt',
'type': 'line',
'source': 'directions',
'layout': {
'line-cap': 'round',
'line-join': 'round'
},
'paint': {
'line-color': '#bbb',
'line-width': 4
},
'filter': [
'all',
['in', '$type', 'LineString'],
['in', 'route', 'alternate']
]
});
map.addLayer({
'id': 'directions-route-line-casing',
'type': 'line',
'source': 'directions',
'layout': {
'line-cap': 'round',
'line-join': 'round'
},
'paint': {
'line-color': '#2d5f99',
'line-width': 12
},
'filter': [
'all',
['in', '$type', 'LineString'],
['in', 'route', 'selected']
]
});
map.addLayer({
'id': 'directions-route-line',
'type': 'line',
'source': 'directions',
'layout': {
'line-cap': 'butt',
'line-join': 'round'
},
'paint': {
'line-color': {
'property': 'congestion',
'type': 'categorical',
'default': '#4882c5',
'stops': [
['unknown', '#4882c5'],
['low', '#4882c5'],
['moderate', '#f09a46'],
['heavy', '#e34341'],
['severe', '#8b2342']
]
},
'line-width': 7
},
'filter': [
'all',
['in', '$type', 'LineString'],
['in', 'route', 'selected']
]
});
map.addLayer({
'id': 'directions-hover-point-casing',
'type': 'circle',
'source': 'directions',
'paint': {
'circle-radius': 8,
'circle-color': '#fff'
},
'filter': [
'all',
['in', '$type', 'Point'],
['in', 'id', 'hover']
]
});
map.addLayer({
'id': 'directions-hover-point',
'type': 'circle',
'source': 'directions',
'paint': {
'circle-radius': 6,
'circle-color': '#3bb2d0'
},
'filter': [
'all',
['in', '$type', 'Point'],
['in', 'id', 'hover']
]
});
map.addLayer({
'id': 'directions-waypoint-point-casing',
'type': 'circle',
'source': 'directions',
'paint': {
'circle-radius': 8,
'circle-color': '#fff'
},
'filter': [
'all',
['in', '$type', 'Point'],
['in', 'id', 'waypoint']
]
});
map.addLayer({
'id': 'directions-waypoint-point',
'type': 'circle',
'source': 'directions',
'paint': {
'circle-radius': 6,
'circle-color': '#8a8bc9'
},
'filter': [
'all',
['in', '$type', 'Point'],
['in', 'id', 'waypoint']
]
});
map.addLayer({
'id': 'directions-origin-point',
'type': 'circle',
'source': 'directions',
'paint': {
'circle-radius': 18,
'circle-color': '#3bb2d0'
},
'filter': [
'all',
['in', '$type', 'Point'],
['in', 'marker-symbol', 'A']
]
});
map.addLayer({
'id': 'directions-origin-label',
'type': 'symbol',
'source': 'directions',
'layout': {
'text-field': 'A',
'text-font': ['Open Sans Bold', 'Arial Unicode MS Bold'],
'text-size': 12
},
'paint': {
'text-color': '#fff'
},
'filter': [
'all',
['in', '$type', 'Point'],
['in', 'marker-symbol', 'A']
]
});
map.addLayer({
'id': 'directions-destination-point',
'type': 'circle',
'source': 'directions',
'paint': {
'circle-radius': 18,
'circle-color': '#8a8bc9'
},
'filter': [
'all',
['in', '$type', 'Point'],
['in', 'marker-symbol', 'B']
]
});
map.addLayer({
'id': 'directions-destination-label',
'type': 'symbol',
'source': 'directions',
'layout': {
'text-field': 'B',
'text-font': ['Open Sans Bold', 'Arial Unicode MS Bold'],
'text-size': 12
},
'paint': {
'text-color': '#fff'
},
'filter': [
'all',
['in', '$type', 'Point'],
['in', 'marker-symbol', 'B']
]
});
}

// when you want to switch styles use the following 3 step process
removeDirectionsLayers();
map.setStyle('mapbox://styles/mapbox/satellite-v9');
addDirectionsLayers();

@jonathonwpowell
Copy link

This seems due to the onAdd method in directions.js

    if (this._map.loaded()) this.mapState()
    else this._map.on('load', () => this.mapState());

If a style is changed, loaded() will return false while it is loading but the 'load' event only triggers the first time the map is loaded, so it will not trigger if the style is changed after the initial load.

Related issues:
mapbox/mapbox-gl-js#6707
#111
mapbox/mapbox-gl-js#8691

@jonathonwpowell
Copy link

I think that the best solution may be subscribing to the idle event instead, and then unsubscribing once the event has triggered

@xiaofanliang
Copy link

xiaofanliang commented Jun 12, 2023

It is 2023! And this issue still persists... reloading the data layer after the style change works but only for displaying static data. The Direction Plugin API will still return the same error.

The layer 'directions-route-line-alt' does not exist in the map's style and cannot be queried for features.

The markers for origin and destination and the routes disappear on the map, even though the API picks up the coordinates correctly and returns the right instructions and route statistics.

Here is a simple snippet to recreate this bug if needed. I am desperately searching for workarounds. I tried removing the plugin and then re-creating it after the style change (hoping it will reinitialize the plugin), but it still does not work.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Display navigation directions</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<link href="https://api.mapbox.com/mapbox-gl-js/v2.15.0/mapbox-gl.css" rel="stylesheet">
<script src="https://api.mapbox.com/mapbox-gl-js/v2.15.0/mapbox-gl.js"></script>
<style>
body { margin: 0; padding: 0; }
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
#menu {
position: absolute;
background: #efefef;
padding: 10px;
left: 500px;
font-family: 'Open Sans', sans-serif;
}
</style>
</head>
<body>
<script src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-directions/v4.1.1/mapbox-gl-directions.js"></script>
<link rel="stylesheet" href="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-directions/v4.1.1/mapbox-gl-directions.css" type="text/css">
<div id="map">
</div>
<div id="menu">
<div id="directions"></div>
<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>
</div>
 
<script>
<script>
	mapboxgl.accessToken = ''
	const map = new mapboxgl.Map({
		container: 'map',
		style: 'mapbox://styles/mapbox/streets-v12',
		center: [-79.4512, 43.6568],
		zoom: 13
	});
	
	map.addControl(
	new MapboxDirections({
		accessToken: mapboxgl.accessToken
	}),
	'top-left'
	);

	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>
</script>
 
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
4 participants