Mapbox gl - Custom filter and render of PBF tiles - mapbox-gl-js

map.addSource('testLayer', {
'type': 'vector',
'source-layer': 'testLayer',
'tiles': [
'http://localhost:3004/{z}/{x}/{y}.pbf'
],
'minzoom': 0,
'maxzoom': 24,
});
map.addLayer({
'id': 'urban-areas-fill',
'source': 'testLayer',
// Custom styling based on filtering. Help needed here
});
Above pbf tile contains point data, along with height attribute. I want to collect height attribute of all the points within each tile, take an average of it per tile, use it for each individual point's height value (respective to that tile) to perform certain filtering (if else) and assign colours accordingly to display. Also, I want to convert the final rendering of each point as pixel (ie rectangle), and not as a circle. Thanks :)

Related

Mapbox raster Image quality changes with zoom level

I have a floorplan image added on top of Mapbox as a Raster, everything works as expected except as I zoom out the image gets blurrier and its features are unrecognizable. please see below what I mean.
Zoom = 20
Zoom = 19
Zoom = 18
Is this something I can change, or is it how Mapbox handles the raster display?
Here is my code
map.on('load', () => {
map.addSource('radar', {
'type': 'image',
'url': 'URL_TO_IMAGE',
'coordinates': [...]
});
map.addLayer({
id: 'radar-layer',
'type': 'raster',
'source': 'radar',
'paint': {
'raster-fade-duration': 0
}
});
});
Because of the way this is rendered as an overlay image, there is no way to really fix this.
My answer is to actually just convert the image to a GeoTIF and use the utility gdal2tiles to convert the image to a tileset. For each zoom level, the tiles are rendered differently and the image will always be as intended. It is not trivial if you have never worked with GeoTIFs or gdal before, but with effort you can get it to look perfectly as desired.

How I can I get geojson boundary array from existing layer using mapbox gl?

I am using one of the custom tileset of tilling service in mapbox. I loaded that custom tile layer in map using below code.
map.addSource('california', {
type: 'vector',
url: 'mapbox://xyz.california'
});
map.addLayer({
'id': 'terrain-data',
'type': 'fill',
'source': 'california',
'source-layer': 'california',
'layout': {},
'paint': {
'fill-color': 'black',
'fill-opacity': 0.5
}
});
Above code is filling out the inner area with black color. But I want to fill out the outer area of that polygon. Only one way I know to do that is getting difference of whole map with that polygon by using turf.js. After that I will be able to fill the outside area.
Now the question is how can I get the geojson ploygon array of above added layer? So I can calculate the difference.
You can't easily get the complete geometry of a polygon from a vector tile set, because it has already been cut up into tiles. You would have to either find a way to merge them together, or get your geometry into the front end as a complete geojson first.

Mapbox-gl fill layer distorts rendering on higher zoom

I'm using mapbox-gl version 0.46.0-beta.1 (With ReactJS).
I've drawn simple fill layers using GeoJSON source.
The coordinates used to draw the fill are
Coordinates Data:
At a specific zoom level, the polygon renders as expected.
Expected Layer:
But on zooming in, the polygon distorts.
Distorted Fill Layer:
The code I'm using is:
`let paint = {
'fill-color': 'Some Color',
'fill-opacity': 0.4,
'fill-outline-color': 'Some Color'
}
let uniqueID = 'someuniqueID';
map.addLayer({
'id': uniqueID,
'type': 'fill',
'source': {
'type': 'geojson',
'data': {
'type': 'Feature',
'geometry': {
'type': 'Polygon',
'coordinates': [polyCoords]
}
}
},
'paint': paint
})`
We were able to solve the same problem by making sure the first point in the polygon is also the last. For this polygon, you should add the point:
[28.6045067810482..., 77.3860210554725...]
I also had this issue. For a bounding box of coordinates for mapbox, having just the 4 coordinate pairs to create the polygon does create rendering artifacts, directly like above. When making your coordinate bounding box as a polygon, be sure to enter a 5th record, which would be the same as your coordinate at coor[0], where coor is your array of coordinate pairs. You will only notice the weird rendering and re-drawing when zooming, this in fact made it go away for me.
For example:
var coors = [[+sw_lng, +sw_lat], [+sw_lng, +ne_lat], [+ne_lng, +ne_lat], [+ne_lng, +sw_lat]]; //makes a 4 pointed polygon
coors.push(coors[0]); //then continue

