Mapbox.js set map default zoom option - javascript

I have a mapbox.js map but the parameter zoom doesn't seem to be doing anything
and I can't figure it out in the documentation. whatever I set zoom to the zoom level always defaults to my project zoom level Here is the code:
<script src='https://api.tiles.mapbox.com/mapbox.js/v1.6.1/mapbox.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox.js/v1.6.1/mapbox.css' rel='stylesheet' />
$(document).ready(function() {
var map = L.mapbox.map('map', 'nhaines.hek4pklk', {
zoom: 1
});
// disable drag and zoom handlers
map.dragging.disable();
map.touchZoom.disable();
map.doubleClickZoom.disable();
map.scrollWheelZoom.disable();
// disable tap handler, if present.
if (map.tap) map.tap.disable();
});

It took me a lot of digging around but I figured this out on my own. The dev's didn't respond yet. We were going about this all wrong. Here's what to do:
First, create the MapBox object, but set zoomAnimation to false. This question helped me realize that trying to setZoom while a CSS3 animation was in progress wouldn't ever work because it's tough to break out of. At least that's what I think is going on. Setting zoomAnimation to true allows the map to animate in and bypasses any custom zoom levels, so clearly this is very important.
var map = L.mapbox.map('map', 'username.map_id', {
zoomAnimation: false
});
Next, create a polygon layer and add to map from map's geojson. You find this within your MapBox projects > info tab. (In my case this geojson happens to contain the lat/lng coords of a polygon but your case may be different. featureLayer() should still add the geojson either way.)
var polygonLayer = L.mapbox.featureLayer().loadURL('http://your/maps/geojson').addTo(map);
After polygon layer (or whatever your lat/lng coords are of) has been added to map
polygonLayer.on('ready', function() {
// featureLayer.getBounds() returns the corners of the furthest-out markers,
// and map.fitBounds() makes sure that the map contains these.
map.fitBounds(polygonLayer.getBounds());
map.setView(map.getCenter(), 10);
}
Apparently fitBounds satisfies the map requirements to allow setView to be called on it, since now you can just call the map object directly to get the center lat/lng.
I haven't tested this in simple cases - I adapted this code from mine which checks if an address's lat/lng coords fall within a polygon while iterating over a series of MapBox maps. It should get you going though. Hope it helps!

Related

Maximum latitude map panning with leaflet

I am new to leaflet and I want the restrict the panning of a world map horizontally and not vertically (longitude but not latitude) because this map will display pictures when I click on them and I cant see well the image when i restrict the panning horizontally AND vertically. The map by itself it not a picture, it's a real world map. But when I click on certain location, a small picture will appear on the map.
I try to play with maxBounds and setMaxbounds. The normal maxBounds (to view the world map) is :
maxBounds: [[-85, -180.0],[85, 180.0]],
When i try to put the latitude to
[[-150, -180.0],[150, 180.0]]
, the vertical panning is still restricted. Can somebody help please? Thank you.
This sounds similar to a (quite obscure) issue in the Leaflet issue tracker a
while back: see https://github.com/Leaflet/Leaflet/issues/3081
However, that issue was dealing with infinite horizontal bounds, not vertical bounds in a CRS that already has some preset limits.
If you set the map's maxBounds to a value larger than 85 (the value for MAX_LATITUDE of L.Projection.Spherical) and run a debugger, the call stack goes through the map's _panInsideMapBounds(), then panInsideBounds(), then _limitCenter(), then _getBoundsOffset, then project(), then through the map CRS's latLngToPoint, then untimately L.Projection.Spherical's project(). L.Projection.Spherical.project() projects the bounds' limits into pixel coordinates, and clamps the projected point to be inside the projection's limits.
There are a lot of reasons behind this, one of them being to prevent users from putting markers outside the area covered with tiles:
(This is particularly important when a user confuses lat-lng with lng-lat and tries to use a value outside the [-90,90] range for latitude, and the projection code starts returning Infinity values everywhere)
How to get around this? Well, we can always specify the map's CRS, and we can create a CRS with a hacked projection which enforces a different limit. Please be aware that this changes how the pixelOrigin works internally (as explained in the Leaflet tutorial about extending layers), so stuff (particularly plugins) might break.
So something like:
var hackedSphericalMercator = L.Util.extend(L.Projection.SphericalMercator, {
MAX_LATITUDE: 89.999
});
var hackedEPSG3857 = L.Util.extend(L.CRS.EPSG3857, {
projection: hackedSphericalMercator
});
var map = new L.Map('mapcontainer', {
crs: hackedEPSG3857,
});
Of course, then you can set up your own maxBounds:
var map = new L.Map('mapcontainer', {
crs: hackedEPSG3857,
maxBounds: [[-Infinity, -10], [Infinity, 10]]
});
In this case, the bounds' limits would still be clamped to hackedSphericalMercator.MAX_LATITUDE, but you should have enough wiggle room for your application.
As a side note: A radically different approach to this problem would be to use a different map projection. We're used to a spherical cylindrical projection, but that's not the only way to flatten the earth.
In particular, a Transverse Mercator projection (or pretty much any other transverse cylindrical projection, for that matter) works pretty much in the same way, but wraps vertically instead of horizontally, and it's the projected longitudes, not latitudes, the ones which approach infinity asymptotically when approaching the [-180, 180] range. Let me borrow an image from its wikipedia article:
This implies a different set of challenges (namely finding some raster tiles appropriate for your application, including which prime meridian to use, and making proj4leaflet play nice), but it's definitely doable.

Understanding Google Maps "fitBounds" method

I just want to clarify whether my way of understanding is correct. In my Google Maps app I would like to show to my users markers from particular continents.
Question: Am I right that a bound in Google Map API is an area made from NOT MORE AND NOT LESS than two points (markers)?
From math lessons, to draw 2D area I just need two points. Right? So to show to my users all markers from Europe should I just find two coordinates, one from Iceland (top, left) and second from let's say south-east Turkey? (For USA I would pick Seattle and Miami).
So, below JS code works perfectly. My question is - could you confirm that my way of understanding and the approach I've chosen is correct? Does it make any sense?
var bounds = new google.maps.LatLngBounds();
bounds.extend(new google.maps.LatLng('66.057878', '-22.579047')); // Iceland
bounds.extend(new google.maps.LatLng('37.961952', '43.878878')); // Turkey
this.map.fitBounds(bounds);
Yes, you are mostly correct. Except a 'bound' in Google maps case can include multiple points, for example if you had a point to the far right in the middle of the square in your image above and another at the bottom of the square in the middle you would still get an area the same as you have drawn above but with 3 points as in the edited map.
Obligatory link to the docs :)
https://developers.google.com/maps/documentation/javascript/reference?hl=en
You should not think about "top-left" and "bottom-right" but as south-west and north-east (so bottom-left and top-right if you like), as these are the coordinates used to create and/or retrieve the bounds object.
See the documentation and the getNorthEast and getSouthWest methods.
These two points are LatLng objects, and not markers. As an example, a marker is positioned on the map using a LatLng object.
I don't know your use case and your way of storing the data, but there might be a more precise way to display "Europe" markers. You could for example save the region along with each marker so that you can just query for "EU" markers and not others...

