175 votes

Google Maps V3 - Comment calculer le niveau de zoom pour une limite donnée

Je suis à la recherche d'un moyen de calculer le niveau de zoom pour une des limites à l'aide de Google Maps API V3, semblable à getBoundsZoomLevel() dans la V2 de l'API.

Voici ce que je veux faire:

// These are exact bounds previously captured from the map object
var sw = new google.maps.LatLng(42.763479, -84.338918);
var ne = new google.maps.LatLng(42.679488, -84.524313);
var bounds = new google.maps.LatLngBounds(sw, ne);
var zoom = // do some magic to calculate the zoom level

// Set the map to these exact bounds
map.setCenter(bounds.getCenter());
map.setZoom(zoom);

// NOTE: fitBounds() will not work

Malheureusement, je ne peux pas utiliser le fitBounds() méthode pour mon cas d'utilisation particulier. Il fonctionne bien pour la pose de marqueurs sur la carte, mais il ne fonctionne pas bien pour la définition exacte des limites. Voici un exemple de pourquoi je ne peux pas utiliser le fitBounds() la méthode.

map.fitBounds(map.getBounds()); // not what you expect

333voto

John S Points 6450

Grâce à Giles Gardam pour sa réponse, mais il ne traite que de la longitude et de ne pas la latitude. Une solution complète doit calculer le niveau de zoom nécessaires pour la latitude et le niveau de zoom est nécessaire pour la longitude, puis prendre la plus petite (en plus) des deux.

Voici une fonction qui utilise à la fois la latitude et la longitude:

function getBoundsZoomLevel(bounds, mapDim) {
    var WORLD_DIM = { height: 256, width: 256 };
    var ZOOM_MAX = 21;

    function latRad(lat) {
        var sin = Math.sin(lat * Math.PI / 180);
        var radX2 = Math.log((1 + sin) / (1 - sin)) / 2;
        return Math.max(Math.min(radX2, Math.PI), -Math.PI) / 2;
    }

    function zoom(mapPx, worldPx, fraction) {
        return Math.floor(Math.log(mapPx / worldPx / fraction) / Math.LN2);
    }

    var ne = bounds.getNorthEast();
    var sw = bounds.getSouthWest();

    var latFraction = (latRad(ne.lat()) - latRad(sw.lat())) / Math.PI;

    var lngDiff = ne.lng() - sw.lng();
    var lngFraction = ((lngDiff < 0) ? (lngDiff + 360) : lngDiff) / 360;

    var latZoom = zoom(mapDim.height, WORLD_DIM.height, latFraction);
    var lngZoom = zoom(mapDim.width, WORLD_DIM.width, lngFraction);

    return Math.min(latZoom, lngZoom, ZOOM_MAX);
}

Démo sur jsfiddle

Paramètres:

Les "limites" valeur du paramètre doit être un google.maps.LatLngBounds objet.

Le "mapDim" valeur du paramètre doit être un objet avec "hauteur" et "largeur" des propriétés qui représentent la hauteur et la largeur de l'élément du DOM qui affiche la carte. Vous pouvez diminuer ces valeurs si vous souhaitez vous assurer de rembourrage. C'est, peut ne pas vouloir marqueurs de carte dans la limite d'être trop près du bord de la carte.

Si vous êtes à l'aide de la librairie jQuery, l' mapDim de la valeur peut être obtenue comme suit:

var $mapDiv = $('#mapElementId');
var mapDim = { height: $mapDiv.height(), width: $mapDiv.width() };

Si vous êtes à l'aide de la librairie Prototype, le mapDim valeur peut être obtenue comme suit:

var mapDim = $('mapElementId').getDimensions();

Valeur De Retour:

La valeur de retour est la valeur maximale du niveau de zoom qui continue d'afficher l'ensemble des limites. Cette valeur doit être comprise entre 0 et le maximum de niveau de zoom, inclusivement.

