How to find all layers in Mapboxgl ? Ultimately I want to show custom layer only on water and not on land - mapbox-gl-js

I created a custom circle layer. I want to show this layer only on water and not on land. I managed to do the opposite (ie: showing the layer on land and not on water) using below command. Refer this image for better understanding
map.moveLayer('polygon','water');
Now I need to know the land layer which is used by mapboxgl so that I can call function map.moveLayer('polygon','land'); to achieve what i want.
I need help to find the different layers present in the mapboxgl-streets map. But unfortunately, Mapboxgl doesn't have map.eachLayer function.

You can use the Map#getStyle method to get a serialized representation of the entire style including the layers.
map.getStyle().layers

It depends on the map style you're using. In general, you either have to look at its source or load it in Mapbox Studio to identify the correct layer name. Also keep an eye on https://github.com/mapbox/mapbox-gl-js/issues/4173.

Just to add to Lucas' answer (which is still correct), map.getStyle().layers provides all layers in the style, including ones you have explicitly added (via map.addLayer()), and those that are included in the style (which could be a lot). Careful how you filter through these. For my case, I created arrays to hold the layers I created myself, to make future iteration simpler.

Related

Hide polygons that are within a specific area

I'm trying to create an experience where I have a couple of detailed 3D models of buildings on the map with extruded building footprints of neighboring buildings via a vector tile source. The 3D models would be the main focus point and the extruded footprints would be for reference. One challenge I'm running into is that I have a global building footprint layer and it has a footprint for the 3D buildings which doesn't match up perfectly. Additionally, when extruded, it ends up merging/overlapping the nice 3D models.
I'd like to be able to hide the individual footprints that overlap the 3D models. My original thought was to grab the bounding box of the 3D model and then use the new within style expression, but it looks like this will only filter points and lines, not polygons. The building footprint polygons have no unique information in them that I could use to filter on.
I know I could monitor map movements and query the rendered features and manually detect intersecting polygons, but since there is no unique property on the footprint, I can't filter or use feature state.
Any ideas of how to efficiently avoid rendering individual polygons in a specific area that come in from a vector tile source?
It is a common issue that the buildings layer in Mapbox Streets don't contain any unique attributes to allow filtering or rendering differently.
The best solution is usually to source a different buildings layer, and in this case, remove those redundant buildings in pre-processing.
I can think of one rather crazy workaround that might work here, although the performance may be poor.
Add the building layer with very low opacity, of type fill, essentially invisible. (Maybe invisible would work.) Call your main source buildings`.
Create a secondary building source of type geojson, and a secondary fill-extrusion layer. Call this source buildings-copy.
On map move or moveend, use querySourceFeatures to obtain a copy of all buildings.
Process this copy using Turf to remove the buildings you don't want, and call setData to set the copy as the data for buildings-copy.
You may need to do some clever caching to get reasonable performance.

Best Practice to display local markers and a wider area of points of interest markers?

I've created a base layer and 6 different overlay (Points of Interest) layers for a leaflet map.
The base layer of markers can appear on the map almost anywhere in the world, but I want the POI layers to appear only if they are in the same area (mapBounds) of the base layer. Probably the screen size.
All the data is pulled from a MySQL database and using Ajax I create the various sets of markers from two different tables, base and poi. This much is all done and working, you can see it at https://net-control.us/map2.php. The green and blue markers are from the base table, other markers are currently selected for view by clicking on the appropriate icon in the lower right. The only one active at the moment is 'Fire Station'. But if you zoom out far enough you will see additional fire stations in the Kansas City area, and in Florida. Those sets are not needed.
After the query runs I create a fitBounds variable of the base layer and another poiBounds for the poi layer. But I'm not sure I need the poiBounds. The number of base markers is generally less than 50 for the base query, but if all the poi markers are pulled world wide that number could be very large.
So I'm hoping someone can help me determine a best practice for this kind of scenario and maybe offer up an example of how it should be done. Should I...
1) Download all POIs and not worry about them appearing outside the base bounds layer? Should I inhibit them from showing in the javascript or in the SQL? How?
2) If I inhibit the unwanted points from SQL do I test one POI at a time to see if its included in the base bounds? How? Are there MySQL functions perhaps to work with this kind of data?
I'm fairly new at leaflet maps and would appreciate examples if appropriate.
2) If I inhibit the unwanted points from SQL do I test one POI at a time to see if its included in the base bounds? How? Are there MySQL functions perhaps to work with this kind of data?
You probably want a column of type POINT, a spatial index on such column (which internally is likely to be implemented as an R-Tree), and spatial relation functions on your SQL query to make use of that index.
Start by reading https://dev.mysql.com/doc/refman/8.0/en/spatial-types.html. Take your time, as spatial databases, spatial data types and spatial indices work a bit differently than their non-spatial equivalents.

Multiple extruded polygons Mapbox iOS

Latest Mapbox SDK and Swift
So I've been battling with this for 3 days now...
I'm trying to use an array of coordinates to create a line of extruded cylindrical pillars (or a sloped solid "wall" if that makes sense... But I've found this to be harder than just a line of pillars)
I've read most of Mapbox's docs but can't get my head wrapped around the use of MGLShapeSource, MGLPolygon and MGLFillExtrusionStyleLayer.
From what I can tell, one needs to add a polygon to a source, add that source to the map object, then apply the extrusion layer to that source... However, I can't figure out how to make that work.
This is what I've managed so far, as a solid wall... But using pillars, I could adjust the height as the line goes, creating a sloping look
Any advice would be appreciated. I'd paste my code here but it is WAY too messy and too much after 3 days of trial and error. haha.
BONUS: I'd like to animate the path being created as it goes... So pillar 1 appears at a certain height, then pillar two and a lower height, then pillar 3 and so on. This involves modifying the source apparently - have little idea on how to do that though :(
Are there individual height properties associated with the points in your underlying data? Your end goal is definitely possible, but it's dependent on whether or not you have the data for reference by your style layer.
Unfortunately, the Mapbox site doesn't have any iOS examples explicitly tied to this. But, the 3D buildings example follows basically the same flow. (i.e. mapView.addSource -> MGLFillExtrusionStyleLayer -> layer.fillExtrusionHeight).
The crucial bit in the building example is using .fillExtrusionHeight with a "forKeyPath" expression to set the extrusion height based on the corresponding property in your data:
layer.fillExtrusionHeight = NSExpression(forKeyPath: "height")
If you don't have height within your underlying data, you'll have to get some in order for the extrusion styling to work this way.
⚠️ Disclaimer: I currently work for Mapbox ⚠️

How is the Layer Order is decided in leaflet map?

When I use the following code to go through all the layers in a leaflet map,
map.eachLayer(function (layer) {
console.log(layer);
});
I just wants what rule is used to create this order. Is it because of the ZIndex of the layer? Or is it because the layer is added in different time? If the layer is added early, it will be in the bottom.
Thanks,
Good question, it seems the LeafletJS docs don't say anything about the ordering of the layers via eachLayer, so...
Looking at the code on github, L.Map.eachLayer loops through L.Map._layers which is an object (not an array). So technically the layers could come back in any order...
That said, the individual layers are added to the _layers object in the order they are added to the map. So in all likelihood, eachLayer will be iterating over the layers in that same order (whatever order they were added to the map).

Is using MapServer to merge several MapLayers on runtime to use with Leaflet a good idea?

MY PROBLEM
We´re doing a Project right now where we have to display a huge image (containing chemical compounds and elements, so not geo referenced) as a map within a Web-Application (with Leaflet). The image itself is an Adobe Illustrator-File, so its actually a bunch of vector graphics. To makes things easy, we just converted it into a large .png (27.000x19.000 px) and then used MapTiler to create the needed MapRessources for Leaflet, easily included within a TileLayer.
The Problem is:
The user needs to be able to dynamically add and remove different Layers (== Filter) of the map to show more or less informationes from the picture. So we first created those layers within the Illustrator-File, then exported every layer as its own transparent .png-File, mapTiled it and included it as an own Leaflet-Layer.
Right now, we have 6 Filter-Layers and two more base Layers for the background and an overlay. This means that when all Filters are activated (which is the default), we have 8 Leaflet-Layers stacked on top of each other at once. As you can imagine, this causes some performance issues in the Browser, since Leaflet has to load and render 8 Layers with all its Tiles (depending on Screen size up to 25 at once) for every zoom or drag-action. Its still in a point that is not impossible to bear, but we are expecting several more filters to come and therefore wanna stay scalable in the future.
This means we will somehow have to change our approach of generating the Layers.
MY APPROACH SO FAR
Since we actually have a vector-graphics based map, i thought there have to be better alternatives. But it seems that we have a rare case of requirements, since my researches mostly ended in dead ends, especially since most of the cases only cover REAL geographical maps, but what we have is a raster map. I also thought about somehow putting the map into a GeoJSON or redraw it somehow directly with SVG, but since we have LOTS of single elements on the map (> 20k), I dont think this would perform much better.
So I kind of need to stay with the Bitmaps, and therfore my main goal is simple: I wanna reduce the number of layers by merging the tiles of the currently activated Filter into one single .png which then gets delivered to leaflet within ONE Layer. I spent some hours now researching, but I always run into dead ends since it seems we have a rare case of requirements here (especially since most people deal with georeferenced data, not with custom raster maps).
So right now, I can think of 2 different options:
Create ONE Layer for every Filter-Combination. This means we would have to create 2^n layers, so this would only work up to a certain number of filters (which probably will increase) - therefore, i would prefer another solution (this is only last case)
Use MapServer and somehow import my Layers. Then we could merge the Layers on runtime with a query (I read about Union Layer here) and therefore only deliver ONE Layer to leaflet.
MY QUESTION
I have absolutely no experience with MapServer and im therefore not even sure if that is a use-case or if its capabale of doing this, and more important: If it would really give us a performacne boost, since it probably requires a lot of logic ServerSide.
Before i start spending another hours to try this out:
Can someone who already worked with MapServer give me some feedback if that is even a good idea or if I am misunderstanding something with MapServer completely?
Also, if someone has another alternative or idea for me, you´re more than welcome to share it, im grateful for every input. :)
Thanks in advance!
You might want to look at OpenLayers where you can display a mix of raster and vector layers. another option might be mapcache a tile caching engine part of the mapserver project. This has the ability to do vertical assembly of tiles. So if you case where you have 8 layers you can ask mapcache to stack all the eight tiles into a single tile. You can give it a list of layers to stack and it takes care of it for you. You can also do this with mapserver. The difference being that mapcache is a lightweight apache module that just works with tiles and is probably a little faster. Mapserver is a cgi-bin process and work efficiently at rendering and combining raster layers but is probably not as fast as mapcache for simple assembly of tiles.