Mapbox/Leaflet map rotation - leaflet

The app uses mapbox with leaflet Js.
Theres a callback for the location-found event and we set a marker with user's location.
I'd the like map to rotate according with the user location, like a compass.
Any way to accomplish this?

Leaflet doesn't support map rotation (yet), or perspective, for that matter. See bug #268.
I did some work for this in the rotate code branch, but that is still kinda experimental and breaks easily. I don't think it will make it to the Leaflet core, as WebGL is a more promising (and less messy in the long run) way of achieving better results at map rotation than CSS transforms (which is what the rotate branch is about).

MapBox has a "bearing" option for that. Here https://jsfiddle.net/rwnfbu7c/1/ is a example
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v11',
// camera options properties - https://docs.mapbox.com/help/glossary/camera/
center: [34, 28],
bearing: -65, // bearing in degrees
zoom: 2
});

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.

Leaflet or mapbox icon rotation like computeheading

I have a map in leafletJS and when the icon moves along, I have the angle and I am using the Leaflet.RotatedMarker plugin to rotate the icon to face where its heading.
Does leaflet js have a plugin that can enable me to not supply the angle myself ...
L.marker([48.8631169, 2.3708919], {
rotationAngle: 45
}).addTo(map);
...and instead use a function like gogle maps' computeheading() ?
Edit:
Does mapbox have a function like computeHeading
https://github.com/bbecquet/Leaflet.RotatedMarker
js:
var boat_marker = L.marker([set_lat, set_long], {
pid: guid(),
// rotationAngle: 45,
icon: boatIcon,
draggable: true,
}).addTo(mymap);
function rotated_point() {
boat_marker.setRotationAngle(90);
}
No.
Leaflet has only a minimal set of geodesy-related functions. Functions to calculate headings, azymuths, geodesic distances or great circles are not needed for basic Leaflet functionality, and are not included.
A popular approach to this kind of problems is to rely on the javascript bindings of geographiclib for geodesy-related calculations (such as heading/azymuth), in the same way turf.js helps with geoprocessing of vector data.
Note that geographiclib is not a Leaflet plugin, but rather a generic set of geodesic functions. You will need to use a bit of care to get the latitude and longitude components of L.LatLngs, and fetch only the azymuth (and drop the distance) from the solution to the geodesic problem.

Is it possible to set a "max allowed pitch" for a Mapbox GL map?

I am unable to find a method to prevent the user from setting the pitch angle of the map too far. I am working with high resolution weather data, so I want to prevent them from setting the pitch so extreme that they can see far away from the intended area. That puts me in a position to either extend the data (WAY too much bandwidth would be used) or just not display it there, making it ugly. I would not like to eliminate the pitch ability completely, as it helps with visualization.
I have looked as much as I can in the documentation but since I cannot find the information and I do not even have a code snippet I have tried because I have nowhere to start. Is there any way to (for example) let the user pitch up to a certain degree only? I made an example image where the left pitch would be OK but not the right, as in that current zoom level it would let them see too far away. If this is not possible, I am open to alternate methods, if any.
Use the render event to check the value of the angle:
map.on('render', (e) => {
if (e.target.getPitch() > MAX_PITCH) e.target.setPitch(MAX_PITCH)
})
[ https://jsfiddle.net/05o4e7dr/ ]
There's now a maxPitch option that you can pass to the Map construct. And, as of Mapbox GL JS 2.0.0, you can set it to pretty high values, all the way up to 85°:
let MAX_PITCH = 85
new mapboxgl
.Map({
container: 'map',
// ...
pitch: MAX_PITCH,
maxPitch: MAX_PITCH,
});

How to visualize isometric map in Mapbox, Openstreetmap

I saw very nice map visualization by the city of Melbourne here:
http://www.pedestrian.melbourne.vic.gov.au/#date=11-03-2018&sensor=Col270_T&time=10
The map on this page is using Mapbox and OpenStreetMap (based on the credit in the bottom right corner). But I would like to know how did they accomplish tilting the map into Isometric.
I tried looking for a solution, but could not find the working one.
e.g. There is a link to this: http://osm.kyblsoft.cz/3dmapa/info. But its Github seems to disappeared.
Thank you very much for your help :)
See Set pitch and bearing in the Mapbox GL JS documentation.
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v9',
center: [-73.5804, 45.534830],
pitch: 60, // pitch in degrees
bearing: -60, // bearing in degrees
zoom: 10
});

Mapbox.js - Fallback tile image from lower zoom level, when missing in requested zoom level

I serve map png files from disk and I have tile pngs for whole city in zoom level 15. I have also tiles in zoom levels 16-18 but only for certain areas.
I would like to set up the tile Layer, so that when the user is in zoom level 18 the map will display scaled tiles from level 15 as a fallback.
I tried setting option maxNativeZoom, but didn't work for me.
Here is my code:
offlineLayer = L.mapbox.tileLayer(tileJSON, {
minZoom: 8,
maxZoom: 18,
maxNativeZoom: 15
});
map.addLayer(offlineLayer, 'Offline', 1);
Can I make it work, that way using some options or do I need to hack it some way? Or is there some example code for that?
Just to let people know that I wrote Leaflet.TileLayer.Fallback plugin some time ago to address this exact use case:
Replaces missing Tiles (404 error) by scaled lower zoom Tiles.
Demo page
In OP's situation, you would just specify the maxZoom Tile Layer option as usual, and whenever a tile is found missing at the current zoom level, the plugin will try to replace it by the "parent" tile at the previous zoom level (scaled and clipped appropriately so that it fits the missing tile), and so on until a tile is found or minZoom is reached.
L.tileLayer.fallback(urlTemplate, {
minZoom: 8,
maxZoom: 18
});
Disclaimer: I am the author of that plugin.
When you say that it didn't work for you, I'm guessing that what you're seeing with the code above is level 15 tiles for everywhere even when at zoom levels 16-18 in the areas where you have tiles at those levels? That's the expected behavior of maxNativeZoom. TileLayer creates all of the tiles for a given zoom level and map bounds and sets the "src" to a URL containing the current zoom level. If the current zoom level is greater than "maxNativeZoom" then the zoom level in the URL is set to "maxNativeZoom". For example, src="http://a.tile.openstreetmap.org/15/16368/10896.png" would be used for zoom levels 16-18 if "maxNativeZoom" is set to 15.
There is no logic in the code that checks to see if an image actually exists for that tile at that zoom level.
If your tiles are in a single data set then you could modify the code in TileLayer to check for a HTTP 404 return code for the generated URL and if one is received then create a new URL using "maxNativeZoom". If your tiles are in multiple data sets (i.e. one for zoom level 15 and less, and another for zoom levels 16-18) then I think you'd have to write a TileLayer that supports multiple data sets.