How to add hover effect to new layer created with custom geojson - javascript

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

Related

How to get Mapbox GL JS to load all tiles in map extent

I am trying to use some US Census Bureau vector tiles hosted on ArcGIS online (https://gis.data.census.gov/arcgis/rest/services/Hosted/VT_2010_140_00_PY_D1/VectorTileServer) with Mapbox GL JS.
It doesn't seem like all the tiles to cover the map extent are being loaded. Is there an option I need to pass? I'm not sure if this is a Mapbox or ArcGIS Vector Tile Service issue.
Screenshot 1 - I've outlined the "empty" spaces in red
Screenshot 2 - See how the red area from Screenshot 1 loads when I move the map east
mapboxgl.accessToken = MY_TOKEN;
const map = new mapboxgl.Map({
container: 'mapid', // container ID
style: 'mapbox://styles/mapbox/light-v10', // style URL
projection: 'albers',
center: [-97, 39], // starting position
minZoom: 6,
zoom: 6 // starting zoom
});
map.on('load', () => {
map.addSource("ct2010", {
type: "vector",
tiles: ["https://gis.data.census.gov/arcgis/rest/services/Hosted/VT_2010_140_00_PY_D1/VectorTileServer/tile/{z}/{y}/{x}.pbf"],
minzoom: 6,
promoteId: "GEOID" // promote field to be used as a foreign key
})
// Add a new layer to visualize the polygon.
map.addLayer({
'id': 'cdfi',
'type': 'fill',
'source': 'ct2010', // reference the data source
"source-layer": "CensusTract",
'layout': { },
'paint': {
'fill-color': 'rgb(13,40,75)',
'fill-opacity': 0.5
}
});
});
EDIT: I think my problem was trying to use the Albers projection. Removing that option resolves my issue. Maybe related to https://github.com/mapbox/mapbox-gl-js/issues/11284

Mapbox - Visualisation issue with passed data using jinja2

I'm trying to pass the coordinates for a polygon from my flask app to the html containing the mapbox gl using jinja2.
My flask app looks something like this:
#app.route('/<path:subpath>', methods=['POST', 'GET'])
def show_subpath(subpath):
if request.method == 'POST':
try:
data = request.form
name = 'Eine Karte'
poly = coords
return render_template('/map.html', name=name, polygon=poly)
except:
return 'That didnt work'
The script section containing the map in map.html looks like this:
<script>
mapboxgl.accessToken = 'TOKEN';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v9',
center: [12.940985, 54.063782],
zoom: 10
});
var geom = '{{ polygon }}';
map.on('load', function() {
map.addControl(
new MapboxGeocoder({
accessToken: mapboxgl.accessToken,
mapboxgl: mapboxgl
})
);
})
map.on('load', function () {
map.addSource('iso', {
'type': 'geojson',
'data': {
'type': 'Feature',
'geometry': {
'type': 'Polygon',
'coordinates': geom
}
}
});
map.addLayer({
'id': 'iso',
'type': 'fill',
// Use "iso" as the data source for this layer
'source': 'iso',
'layout': {},
'paint': {
// The fill color for the layer is set to a light purple
'fill-color': '#088',
'fill-opacity': 0.8
}
});
});
</script>
When I use "console.log(geom)" at the end of the script I can see, that the data is passed correctly. However the polygon isn't display on the map. When I hard code the coordinates they appear on the map. How can I visualize the passed data?
Very simple - you passed the polygon to mapbox as a string, while it requires a GeoJSON object. I replicated your code and got
ErrorĀ {message: "Input data given to 'maine' is not a valid GeoJSON object."}
What you want to do is remove the quotes from your geom variable. Just to be on the safe side, you can use tojson so that it escapes certain characters so it doesn't cause unexpected errors, especially when you're using variables in <script> tags.
Modify var geom = '{{ polygon }}'; into:
var geom = {{ polygon|tojson }};
and it should work!
You can also remove the additional variable if you're not doing any extra processing:
map.addSource('maine', {
'type': 'geojson',
'data': {
'type': 'Feature',
'geometry': {
'type': 'Polygon',
// These coordinates outline Maine.
'coordinates':
{{ polygon|tojson }}
}
}
});
Also, make sure that when you pass the arguments from flask, you're not adding quotes to make it into a string object.

Mapbox GL setData to update layer

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

Mapbox markers flashing when using `icon-allow-overlap`

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!

Mapbox clear marker not working

I'm trying to remove marker from my map before I add a different one but the suggested method, although throwing no error, doesn't remove my marker.
$scope.geo.push({
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [$scope.gig.lng, $scope.gig.lat]
},
properties: {
title: $scope.gig.venue,
description: $scope.gig.address + ' ' + $scope.gig.postcode,
'marker-size': 'medium',
'marker-color': '#676767'
}
});
/* show on map */
var markerLayer = L.mapbox.markerLayer().setGeoJSON({
type: 'FeatureCollection',
features: $scope.geo
}).addTo(map);
map.setZoom(13);
map.panTo($scope.geo[0].geometry.coordinates.reverse());
markerLayer.eachLayer(function(m) {
});
According to the documentation I should be able to then call the following to clear all markers but it does nothing.
L.mapbox.markerLayer().clearLayers();
Am I doing something wrong? If not is there a nuclear way of resetting the map?
L.mapbox.markerLayer().clearLayers();
L.mapbox.markerLayer() is a function that creates a new marker layer: this call is creating a new marker layer, and clearing the markers in it.
In your code, you have the lines
var markerLayer = L.mapbox.markerLayer().setGeoJSON({
type: 'FeatureCollection',
features: $scope.geo
}).addTo(map);
You are creating a new marker layer with the L.mapbox.markerLayer() and naming it with the variable markerLayer. So, to clear the markers in this layer, you would call:
markerLayer.clearLayers();

Categories

Resources