How to change map color by current zoom level with mapbox gl js? - mapbox

My question is about mapbox gl js.
How to change map fill-color by current zoom level?
The fill-color of this map has population growth rates by country, with a gradation from minimum to maximum. However, if the zoomed location has similar data, the fill-color difference becomes difficult to understand. So, I want to refer to the tile information according to the zoom level, get the country on the screen, and redraw it.
I searched a lot, but I couldn't figure out how to get the information on the screen. Please let me know if you have any information.
Zoom Level: 1
Zoom Level: 3
Thank you!

Your question initially asks:
How to change map color by current zoom level with mapbox gl js?
For that, you use an expression like 'fill-color': ['interpolate', ['linear'], ['zoom'], ...]
But what you want is something very different:
However, if the zoomed location has similar data, the fill-color difference becomes difficult to understand. So, I want to refer to the tile information according to the zoom level, get the country on the screen, and redraw it.
It sounds like what you want is context-sensitive color scaling. That is, instead of a fixed scale of colors where dark green always means X and light green means Y, instead, dark is the lowest value in the current viewport and light is the highest value in the viewport.
This does not have anything to do with zoom.
The steps you need are:
Detect when the viewport has changed: map.on("moveend", ...)
Find what values exist within the viewport: map.queryRenderedFeatures(...)
Calculate a new expression based on those values.
Set the new expression: map.setPaintProperty(...)

Related

Equivalent of map.cameraForBounds without a Mapbox GL Map instance

With Mapbox GL JS, I can get a center and zoom level to show all of a given bounding box using the cameraForBounds method:
const {center, zoom} = map.cameraForBounds(
[
[sw.lng, sw.lat],
[ne.lng, ne.lat],
],
{
padding: 20,
bearing,
pitch, // probably ignored?
},
);
(The typings say that pitch is OK but the docs don't mention it and neither does the implementation, so I assume it's ignored.)
This usually works great, but there occasionally situations where I want to figure out the center/zoom before the map is initialized. It seems like the bounds → camera transformation should just be math, not requiring a Map instance.
How can I go from bounds and bearing (and ideally pitch) to a center/zoom that will include those bounds without an instance of a Mapbox GL map?
You can't, for the simple reason that you don't know how many pixels this map will occupy. Setting a centre and zoom determines how much area (and which area) will be covered by each pixel in the middle of the map. The bigger the map DOM element is, the more area will be covered by the area within the map.

Displayed zoom level vs tile zoom level: pixel density?

Tiles come with a zoom level, and depending on the area that is viewed, leaflet fills the display with tiles of a certain zoom level.
Currently, the number of pixels in the display and the number of pixels in a tile, are tightly bound together, if I understand correctly. Or actually, it is probably the html/css pixels, which are no longer device pixels.
I believe that these are actually two fundamentally different zoom parameters, especially when (mobile) devices have varying pixel densities (window.devicePixelRatio).
My question is: is it possible to control which zoom level of the tiles is shown, as a function of the zoom level that is displayed (geospatial distance vs screen distance)?
The reason I ask is that the level of detail is often different for different zoom levels. On some devices displaying tiles of higher detail might actually look good. Some map sources, like topographic maps from http://geoportail.gouv.fr even change the map style drastically between different levels. I want to play with the possibility of showing, say, zoom level 15 over a large physical area on a hdpi display, where leaflet would normally show zoom level 14 or 13.
I found that by modifying the option "tileSize", passed to the TileLayer constructor, choosing a value lower than the default 256, I get almost what I want. However: the positioning is way off. Is there a simple solution for this?
After some digging in the source code, I noticed, as IvanSanchez pointed out, that the functionality is present indeed.
detectRetina applies a zoom of 'one up', that is bumping the zoom by one and dividing the length of the sides of the tiles by two, if the device has a devicePixelRatio >= 2.
I want to apply an arbitrary offset at will. This can be done at once for a layer by initializing with the options
let zoomOffset = 2;
let options = {
"detectRetina" : false,
"zoomOffset" : zoomOffset,
"tileSize" : 256 / Math.pow(2, zoomOffset)
}
However, it's even neater to have the possibility to do this realtime while viewing, so I wrote this L.Control-plugin: Leaflet.Control.DetailLevel
I want to play with the possibility of showing, say, zoom level 15 over a large physical area on a hdpi display, where leaflet would normally show zoom level 14 or 13.
It seems that what you want is already implemented by the detectRetina option of L.TileLayers. Quoting the docs::
If true and user is on a retina display, it will request four tiles of half the specified size and a bigger zoom level in place of one to utilize the high resolution.

