I am working on an enhancement to the map accessible at http://travellr.com/map
The idea is to be able to load the map on a country, and have the map
zoomed to appropriately fit the country. For all countries I have co-
ordinates and bounding boxes already.
The problem is that when using Map.fitBounds(), the zoom level
sometimes isn't quite right - for loading on countries I would like to
limit zoom within a min / max, and places like Russia and Canada
break out of that. After using Map.fitBounds(), I could then check the
zoom level once the zoom_changed event fires, and if required update
it, but that seems quite a clunky multi step process.
Ideally I would like to be able to calculate the zoom level prior to
instantiating the map. However the API v3 does not seem to provide a
way to do this.
I have read some solutions akin to:
// mnode = the map node
// bounds = a bounding box
function best_zoom(bounds, mnode) {
var width = mnode.offsetWidth;
var height = mnode.offsetHeight;
var dlat = Math.abs(bounds.maxY - bounds.minY);
var dlon = Math.abs(bounds.maxX - bounds.minX);
// Center latitude in radians
var clat = Math.PI*(bounds.minY + bounds.maxY)/360.;
var C = 0.0000107288;
var z0 = Math.ceil(Math.log(dlat/(C*height))/Math.LN2);
var z1 = Math.ceil(Math.log(dlon/(C*width*Math.cos(clat)))/
Math.LN2);
return (z1 > z0) ? z1 : z0;
}
However this does not seem to provide the correct zoom levels (they
increase as dlat or dlon increase, shouldn't they go down?) - Please
tell me if I am missing something here? Also, where does the constant
C come from?
Thanks for your help.
- Jai
function zoomRecenter(map, bounds) {
map.setZoom(map.getBoundsZoomLevel(bounds));
map.panTo(bounds.getCenterMap(map));
}
GLatLngBounds.prototype.getCenterMap = function(m) {
var p = m.getCurrentMapType().getProjection();
var b = new GBounds;
b.extend(p.fromLatLngToPixel(this.getNorthEast(), m.getZoom()));
b.extend(p.fromLatLngToPixel(this.getSouthWest(), m.getZoom()));
return new GLatLng(p.fromPixelToLatLng(b.mid(),
m.getZoom()).lat(), this.getCenter().lng());
}
Note the complexity of finding the *pixel* middle of a GBounds.
However, since it isn't possible (currently) in V3 to get the
projection in use by the current basemap, you are somewhat hosed.
You can star the bug at
http://code.google.com/p/gmaps-api-issues/issues/detail?id=2181&q=apitype%3AJavascript3%20type%3ADefect&sort=-id%20-stars&colspec=ID%20Type%20Status%20Introduced%20Fixed%20Summary%20Internal%20Stars
if you want.
Philip
On Feb 16, 12:58 am, Jaidev S <j...@travellr.com> wrote:
> Hi,
>
> I am working on an enhancement to the map accessible athttp://travellr.com/map
C is a value based on your latitude, values I calculated were:
constant_at_0_degrees = 1.406245461070741
constant_at_20_degrees = 1.321415085624082
constant_at_40_degrees = 1.077179995861952
constant_at_60_degrees = 0.703119412486786
constant_at_80_degrees = 0.488332580888611
I found for most countries just using the 60 degree one worked well.
For working out the zoom level to display a bounding box (this is in
ruby but easily translated into JS):
width = width-of-map-element
height = height-of-map-element
bounds_t = top-of-bounding-box
bounds_b = bottom-of-bounding-box
bounds_l = left-of-bounding-box
boubds_r = right-of-bounding-box
dlat = bounds_t - bounds_b
if bounds_l < bounds_r
dlon = bounds_r - bounds_l
else
dlon = 360 - bounds_l + bounds_r
end
z0 = (Math.log(constant_at_60_degrees * height / dlat) /
Math.log(2)).ceil
z1 = (Math.log(constant_at_60_degrees * width / dlon) /
Math.log(2)).ceil
zoom = z1 ? ((z1 > z0) ? z0 : z1) : z0
Happy mapping :)
On Feb 16, 4:58 pm, Jaidev S <j...@travellr.com> wrote:
> Hi,
>
> I am working on an enhancement to the map accessible athttp://travellr.com/map
>
> The idea is to be able to load the map on a country, and have the map
> zoomed to appropriately fit the country. For all countries I have co-
> ordinates and bounding boxes already.
>
> The problem is that whenusingMap.fitBounds(), thezoomlevel
> sometimes isn't quite right - for loading on countries I would like to
> limit zoomwithin a min / max, and places like Russia and Canada
> break out of that. AfterusingMap.fitBounds(), I could then check thezoomlevelonce the zoom_changed event fires, and if required update
> it, but that seems quite a clunky multi step process.
>
> Ideally I would like to be able to calculate thezoomlevelprior to
> instantiating the map. However theAPIv3 does not seem to provide a
> way to do this.
>
> I have read some solutions akin to:
>
> // mnode = the map node
> // bounds = a bounding box
> function best_zoom(bounds, mnode) {
> var width = mnode.offsetWidth;
> var height = mnode.offsetHeight;
>
> var dlat = Math.abs(bounds.maxY - bounds.minY);
> var dlon = Math.abs(bounds.maxX - bounds.minX);
>
> // Center latitude in radians
> var clat = Math.PI*(bounds.minY + bounds.maxY)/360.;
>
> var C = 0.0000107288;
> var z0 = Math.ceil(Math.log(dlat/(C*height))/Math.LN2);
> var z1 = Math.ceil(Math.log(dlon/(C*width*Math.cos(clat)))/
> Math.LN2);
>
> return (z1 > z0) ? z1 : z0;
>
> }
>
> However this does not seem to provide the correctzoomlevels (they