Google Maps v3 fitBounds () Zoom trop près pour un seul marqueur


92

Existe-t-il un moyen de définir un niveau de zoom maximal pour fitBounds()? Mon problème est que lorsque la carte n'est alimentée qu'à un seul emplacement, elle effectue un zoom avant aussi loin que possible, ce qui sort vraiment la carte de son contexte et la rend inutile. Peut-être que je prends la mauvaise approche?

Merci d'avance!


2
stackoverflow.com/questions/4523023/… est une bien meilleure solution. Réponse particulière à @Nequins
Kennet

Réponses:


138

J'aime la solution de mrt (surtout quand vous ne savez pas combien de points vous allez cartographier ou ajuster), sauf qu'elle jette le marqueur pour qu'il ne soit plus au centre de la carte. Je l'ai simplement prolongé d'un point supplémentaire en soustrayant également 0,01 de la lat et de la longueur, de sorte qu'il garde le marqueur au centre. Fonctionne très bien, merci mrt!

// Pan & Zoom map to show all markers
function fitToMarkers(markers) {

    var bounds = new google.maps.LatLngBounds();

    // Create bounds from markers
    for( var index in markers ) {
        var latlng = markers[index].getPosition();
        bounds.extend(latlng);
    }

    // Don't zoom in too far on only one marker
    if (bounds.getNorthEast().equals(bounds.getSouthWest())) {
       var extendPoint1 = new google.maps.LatLng(bounds.getNorthEast().lat() + 0.01, bounds.getNorthEast().lng() + 0.01);
       var extendPoint2 = new google.maps.LatLng(bounds.getNorthEast().lat() - 0.01, bounds.getNorthEast().lng() - 0.01);
       bounds.extend(extendPoint1);
       bounds.extend(extendPoint2);
    }

    map.fitBounds(bounds);

    // Adjusting zoom here doesn't work :/

}

4
Bonne idée de garder le centre d'origine. La raison pour laquelle le niveau de zoom ne peut pas être ajusté de manière fiable lors de l'utilisation de la fitBounds()méthode est que le zoom se produit de manière asynchrone: stackoverflow.com/questions/2989858/…
Metro Smurf

1
Cela a très bien fonctionné pour moi. J'ai dû passer la référence de la carte dans la fonction "function fitToMarkers (marqueurs, carte)" sur V3, mais cela fonctionne comme un charme après ça!
Shane

4
J'aime ça. Bon @ryan. Cela a très bien fonctionné pour moi, mais .01 dans mon cas a fait un zoom arrière trop loin, .001 a atteint le point idéal.
willdanceforfun

Merci. Comme @willdanceforfun dans le même cas, 001 a frappé la tache.
Goran Jakovljevic

1
Je recommanderais cette solution stackoverflow.com/questions/2437683/…
NinjaOnSafari

38

Vous pouvez configurer votre carte avec maxZoomdans le MapOptions (api-reference) comme ceci:

var map = new google.maps.Map(document.getElementById("map"), { maxZoom: 10 });

Cela empêcherait la carte de zoomer plus profondément lors de l'utilisation fitBounds()et supprimerait même les niveaux de zoom de la commande de zoom.


@candlejack Donc exactement comme décrit dans ma réponse?
Flygenring

6
Vous pouvez définir le maxZoomavant d'ajuster les limites, puis le désactiver à nouveau à l'aide map.setOptions({ maxZoom: undefined })de l' idleévénement déclenché en modifiant les limites. Cela empêche l'effet de zoom avant ou arrière de réinitialiser le zoom dans l' idleévénement.
El Yobo

29

Une autre solution consiste à étendre les limites si vous détectez qu'elles sont trop petites avant d'exécuter fitBounds ():

var bounds = new google.maps.LatLngBounds();
// here you extend your bound as you like
// ...
if (bounds.getNorthEast().equals(bounds.getSouthWest())) {
   var extendPoint = new google.maps.LatLng(bounds.getNorthEast().lat() + 0.01, bounds.getNorthEast().lng() + 0.01);
   bounds.extend(extendPoint);
}
map.fitBounds(bounds);

19
var map = new google.maps.Map(document.getElementById("map"), { maxZoom: 10 });

L'utilisation de l'option MaxZoom fonctionne mieux pour ne pas zoomer pour se rapprocher des marques que vous avez.


Fantastique! Sauveur de vie!
Jaypee

18

Une fois que vous avez ajouté toutes les limites réelles, ajoutez ces lignes

var offset = 0.002;     
var center = bounds.getCenter();                            
bounds.extend(new google.maps.LatLng(center.lat() + offset, center.lng() + offset));
bounds.extend(new google.maps.LatLng(center.lat() - offset, center.lng() - offset));