Display mountain names at lower zoom level

How can I display layers that by default seem hidden to show at lower zoom levels? For example, I am trying to display mountain names ("poi-parks-scalerank1") at zoom level lower than 10. Is that possible?
It is not possible to show vector tile data at zoom levels lower than the tiles in which it is physically present. For instance, if the mountain names only exist at zoom 10 and above (that is, any vector tiles at /9/x/y.pbf don't have them), there's nothing you can do to force Mapbox-GL-JS to render them.
(The reverse is not true: you can "overzoom" vector tiles by setting maxzoom on the layer.)
It's possible (but very unlikely - Mapbox's tiles are pretty optimised) that the data exists in a lower level than the style actually calls for, so you might as well have a go, as leelum1 suggests.
Otherwise, you will have to obtain the mountain name information somehow and create your own layer, then style it.

Transparent shader allows the objects below to show on top

In my scene, the smileys(Quad with png image) are placed at Y:0 and the dots(Quad with tiling 3X3) are placed at Y: -0.25.
The shader I need to use for the smileys is Transparent-Diffuse as I am using a circle png image.
But the dots I use below are showing up above the smiley. Using any other shader like Diffuse solves the issue but the smiley becomes a square.
Screenshot:
If you need any more clarifications please dont hesitate to ask.
Edit:
I have attached the shader details of both the smiley and the dots from the inspector panel.
link: http://postimg.org/image/cvws1os7d/
Edit 2:
I have found that the issue should be with the MainCamera and especially with distance & "Field Of View".
I need to use "Perspective" as projection type and 140 as Field of View.
If I change the projection type to Orthographic the issue is completely fixed.
The below screenshots show how the distance and Field of View controls the appearance of the dots over the smiley.
Screenshot 1:
Y position: 8.48
Field of View: 30
link: http://postimg.org/image/s31tttrkp/
Screenshot 2:
Y position: 9.7
Field of View: 30
link: http://postimg.org/image/f71sq0y4b/
Screenshot 3:
Y position: 11.41
Field of View: 30
link: http://postimg.org/image/3uk4az3d3/
Screenshot 4:
Y position: 1
Field of View: 140
link: http://postimg.org/image/bul9zwg7z/
Can this be a clue?
Just a couple of info, on how transparency is typically implemented (not only by Unity).
Meanwhile opaque objects can be drawn in any order (even if sorting them in front-to-back order can eventually improve some GPU performances relying on an early z-cull). Which pixels are visible can be deduced using the depth value stored into the z-buffer.
You can't rely on z-buffer for transparency.
For rendering translucent objects a typical approach is to draw them after all opaque objects, and sorting them in back-to-front order (transparent objects more distant from the camera are drawn first).
Now the question is: how do you sort objects? with a perspective camera and meshes of a generic shape, the solution is not obvious.
For quad meshes oriented parallel to a ortographic camera view plane, the z order is implicitly correct (that's why it always works for you).
You can also notice that camera position influences the drawing order, because with perspective camera the order is calculated as distance between object position and camera.
So what can you do with Unity3d, in your specific use case scenario?
A couple of tricks:
Explicitly set the render queue of the material
Explicitly set the render order inside the shader (similar of the above, but equals to every object with the same shader)
Fake the depth using Offset into the shader (not that useful in your case but worth to be known)
hope this helps
EDIT
I didn't know that, the camera transparency sorting mode appears to be customizable. So this is another solution, maybe the best for your case if you want to use a perspective camera.
If you are using Sprite Renderer component to render the images, you have to change the rendering order with Sorting Layer and Order in Layer parameters instead of changing the Y position.
Sorting layers can be added by clicking the "default" and choosing "Add Sorting Layer..". The order of the layers is changed by dragging them into different order. With Order in Layer lower numbers are rendered first. This means that higher numbers will be drawn on top of lower ones.

iPhone : MapKit and displaying the current Map Scale

I need to display on the map a scale showing how far a inch / cm is for example. This will need to change depending on the zoom level.
My theory is that if I know the length of the map, and the length of the graphic, If I know what the current scale of the map was I could just do some maths to work out the graphic indicator scale.
So is there a way to get the current zoom lvl in meters? Is it linked to the span or something?
The zoom level is linked to the span - you first need to get the span of your map view, and then convert it into meters.