How to fit bounds and set max bounds at same time on window resize in MAPBOX? - 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.

Related

Setting the CRS for non-geographical svg map

I'm trying to show a custom non-geographical map with CRS.simple as explained here:
In a CRS.Simple, one horizontal map unit is mapped to one horizontal
pixel, and idem with vertical
However, I wish to use an SVG vector image as an overlay, but I don't get how the map unit is decided in this case, since the vector images don't really have a resolution?
Also, how could set the CRS origin's location to a specific point?
Thanks for helping

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 :)

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.

IOS - Calculating tiles to display in a MapRect when

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.

how to efficiently find a rect # some x,y point with iphone sdk

I am looking for an efficient way to handle the image/frame detection from touch methods. Let's say i am building a keyboard or similar to this. I have 'n' number of images placed on the UI. When someone touches an alphabet (which is an image), i can do the following to detect the corresponding letter
1) CGRectIntersectsRect(..,..) : if i use this, then i need to check each & every letter to find out what letter exists at that touch point (let's say 100,100). This becomes O(n). If i move my finger accross the screen, then i will get m points & all corresponding image detection becomes O(n*m) which is not good.
2) Other way is building a hash for each & every x,y position so that the look up will be simply O(1). But again this will be a memory constraint as i need to store 300*300 ( assuming i am using 300*300 screen size). if i reshuffle my letters, then everything needs to calculated again. So this is not good
In other words, i need some thing like , given a point (x,y), i need some way of finding which rectangle is covering that point efficiently.
Sorry for long post & any help would be grateful.
Thanks
If there are in a regular grid, then integer division by the grid size. Assuming you've a small, fixed screen size, a bucket array gives as similar gain ( a 2D grid, where each entry is a list of the rectangles which intersect that part of the grid ) is very fast if tuned correctly so the lists only have a few members. For unbounded or large spaces, KD trees can be used.
It's useful to have the rects you want as final targets set up as subviews as a larger UIView (or subclass) where you expect all these related hits to occur. For example, if you're building your own keyboard, you could add a bunch of UIButton objects as subviews and hit test those.
So, the easy and traditional way of hit testing a bunch of subviews is to simply have code triggered by someone hitting those buttons. For example, you could add the subviews as UIControl objects (which is a subclass of UIView that adds some useful methods for catching user touch events), and call addTarget:action:forControlEvents: to specify some method to be triggered when the user does something in the rect of that UIControl. For example, you can catch things like UIControlEventTouchDown or UIControlEventTouchDragEnter. You can read the complete list in the UIControl class reference.
Now, it sounds like you might be going for something even more customized. If you really want to start with a random (x,y) coordinate and know which rect it's in, you can also use the hitTest:withEvent: method of UIView. This method takes a point in a view, and finds the most detailed (lowest in the hierarchy) subview which contains that point.
If you want to use these subviews purely for hit testing and not for displaying, then you can set their background color to [UIColor clearColor], but don't hide them (i.e. set the hidden property to YES), disable user interaction with them (via the userInteractionEnabled BOOL property), or set the alpha below 0.1, since any of those things will cause the hitTest:withEvent: method to skip over that subview. But you can still use an invisible subview with this method call, as long as it meets these criteria.
Look at UIView's tag property. If your images are in UIViews or subviews of UIView, then you can set each tag and use the tag to look up in an array.
If not, then you can improve the speed by dividing your array of rectangles into sets that fit into larger rectangles. Test the outer rectangles first, then the inner rectangles. 25 rectangles would need only 10 tests worst case as 5 sets of 5.
Thanks Pete Kirkham & Tyler for your answers which are really helpful. Lets say i dont wanna use buttons as i am mainly displaying images as a small rectangles. To check for the rect # (x,y) , i can trigger that easily by making my grid as a square & finding
gridcolumn = Math.floor(pos.x / cellwidth); gridrow = Math.floor(pos.y / cellheight);
But my problem is with touchesMoved. Lets say i started # grid-1 & dragged till grid-9 (in a 3*3 matrix), in this case, i am assuming i will get 100-300 (x,y) positions, so everytime i need to run above formula to determine corresponding grid. This results in 300 calculations which might effect the performance.
So when i display an image as a rect, can i associate some id for that image? so that i can simply just save the ids in a list (from grid-1 to grid-9) so that i can avoid the above calculation.
Thanks for your help