il obtient le centre des limites réelles puis ajoute deux points supplémentaires un au nord-est et un au sud-ouest de votre centre

Cela définit efficacement le zoom minimum, changez la valeur du décalage pour augmenter ou diminuer le zoom


12

S'il s'agit d'un seul emplacement, vous pouvez utiliser setCenter () et setZoom () à la place.


solution la plus simple
Alberto M

11

tu peux utiliser

map.setOptions({
    maxZoom: [what u want],
    minZoom: [what u want]
});

de cette façon, vous définissez les propriétés de la carte après l'initialisation de la carte .... vous pouvez les définir autant de fois que vous le souhaitez ... mais dans votre cas ... vous pouvez les définir avant fitBounds ()

bonne chance, rarutu


7

La façon dont j'empêche la carte de zoomer trop loin est d'ajouter cette ligne de code:

var zoomOverride = map.getZoom();
        if(zoomOverride > 15) {
        zoomOverride = 15;
        }
      map.setZoom(zoomOverride);

Juste après cette ligne:

map.setCenter(bounds.getCenter(), map.getBoundsZoomLevel(bounds));

N'hésitez pas à modifier le niveau de zoom au niveau auquel vous ne souhaitez pas que la carte fasse un zoom avant.

Si vous avez des problèmes ou des questions, laissez-moi simplement un commentaire sur le billet de blog que j'ai écrit à ce sujet sur http://icode4you.net/creating-your-own-store-locator-map-how-to-prevent-the- carte-à-partir-de-zoom-avant-trop-près-sur-un-marqueur-unique


1
J'aime cette solution mais insérez le setzoom à l'intérieur du if pour ne pas l'appeler à chaque fois. Il pourrait également y avoir un effet secondaire de synchronisation qui renvoie «indéfini» de getzoom (). Solution: zoom = map.getZoom (); if (typeof zoom! == 'undefined' && zoom> 8) map.setZoom (8);
Le Droid

5

J'aime vraiment la solution de mrt et cela fonctionne parfaitement si vous n'avez toujours qu'un seul point à travailler. J'ai cependant constaté que si le cadre de délimitation n'était pas basé sur un point, mais que les points étaient très proches les uns des autres, cela pourrait toujours entraîner un zoom trop important sur la carte.

Voici un moyen de vérifier d'abord si les points sont à une distance définie les uns des autres, puis s'ils sont plus petits que cette distance minimale, étendez les limites de cette distance minimale:

var bounds = new google.maps.LatLngBounds();
// here you extend your bound as you like

// ...

var minDistance = 0.002;
var sumA = bounds.getNorthEast().lng() - bounds.getSouthWest().lng();
var sumB = bounds.getNorthEast().lat() - bounds.getSouthWest().lat();

if((sumA < minDistance && sumA > -minDistance) 
&& (sumB < minDistance && sumB > -minDistance)){
var extendPoint1 = new google.maps.LatLng(bounds.getNorthEast().lat() + minDistance, bounds.getNorthEast().lng() + minDistance);
    var extendPoint2 = new google.maps.LatLng(bounds.getNorthEast().lat() - minDistance, bounds.getNorthEast().lng() - minDistance);
    bounds.extend(extendPoint1);
    bounds.extend(extendPoint2);
}

J'espère que cela aide quelqu'un!


3

Cela vous donne un contrôle direct sur le zoom maximum autorisé sur l'ajustement des limites.

var fitToMarkers = function(map, markers, maxZoom) {
    if (typeof maxZoom == 'undefined') maxZoom = 15;

    google.maps.event.addListenerOnce(map, 'bounds_changed', function(event) {
        if (this.getZoom() > maxZoom) {
            this.setZoom(maxZoom);
        }
    });

    var bounds = new google.maps.LatLngBounds();
    for (var m = 0; m < markers.length; m++) {
        var marker = markers[m];
        var latlng = marker.getPosition();
        bounds.extend(latlng);
    }

    map.fitBounds(bounds);
};

3

Quant à moi, je le résous en créant un événement inactif après fitBounds. Fonctionne parfaitement. Je suppose que c'est l'une des solutions les plus propres ici

var locations = [['loc', lat, lng], ['loc', lat, lng]];
.....
for (i = 0; i < locations.length; i++) { 
  var map = new google.maps.Map(document.getElementById('map'), {
    zoom: 10
  });
  .... create markers, etc.
}
....
map.fitBounds(bounds);  
google.maps.event.addListenerOnce(map, 'idle', function() {
  if (locations.length == 1) {
    map.setZoom(11);
  }
});