Le niveau de zoom maximum est de 21 ans. (Je crois que c'était seulement 19 pour Google Maps API v2.)


Explication:

Google Maps utilise une projection de Mercator. Dans une projection de Mercator les lignes de longitude sont équidistants, mais les lignes de latitude sont pas. La distance entre les lignes de latitude augmenter comme ils vont de l'équateur vers les pôles. En fait, la distance tend vers l'infini, il atteint des pôles. Une carte Google Maps, cependant, ne montrent pas des latitudes supérieures à environ 85 degrés Nord ou en dessous d'environ -85 degrés au Sud. (référence) (I calculer la réelle coupure à +/-85.05112877980658 degrés).

Cela rend le calcul des fractions pour les limites plus compliqué pour la latitude de longitude. J'ai utilisé une formule à partir de Wikipedia pour calculer la latitude de la fraction. Je suis en supposant que cela correspond à la projection utilisée par Google Maps. Après tout, Google Maps page de documentation je lien ci-dessus contient un lien vers la même page de Wikipédia.

Autres Remarques:

  1. Niveaux de Zoom de la gamme de 0 au maximum le niveau de zoom. Le niveau de Zoom 0 est la carte entièrement zoom arrière. La hausse des niveaux de zoom de la carte. (référence)
  2. Au niveau de zoom 0, le monde entier peut être affiché dans un endroit qui est de 256 x 256 pixels. (référence)
  3. Pour chaque hausse du niveau de zoom le nombre de pixels nécessaires à l'affichage de la même zone double en largeur et en hauteur. (référence)
  4. Cartes enveloppez-la dans le sens longitudinal, mais pas dans la direction de largeur.

119voto

Giles Gardam Points 622

Une question similaire a été posée sur le groupe Google groupes: http://groups.google.com/group/google-maps-js-api-v3/browse_thread/thread/e6448fc197c3c892

Les niveaux de zoom sont discrètes, à l'échelle de doubler à chaque étape. Donc, en général, vous ne peut répondre aux limites que vous voulez exactement (sauf si vous êtes très chanceux avec la taille de la carte).

Un autre problème est le ratio entre longueur côté: par exemple, vous ne pouvez pas adapter les limites exactement à un mince rectangle à l'intérieur d'un carré la carte.

Il n'y a pas de réponse facile pour savoir comment l'ajustement exact des limites, parce que même si vous êtes prêt à changer la taille de la carte div, vous devrez choisir la taille et correspondant au niveau de zoom que vous changer (en gros, ne vous rendre plus grande ou plus petite qu'elle ne l'est actuellement?).

Si vous avez vraiment besoin de calculer le facteur de zoom, plutôt que de les stocker, ce qui devrait faire l'affaire:

La projection de Mercator chaines de latitude, mais aucune différence en longitude représente toujours la même fraction de la largeur de la carte (la différence de l'angle en degrés / 360). Au zoom zéro, l'ensemble de la carte du monde est 256x256 pixels et un zoom à chaque niveau de la double à la fois la largeur et la hauteur. Ainsi, après un peu d'algèbre, nous pouvons calculer le zoom comme suit, à condition que nous savons de la carte de la largeur en pixels. A noter qu'en raison de longitude entoure, nous devons nous assurer que l'angle est positif.

var GLOBE_WIDTH = 256; // a constant in Google's map projection
var west = sw.lng();
var east = ne.lng();
var angle = east - west;
if (angle < 0) {
  angle += 360;
}
var zoom = Math.round(Math.log(pixelWidth * 360 / angle / GLOBE_WIDTH) / Math.LN2);

52voto

d.raev Points 1382

Pour la version 3 de l'API, c'est simple et fonctionnel:

 var latlngList = [];
latlngList.push(new google.maps.LatLng (lat,lng));

var bounds = new google.maps.LatLngBounds();
latlngList.each(function(n){
   bounds.extend(n);
});

map.setCenter(bounds.getCenter()); //or use custom center
map.fitBounds(bounds);
 

et quelques astuces optionnelles:

 //remove one zoom level to ensure no marker is on the edge.
map.setZoom(map.getZoom()-1); 

// set a minimum zoom 
// if you got only 1 marker or all markers are on the same address map will be zoomed too much.
if(map.getZoom()> 15){
  map.setZoom(15);
}
 

2voto

Valerio Giacosa Points 11

Merci, cela m'a beaucoup aidé à trouver le facteur de zoom le plus approprié pour afficher correctement une polyligne. Je trouve les coordonnées maximales et minimales parmi les points que je dois suivre et, si le chemin est très "vertical", je viens d'ajouter quelques lignes de code:

 var GLOBE_WIDTH = 256; // a constant in Google's map projection
var west = <?php echo $minLng; ?>;
var east = <?php echo $maxLng; ?>;
*var north = <?php echo $maxLat; ?>;*
*var south = <?php echo $minLat; ?>;*
var angle = east - west;
if (angle < 0) {
    angle += 360;
}
*var angle2 = north - south;*
*if (angle2 > angle) angle = angle2;*
var zoomfactor = Math.round(Math.log(960 * 360 / angle / GLOBE_WIDTH) / Math.LN2);
 

En fait, le facteur de zoom idéal est zoomfactor-1.

0voto

Lukas Olsen Points 1330

Valerio a presque raison avec sa solution, mais il y a une erreur de logique.

vous devez d’abord vérifier si l’angle2 est supérieur à l’angle, avant d’ajouter 360 au négatif.

sinon vous avez toujours une valeur supérieure à l'angle

La solution correcte est donc:

 var west = calculateMin(data.longitudes);
var east = calculateMax(data.longitudes);
var angle = east - west;
var north = calculateMax(data.latitudes);
var south = calculateMin(data.latitudes);
var angle2 = north - south;
var zoomfactor;
var delta = 0;
var horizontal = false;

if(angle2 > angle) {
    angle = angle2;
    delta = 3;
}

if (angle < 0) {
    angle += 360;
}

zoomfactor = Math.floor(Math.log(960 * 360 / angle / GLOBE_WIDTH) / Math.LN2) - 2 - delta;
 

Delta est là, car j'ai une largeur plus grande que la hauteur.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X