Leaflet.js fitBounds with padding? - leaflet

I'm trying to set the fitBounds option in a leaflet map like this:
var bounds = new L.LatLngBounds([[Math.max(lat, borneLat), Math.max(lng, borneLng)], [Math.min(lat, borneLat), Math.min(lng, borneLng)]]);
map.fitBounds(bounds, { padding: [20, 20] });
However this doesn't seem to add any padding ? at least the map "zoom level" doesn't change, and it's always showing the two points in the edges (i.e. one is top far right and the other is bottom far left). For some marker sets, it works ok, the zoom is at a decent level away and you can see everything nicely. However when the items are quite close to each other, it seems it zooms in a bit too much unless I can fit it with some "padding."
Also I'm unsure if the bounds would be correct like that? Should I use instead just:
var bounds = [[Math.max(lat, borneLat), Math.max(lng, borneLng)], [Math.min(lat, borneLat), Math.min(lng, borneLng)]];

map.fitBounds(bounds, {padding: []}) should work. I suggest you to change padding to eg. [50, 50], maybe your padding values are too small.
Check out this JSFiddle example.

Leaflet only zooms between integer-value zoom levels by default. Past version 1.0.0, "fractional zooms" are available with the "zoomSnap" parameter:
var map = L.map('map', {
zoomSnap: 0.1
});
This will allow smaller padding values to be visible, but will also affect scrollWheelZoom behavior.

I came across this problem. As I understand the padding is controlled by the zoom. In my example all padding settings under 10 make no difference. As soon as the padding goes to 10 the map is zoomed out one level and there is padding. Furhter increasing the padding value has no influence, until it is so big that another zoom-out level is reached.

FWI, you can also set a max zoom level to the map like so:
var map = L.mapbox.map('map', 'mapbox.emerald', {
maxZoom: 16
});
this way you can avoid the map zooming in too much in case the markers are too close togther.

Related

How to fit bounds and set max bounds at same time on window resize in MAPBOX?

To fit the map we use mapbox.fitBounds() and to set we do mapbox.setMaxBounds(), which avoid panning. This work's perfectly well on first load.
But on Window resize map get cropped and take the bounds reference from initially set maxbounds. I am trying to fit the map in viewport using setTimeout, so that map first fit on screen and then getting map bounds from mapbox.getBounds() set the value in mapbox.setMaxBounds(). But this is just an hack.
Is there any correct way to do so?
Please help... and thank you..
Hope you are all well...
After many days of struggle, we are able to find the perfect solution, for my own question posted...
Firstly,
mapbox.fitBounds() is the method on passing given bounds as args, will fit the geometry(polygon etc..), making the center point in the middle. But the only thing it does not disallow panning.
However, we can disallow panning using mapbox.setMaxBounds() which allow us to constrained to passed bounds.
But on window resize, somehow mapbox Map change the bounds as per internal logic, which will no longer be the same as passed bounds initially...
In order to fit the geometry on the viewport, at the same time disallow panning on window resize, we use Resize Observer to observe map's container, and in its callback, we just wrote, three lines
Set map.setMaxBounds(null) //to null
set fitbounds(bounds). //bounds of geometry that u have
Get bounds from viewport using
let bnds = mapbox.getBounds();
and finally set in map.setMaxBounds(bnds);
Note to pass the 3. point in requestAnimationFrame instead of setTimeout
UPDATED Code
MaxBounds and custom asymmetric padding in Mapbox GL
Hope this will help...
Thank you.

Getting the div screen location in Leaflet

I am working on a project using Leaflet. I want to place a label for objects on the map. I don’t want the label to appear on the map. I want the label placed above the map, but at the screen or div Left location from a latLng point.
I can’t seem to get the correct position using the functions available. Is there some example I can look at to give me insight? I would think Leaflet could do this.
The key here is to leverage the latLngToContainerPoint() method of L.Map - it will give you the pixel coordinates relative to the map container of the L.LatLng passed.
So create a container for a tick...
<div id="topbar"><span id="toptick">↓</span></div>
<div id="leaflet"></div>
...and use CSS to ensure it's on top of the map container, and has the same width. Then, run a function to translate the map point you want into an offset relative to the top-left corner of the map container...
function repositionEdges(){
var offset = map.latLngToContainerPoint(geopoint);
}
...run that after map initialization, and after every movement of the map...
repositionEdges();
map.on('move zoom', repositionEdges);
...and finally, inside that function, shift the tick horizontally tweaking its style...
function repositionEdges(){
var offset = map.latLngToContainerPoint(geopoint);
document.getElementById('toptick').style.left = offset.x + 'px';
}
You can see a working example at https://next.plnkr.co/edit/60qrWND50mCOQ11T?preview .
This is just one approach. The specific implementation will be different if you're using more than one point, or if you want to use <canvas> for drawing the ticks.
See also the graticule, edge scale bar and edge markers plugins from the Leaflet plugins list. Those plugins contain implementations of similar concepts.

Map Center & Bounds do not update when Container Div is Resized