2

J'ai résolu avec ce morceau, puisque Google Maps V3 est piloté par les événements:

vous pouvez dire à l'API de réinitialiser le zoom à une valeur appropriée lorsque l' événement zoom_changed se déclenche:

var initial = true
google.maps.event.addListener(map, "zoom_changed", function() {
    if (intial == true){
       if (map.getZoom() > 11) {
         map.setZoom(11);
         intial = false;
       }
    }
}); 

J'ai utilisé intial pour que la carte ne zoome pas trop en chargeant lorsque les éventuels fitBounds sont permus, sans cela, tout événement de zoom supérieur à 11 serait impossible pour l'utilisateur.


1

Après avoir appelé la fitBounds()méthode, essayez à nouveau de configurer le niveau de zoom. Cela forcera la carte à être à ce niveau de zoom tout en étant centrée au bon endroit.


0

J'ai une soulution basée sur la limitation du zoom maximum lors de l'ajustement des limites. Fonctionne pour moi (testé sur Win 7 - IE 9, FF 13, Chrome 19):

// When fitting bounds:
var bounds = new google.maps.LatLngBounds();
// ...
// extend bounds as you like
// ..

// now set global variable when fitting bounds
window.fittingBounds = true;
map.fitBounds(bounds);
window.fittingBounds = false;


// attach this event listener after map init
google.maps.event.addListener(map, 'zoom_changed', function() {
    // set max zoom only when fitting bounds
    if (window.fittingBounds && map.getZoom() > 16) {
        this.setZoom(16);
    }
});

0

Et .. en voici un autre.
Même idée que mrt et Ryan, mais

  • fonctionne également si la taille des limites n'est pas exactement zéro (*)
  • empêche la distorsion près des pôles
  • utilise getCenter () au lieu de getNorthEast ()

(*) Remarque: Si la boîte est déjà assez grande, ajouter ces deux points supplémentaires ne devrait avoir aucun effet. Nous n'avons donc pas besoin de vérification supplémentaire.

function calcBounds(markers) {
  // bounds that contain all markers
  var bounds = new google.maps.LatLngBounds();
  // Using an underscore _.each(). Feel free to replace with standard for()
  _.each(markers, function(marker) {
    bounds.extend(marker.getPosition());
  });
  // prevent lat/lng distortion at the poles
  var lng0 = bounds.getNorthEast().lng();
  var lng1 = bounds.getSouthWest().lng();
  if (lng0 * lng1 < 0) {
    // Take the cos at the equator.
    var cos = 1;
  }
  else {
    var cos0 = Math.cos(lng0);
    var cos1 = Math.cos(lng1);
    // Prevent division by zero if the marker is exactly at the pole.
    var cos_safe = Math.max(cos0, cos1, 0.0001);
  }
  var cos0 = Math.cos(bounds.getNorthEast.lng() * Math.PI / 180);
  var cos1 = Math.cos(bounds.getSouthWest.lng() * Math.PI / 180);
  // "radius" in either direction.
  // 0.0006 seems to be an ok value for a typical city.
  // Feel free to make this value a function argument.
  var rLat = 0.0006;
  var rLng = rLat / cos_safe;
  // expand the bounds to a minimum width and height
  var center = bounds.getCenter();
  var p0 = new google.maps.LatLng(center.lat() - rLat, center.lng() - rLng);
  var p1 = new google.maps.LatLng(lat.center() + rLat, center.lng() + rLng);
  bounds.extend(p0);
  bounds.extend(p1);
  return bounds;
}

EDIT: Je ne sais pas exactement si mon calcul de ratio est correct, étant donné que nous avons une projection Mercator. Je pourrais rééditer ceci.



-1

Voici ma solution, qui fonctionne également lorsque deux marqueurs sont très proches. Le niveau de zoom maximal effectif est le même dans les deux situations. On ne finit donc pas par zoomer inutilement vers l'arrière, lorsqu'il y a plus d'un marqueur

L'effet, encore une fois, est d'assurer un zoom maximum, sans utiliser l'option maxZoom, ce qui a pour effet probablement indésirable de rendre impossible pour l'utilisateur de zoomer plus loin que le niveau maxZoom avec la commande de zoom

J'ai calculé au préalable maxLat, minLat, maxLng et minLng ...

var minLatSpan = 0.002;
if (maxLat - minLat < minLatSpan) {
  // ensures that we do not zoom in too much
  var delta = (minLatSpan - (maxLat - minLat)) / 2;
  maxLat += delta;
  minLat -= delta;
}

map.fitBounds({
  east: maxLng,
  west: minLng,
  north: maxLat,
  south: minLat,
});
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.