I have a piece of code that determines both best region.span.latitudeDelta and region.span.longitudeDelta. It finds the top left and bottom right and takes the diff between lat-coordinates and long-coordinates.
The problem I have is that rendering actually differs than what I set when executing:
region = self.regionThatFits(region)
self.setRegion(region, animated: true)
As an example, if I first select the items I want to render (let's say from a table) and then switch to the map I get a different result (visually) than showing all points on the map and then selecting the ones I want to keep.
Even more, if I render all points on the map, then select a few and render selected, then remove filters and render all, the map is not the same as it was when I started - it shows all the points but it is smaller (looks zoomed out) in comparison to the initial view.
On debugging I can see that both scenarios generate the same span values but it is as if rendering ignores them. From debug using (the selected points in the UK):
Load all points:
region.span.latitudeDelta 7.439768
region.span.longitudeDelta 11.0
Filter points:
region.span.latitudeDelta 1.25
region.span.longitudeDelta 10.50477
Remove filter:
region.span.latitudeDelta 7.439768
region.span.longitudeDelta 11.0
I tried re-centering the map on a fixed coordinate before I re-render (instead of just on viewDidLoad) but it made no difference.
I would like to highlight that the map does not keep zooming out every time I run the above sequence. It kind of zooms out once and that's it.
Is there an obvious step that I am missing? A hidden Boolean that I need to set? Something else?
I also tried changing from regionThatFits to
regionToRender = MKCoordinateRegionMake(region.center, region.span)
And I tried the following too:
func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
self.mapView.region = mapView.region
}
No matter what I do, if I apply the annotation filter when I am already on the map it looks as if actual span is increased/doubled (or as if there is a forced frame around the map edges) making the map look as if it is zoomed out despite the debug output showing otherwise...
Below are the two images from the different scenarios. Any advice will be greatly appreciated.
Thanks!
Picture 1 - applied filter while I was in a table and then navigated to map:
Picture 2 - navigated to map and then applied filter:
Upon extensive debugging covering layouts, frames and bounds among other things, this is what is happening:
When the ViewController containing the map is loaded for the first time, the map does not actually fit the view. To be precise it is loaded in its free form which is effectively 600x492 WxH respectively. Height of 492 is simply:
free form height - NavCon Height - ToolBar Height - default margin (battery etc.)
After the first pass of rendering annotation (effectively in viewDidAppear), the MapView gets the correct height (on iphone 4s) of 372. This is simply:
screen height (480) - NavCon Height - ToolBar Height - default margin
As a result, any rendering from this point will result in a zoom-out like effect (making everything look smaller).
The solution is to calculate the size which the mapView will get and set in viewDidLoad. In addition, you should probably also set the mapView autoresizing mask to match the parent view:
self.mapView.autoresizingMask = self.view.autoresizingMask
I hope you find this helpful.
Related
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.
(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 :)
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.
I have tried the solution on this but get 2 errors when I run the build. First "MAX_ZOOM undeclared" and Implicit declaraation of function'zoomScaleToZoomLevel'
I'm new to xCode, any help? need to fix tile zooming.
Thanks Ken
Calculating tiles to display in a MapRect when "over-zoomed" beyond the overlay tile set
MAX_ZOOM is a constant - you need to define it someplace in your code to match the number of zoom levels in your tile set.
I don't understand how to define the (CGRect)rect in order to control the position of popover, and the position of the arrow.
For example, I have a 1004 x 768 view, how can I put the popover at lower right of the screen, and point the arrow at 700 (x) 1000 (y)?
Nickthedude is right about presentpopoverfromrect, but there is one essential moment with presentpopoverfromrect function: if you don't set popover's contentSizeForViewInPopover property it use defult values - 320*1100 points. And if you popover's rect doesn't fit into screen coordinates (with your coordinates got from the presentpopoverfromrect rect), system places your popover to rectangle which it considered as more optimal.
Cgrectmake(700,1000,10,10) and uipopoverarrowdirectionleft sorry I'm on my iPad so I can't write the exact code but pass those in as the arguments for your presentpopoverfromrect method. The only thing is i think you're too far to the right to put a popover there unless I'm not understanding your question.