Erratic overlay behavior with custom projection, Google Maps API v3

I want to browse a single image with the Google Maps API, for which I've defined my own projection. I wanted to use a GroundOverlay instead of several image tiles, because I only have one small-resolution image, but I wanted it to still be zoomable. However, I get some erratic behavior when trying to work with this projection:
No overlays show up at all at zoom level 0.
At zoom level 1 and higher, Markers show up, but GroundOverlays still don't.
However, I can get GroundOverlays to show up very briefly, if I zoom out from any level. It will only show while it's zooming out and disappear again immediately. Also, while it does show up shortly, it does not show up at the right coordinates, but the Markers do.
I'm rather new to the API, so I would not be surprised if it was a simple oversight on my part, but I just can't see what could cause this. Here is the code for my projection, which just maps the lat/lng linearly to map coordinates:
function EvenMapProjection() {
var xPerLng = 512/360;
var yPerLat = 512/180;
this.fromLatLngToPoint = function(latlng) {
var x = (latlng.lng()+180)*xPerLng;
var y = (latlng.lat()+90)*yPerLat;
console.log('Lng', latlng.lng(), 'Lat', latlng.lat(), '-> Point', x, y);
return new google.maps.Point(x, y);
};
this.fromPointToLatLng = function(point) {
var lat = point.y/yPerLat-90;
var lng = point.x/xPerLng-180;
console.log('Point', point.x, point.y, '-> Lng', lng, lat);
return new google.maps.LatLng(lat, lng);
};
}
An example of what I'm trying to do without the projection (using the default Mercator projection):
http://95.156.209.71/tmp/a.html
The same example with the projection as defined above:
http://95.156.209.71/tmp/b.html
And finally an example using the projection but without the GroundOverlay, and instead just using tiled images (always the same image):
http://95.156.209.71/tmp/c.html
The last link also shows the Marker at LatLng(0, 0) appear at zoom level 1 (or higher), but not at level 0.
Is there something I'm just missing, or some buggy code, or is this actually a problem in the API?
I just found out that my mistake was in the definition of the ground overlay. I was at zoom level 0, which meant that I set the bounds for the overlay from (-90,-180) to (90,180), but the API seems to have issues with these levels, because they wrap longitude, hence I got weird errors. I adjusted it to be at level 1 for minimum zoom, and set the overlay from (-45,-90) to (45,90), and now it all works fine.