Mapbox GL JS: zoom to filtered polygon?

I am using Mapbox GL JS to display a polygon layer. I would to allow the user to choose a name from a dropdown, and then highlight and zoom to the matching polygon.
I already know how to highlight the matching polygon using map.setFilter, but I don't know how to zoom to the bounds of the matching polygon. This is my current code:
map.addLayer({
'id': 'polygon_hover',
'source': 'mysource',
'source-layer': 'mylayer',
'type': 'fill',
'paint': {
'fill-color': 'red',
"fill-opacity": 0.6
},
"filter": ["==", 'CUSTNAME', ""]
});
// Get details from dropdown
custname.on("change", function(e) {
// get details of name from select event
map.setFilter('polygon_hover', ["==", 'CUSTNAME', name]);
// Get bounds of filtered polygon somehow?
// var bounds = ??;
// map.fitBounds(bounds);
});
I have examined the Mapbox example of zooming to bounds, but it assumes that you already know what the bounds are.
Is there any way it's possible to get the bounds of the polygon matching a map filter in Mapbox?
I've the following code to fitBounds to Polygon center coords:
var coordinates = f.geometry.coordinates[0];
var bounds = coordinates.reduce(function (bounds, coord) {
return bounds.extend(coord);
}, new mapboxgl.LngLatBounds(coordinates[0], coordinates[0]));
map.fitBounds(bounds, {
padding: 20
});
Where f is one Feature.
I found a solution to your problem. Leaflet has a polygon Class which takes an Array of polygon coordinates and has a function called getBounds() that returns south west and north east bounds. However, Leaflet doesn't follow the convention of LngLat, its format is LatLng. Therefore, you have to switch it. I took an example out from Mapbox Show drawn polygon area, and added exactly what you're looking for.
var polygon = data.features[0].geometry.coordinates;
var fit = new L.Polygon(polygon).getBounds();
var southWest = new mapboxgl.LngLat(fit['_southWest']['lat'], fit['_southWest']['lng']);
var northEast = new mapboxgl.LngLat(fit['_northEast']['lat'], fit['_northEast']['lng']);
var center = new mapboxgl.LngLatBounds(southWest, northEast).getCenter();
// map.flyTo({center: center, zoom: 10});
map.fitBounds(new mapboxgl.LngLatBounds(southWest, northEast));
I see that the question is still relevant - I solved it making a separate request to the database containing all points of a given polygon and building bounds [[minLng, minLat], [maxLng, maxLat]].
All attempts to address geometry of already rendered or source features didn't work for me - most probably because Mapbox doesn't keep initial geoJSON in the tiles.

Mapbox GL JS: Display map labels above layer?

I'm using Mapbox GL JS, with a Mapbox Streets base layer. I have added a polygon layer with white borders and a transparent fill, but I'm finding it hard to read the basemap labels underneath the polygon layer. See how the labels are covered by the white borders:
Is there any way I can make sure the labels are on top of the polygon layer, or at least not obscured by it?
My code looks like this:
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v9',
center: [-2.839, 54.579],
zoom: 4
});
map.on('load', function () {
map.addSource('constituencies', {
'type': 'vector',
'url': 'mapbox://pcsu.xxx'
});
var constituencyLayer = map.addLayer({
'id': 'constituencies',
'source': 'constituencies',
'source-layer': 'constituencies',
'type': 'fill',
'paint': {
'fill-color': 'rgba(162,181,205,0.6)',
'fill-outline-color': 'white'
},
'layout': {
'visibility': 'visible'
}
});
Have a look at this Mapbox example and use the second argument of map.addLayer(layer, [before]). If this layer before exists, the new layer will be placed before/below it. I think the argument naming is a bit confusing here.
The name of the lowest label layer depends on the style. Most of the time you're looking for housenum-label. There's also a discussion in the Mapbox github issues how to ease this process, e.g by introducing placeholder layers.