In my angular app I am using directions api and trying to add a route path from one direction to another. On the first time when making the ajax request route path is creating properly but from the second time i can not see the route path.
I am getting this error from second time onwards of the ajax request - Layer with id "route" already exists on this map
Is there any way to update the source and layer in mapbox?
drawRoute() {
const url = `https://api.mapbox.com/directions/v5/mapbox/driving/${this.startData?.lng},${this.startData?.lat};${this.endData?.lng},${this.endData?.lat}?alternatives=true&geometries=geojson&steps=true&access_token=${environment.mapbox.accessToken}`;
this._http.get(url).subscribe({
next: (result) => {
const geojson: any = {
type: 'Feature',
properties: {},
geometry: {
type: 'LineString',
coordinates: result.routes[0]
}
};
if (this.map?.getSource('route')) {
const source: mapboxgl.GeoJSONSource = this.map?.getSource('route') as
mapboxgl.GeoJSONSource;
source.setData(geojson);
} else {
this.map?.addSource('route', {
type: 'geojson',
data: {
type: 'Feature',
properties: {},
geometry: {
type: 'LineString',
coordinates: result.routes[0].geometry.coordinates
}
}
});
}
this.map?.addLayer({
id: 'route',
type: 'line',
source: 'route',
layout: {
'line-join': 'round',
'line-cap': 'round'
},
paint: {
'line-color': '#1F5ED8',
'line-width': 2
}
});
},
error: (err) => {}
})
}
I think that the setData() method that is available for GeoJSON sources in Mapbox GL JS is what you are looking for. The method allows you to update the underlying source data and triggers a map re-render. The data-driven styling should then kick in and style your updates layers as desired.
https://docs.mapbox.com/mapbox-gl-js/api/sources/#geojsonsource#setdata
Here is a pseudo-code example
map.getSource("source-id").setData(updatedGeoJSONData);
Hope this helps! I have been writing a series of guides for Mapbox that you might be interested in too. Here are some links:
The Mapbox Developer's Handbook
A Complete Guide to Sources and Layers in React and Mapbox GL JS
Related
Using Mapbox GL, I want to be able to create polygons and give them individual colors, but after along search and read through the api doc, just can'tfigure out out this is supposed to be done.
nb: I want to use draw not addlayer as I want the polygon to still be editable afterwards.
nb: this.color is a hex value selected by the user
maybe I'm a newbie n00bing out, maybe the approach isn't quite right.
// when a poly is created add a color property to it and save it into the stagedFeatures array
this.map.on('draw.create', e => {
e.features.forEach(feature => {
feature['properties'] = { color: this.color }
this.stagedFeatures.push(feature)
})
})
// set the color of the next polygon
document.getElementById('colourSelector').addEventListener('change', e => {
if (e.target['value']) {
this.color = e.target['value']
this.setStyle()
}
})
// generate the styles
getStyles() {
return [
{
'id': 'gl-draw-polygon-fill-inactive',
'type': 'fill',
'filter': [
'all',
['==', 'active', 'false'],
['==', '$type', 'Polygon'],
['!=', 'mode', 'static']
],
'paint': {
// my problem is likely here, have tried many expressions etc but mapbox
// expressions aren't super easy to figure out
'fill-color': this.color,
'fill-outline-color': this.color,
'fill-opacity': 0.5
}
},
...
// redraw the map and readd the polygons
setStyle() {
this.map.removeControl(this.draw)
if (typeof this.map.getSource('staged-features') !== 'undefined') {
this.map.removeSource('staged-features')
}
this.map.addSource("staged-features", {
type: "geojson",
data: {
type: "FeatureCollection",
features: this.stagedFeatures
},
})
this.draw = new MapboxDraw({
userProperties: true,
displayControlsDefault: false,
controls: {
polygon: true,
trash: true
},
styles: this.getStyles()
})
this.map.addControl(this.draw)
// loop through any features that the map needs to redraw
this.stagedFeatures.forEach(i => {
console.warn('restore polygons', i)
this.draw.add(i)
})
}
whats happening is the polys redraw but using only the selected color, I'm wanted to get an expression workeing the pulls back the color from the feature.properties.color value
['get', 'color'] with a fallback to this.color doesn't appear to work here.
whats happening is the polys redraw but using only the selected color, I'm wanted to get an expression workeing the pulls back the color from the feature.properties.color value
['get', 'color'] with a fallback to this.color doesn't appear to work here.
https://docs.mapbox.com/mapbox-gl-js/style-spec/expressions/
tried the null operators suggested here:
https://github.com/mapbox/mapbox-gl-js/issues/5761
I'm currently developing a small web-application where I need to parse a csv into a GeoJSON. Therefore I use Papaparse. Whenever I parse the csv document, everything works but the coordinates in the geoJSON are undefined. I first thought it may not be able to access the s_lon, s_lat fields in the result after parsing the csv, but that's not the case, they can be perfectly accessed as can be seen in the logging. But it becomes even weirder, when I try to hard-code the coordinates in the coordinates array, they're undefined as well whenever the Feature get's returned. Does anyone has an idea where the problem might come from?
csvToGeojson(csvString) {
var self = this;
self.$papa.parse(csvString, {
// download: true,
header: true,
dynamicTyping: true,
skipEmptyLines: true,
complete: function (results) {
var geoJsonFeatureCollection = {
type: 'FeatureCollection',
features: results.data.map(function(datum) {
console.log(datum);
console.log(datum.s_lon, datum.s_lat);
return {
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [datum.s_lon, datum.s_lat]
},
properties: datum
}
})
};
console.log("geoJsonFeatureCollection:")
console.log(geoJsonFeatureCollection);
self.$parent.addLayer(L.GeoJSON.canvasFlowmapLayer(geoJsonFeatureCollection, self.options));
}
})
I've built a map and added a layer that highlights a specific neighborhood, I'd like to add a hover effect to the layer. just like in this example https://docs.mapbox.com/mapbox-gl-js/example/hover-styles
I got as far as creating my own layer with the geojson but the example I am trying to follow uses an external data source whereas I am using my own. I tried to reference my data but I don't think I am doing it correctly. Pleases see this link with a working version showing the layer highlighting the neighborhood.
This is the link to what I have so far https://jsfiddle.net/jrax4pvm/1/
Here's my JS
mapboxgl.accessToken =
'pk.eyJ1IjoibGVvc29ubmVrdXM5NSIsImEiOiJjazAxdHcyZWExMHBjM2lwN2psMDhheXQwIn0.KpEYrurG0lE55PLKMuYtKw';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/leosonnekus95/ck11gbbaz0neb1cmrunqmijkf',
zoom: 15,
center: [174.7570008, -36.8658221]
});
map.on('load', function () {
'id': 'Uptown',
'type': 'fill',
'source': {
'type': 'geojson',
'data': {
'type': 'Feature',
'geometry': {
'type': 'Polygon',
'coordinates':
[
[ /* Co-ordinates here..*/ ]]
}
}
},
'layout': {},
'paint': {
'fill-color': '#088',
'fill-opacity': 0.8
}
});
});
I'd really like to make this layer hoverable/clickable and suspect I have to create a combined version of these two examples
https://docs.mapbox.com/mapbox-gl-js/example/geojson-polygon/
https://docs.mapbox.com/mapbox-gl-js/example/hover-styles/
and would like some guidance.
You'll want to add map.on('mouseenter') and map.on('mouseleave') functions which target your layer to your code like this:
map.on('mouseenter', 'Uptown', function(e) {
map.setPaintProperty('Uptown', 'fill-color', '#FF0000');
});
map.on('mouseleave', 'Uptown', function() {
map.setPaintProperty('Uptown', 'fill-color', '#1F06F0'));
});
I've updated your code in another JSFiddle (https://jsfiddle.net/pjleonard37/jfd0bsha/) with these changes.
Disclaimer: I work at Mapbox
I have a map that's using mapboxgl-js to hide or show map markers based on some criteria.
Hiding the markers is working as expected, but when I want the markers to show again they flash for some milliseconds then disappear again while the map hides labels (street names etc.) on the underlying layer before they show up again.
See this video: https://streamable.com/debcp
See this codepen: https://codepen.io/jakobfuchs/details/VRRgJO
I came to the conclusion that this is caused by setting 'icon-allow-overlap': true on the marker symbol layer.
Any suggestions how I can keep that setting and avoid the flashing?
The strange thing is that this does not happen 100% of the time but ~95% of the time.
Code samples:
Marker layer:
map.addLayer({
id: 'property-layer',
type: 'symbol',
source: 'properties',
filter: ['!has', 'point_count'],
layout: {
'symbol-placement': 'point',
'icon-image': 'marker',
'icon-size': 1,
'icon-anchor': 'bottom',
'icon-allow-overlap': true,
}
});
Filter code:
const filterToggle = document.getElementById('filterToggle');
filterToggle.addEventListener('change', function(e) {
if (openPopup) {
openPopup.remove();
openPopup = '';
}
let properties;
if (this.checked) {
properties = {
type: "FeatureCollection",
features: features.features.filter((property) => property.properties.availability === 'Available')
}
} else {
properties = features;
}
map.getSource('properties').setData(properties);
});
I have faced with the same issue and my solution is use the icon-ignore-placement instead of icon-allow-overlap, and it's still not have any issues
You can find the document here: https://docs.mapbox.com/mapbox-gl-js/style-spec/#layout-symbol-icon-ignore-placement
Hope this will help, thanks!
I have the following setup using the mapbox API. When using geolocate.watchPosition on my laptop and walking around to simulate real time tracking of a user's position on a map, the map marker only updates very occasionally. What am I doing wrong? Is there something wrong with the callback timing? I'm assuming map.on('locationfound'...) will be called when the map.locate() function completes successfully.
L.mapbox.accessToken = 'xxxx';
var map = L.mapbox.map('map', 'mapbox.high-contrast');
var myLayer = L.mapbox.featureLayer().addTo(map);
map.on('locationfound', function(e) {
map.fitBounds(e.bounds);
console.log('location found callback');
myLayer.setGeoJSON({
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [e.latlng.lng, e.latlng.lat]
},
properties: {
'title': 'Here I am!',
'marker-color': '#ff8888',
'marker-symbol': 'star'
}
});
function myFunc(position) {
map.locate(); //part of mapbox API
}
watchId = navGeolocate.watchPosition(myFunc, {}, {});