Leaflet.js - Fit geoJSON co-ordinates on map view

I have a leaflet.js map that has points and linestrings on it that come from an external JSON file.
If I add:
map.setView(new L.LatLng(0,0), 10);
It will centre the map on the latitude and longitude 0,0. How can I set it so the map centre and zoom fit all of the points from the JSON on it?
You could add all of your layers to a FeatureGroup which has a getBounds method. So you should be able to just say myMap.fitBounds(myFeatureGroup.getBounds());
The getBounds method for L.FeatureGroup is only available in the master branch (not the latest version, 0.3.1), for now at least.
Similar case with me. I drawn all the markers from GeoJson data. So I written the function, which gets called repeatedly on button click. Just try if it suits your requirements.
function bestFitZoom()
{
// declaring the group variable
var group = new L.featureGroup;
// map._layers gives all the layers of the map including main container
// so looping in all those layers filtering those having feature
$.each(map._layers, function(ml){
// here we can be more specific to feature for point, line etc.
if(map._layers[].feature)
{
group.addLayer(this)
}
})
map.fitBounds(group.getBounds());
}
The best use of writing this function is that even state of map/markers changed, it will get latest/current state of markers/layers. Whenever this method gets called all the layers will be visible to modest zoom level.
I needed to do this when showing a user directions from his origin to a destination. I store my list of directions in an array of L.LatLng called directionLatLngs then you can simply call
map.fitBounds(directionLatLngs);
This works because map.fitBounds takes a L.LatLngBounds object which is just an array of L.LatLng
http://leafletjs.com/reference.html#latlngbounds

with openlayers , how do i make sure the markers in TWO layers are all dsiplayed

I have markers in two marker layers,which i need to keep separate, so I can clear one or the other in the application.
What is the best way to make sure all markers are displayed. Doing it for one layer is easy with zoomToExtent. But how to do it for more then one layer?
Get the bounds from layer 1, use .extend(layer 2's bounds), and then zoomToExtent on the extended bounds.
http://dev.openlayers.org/releases/OpenLayers-2.10/doc/apidocs/files/OpenLayers/BaseTypes/Bounds-js.html#OpenLayers.Bounds.extend
is the extend method on a bounds.
sketchy and quick, sorry....
Use a new bounds object and use Bounds.extend.
var myNewBounds = Layer1.zoomToExtent.getExtent();
myNewBounds.extend(Layer2.zoomToExtent.getExtent());
Use that new bounds variable to set the bounds on your map. The syntax is wrong, but that's the direction you want to go.

Categories