(pretty new to Mapbox and JS, so I'm in a bit over my head)
I'm working on a page where the user needs to adjust the size of map container. It needs to be able to get accurate bounds and center point of the resized map (via map.getBounds and map.getCenter).
When I use JS to adjust the size of the container div, the center and bounds are not adjusted.
Fiddle: http://jsfiddle.net/xcow63sm/3/
Panning/zooming results in updated center and bounds. Browser window resize (if you have width or height set to 100%) works too. I would expect changing the container dimensions would adjust center and bounds.
However, if you use the form fields to adjust the height/width of the container div, the center and bounds do not. I've tried (with increasing desperation):
function resize (){
var inputwidth = document.getElementsByName("mapwidth")[0].value;
var inputheight = document.getElementsByName("mapheight")[0].value;
var mapDiv = document.getElementById('map');
var mapcenter = map.getCenter();
mapDiv.style.width = inputwidth;
mapDiv.style.height = inputheight;
map.updateSize();
map.update();
map.resize();
map.invalidateSize();
document.getElementById("mapcenter").value = mapcenter;
Edit: this seems to apply but I can't make sense of it: Resizing a leaflet map on container resize
If I understand you, you have two issues: you don't like how the map is positioned after its size changes, and you're getting white space.
Map positioning after resize
There are at least three valid options for how a map should update if, say, its width and height are suddenly doubled:
keep the same northern and western bound, extend the eastern and southern bounds. (Expanding the viewing area right and down)
move all four bounds outwards (keeping the centre of the map in the same place)
leave all four bounds where they are are, but change the zoom, so the same geographic area is displayed, but in more detail.
I think your issue is that Mapbox is choosing option 1, but you want one of the other two options. The solution, as I think you've discovered, is simply to do your own maths and set the bounds how you want them.
Map failing to repaint correctly
Your second issue is that when you resize, calling map.resize() isn't updating the internal size of the map properly, and you're left with white space. The reason for this is you're using animated CSS properties. So when you do this:
mapDiv.style.width = inputwidth;
mapDiv.style.height = inputheight;
map.resize();
This doesn't work because the map's size hasn't actually transitioned to the new size yet. You can work around it like this:
mapDiv.style.width = inputwidth;
mapDiv.style.height = inputheight;
window.setTimeout(()=>map.resize(), 500);
There's probably a better event you can listen to, to keep updating as the map area expands.
Updated fiddle here: http://jsfiddle.net/xcow63sm/11/
Btw you should consult the documentation here. I'm not sure where you got map.updateSize() from but that's not Mapbox-GL-JS :)

Rendering OpenStreetMap in OpenLayers 3 with more detail and higher DPI

I'm using OpenLayers 3 and OpenStreetMap to print maps on paper, and for this I'd need to render the maps with more details and higher DPI than are shown on the screen. I'm using CSS to set the size of ol.Map's target in centimeters to the desired size for the printout (.map { width: 7cm; height: 6.3cm; }).
By default OpenLayers shows one of my maps like this, which is too low detail for my needs:
By changing the map size with map.setSize(map.getSize().map(function (x) { return x*2; })); I'm able to increase the detail closer to what I need:
But the problem with this hack is that when the window is resized, the size is reset and it will look wrong like this:
How would I be able to control the OSM zoom level and map DPI independently of the map's size on screen to achieve the desired outcome (the second picture) reliably?
A solution I've found is to put the map inside two nested divs. The inner one has, for example, width: 200%; height: 200%, and the outer one would have transform: scale(.5) translate(-50%,-50%);. This would double the resolution the user sees.
This approach changes the pixel zoom level relative to the zoom level on screen. However, it needs to be recalculated and updated whenever the user zooms the map.

Leaflet.js shrink getBounds()

Leafletjs has a function pad(x) for increasing the latLng bounds. How do I shrink it? I've tried putting a negative number in there with little success.
I'm basically trying to see if a marker is within the current view, and if not center on that marker. But some markers can be plotted right on the edge of view and still be classed as in view. I'm trying to add inner padding on the current viewport bounds to avoid this.
if(!map.getBounds().pad(-1.5).contains(marker.getLatLng()))
You can use the paddingTopLeft, paddingBottomRight or padding options of L.Map's fitBounds method:
Sets the amount of padding in the top left corner of a map container that shouldn't be accounted for when setting the view to fit bounds. Useful if you have some control overlays on the map like a sidebar and you don't want them to obscure objects you're zooming to.
http://leafletjs.com/reference.html#map-paddingtopleft
map.fitBounds(layer, {'padding': [n, n]})
The negative value range for pad() is 0 to -0.5.
https://github.com/Leaflet/Leaflet/issues/5741
edit: link basically states that pad takes in a ratio of 1 not a typical percentage value. So to decrease the bounds by 50% (which would visually make it 0, because the left bounds would go in 50% to the middle, and the right bounds would also go in 50% to the middle, etc) the parameter value would be pad(-0.5) NOT pad(-50)
to increase add a positive ratio.