API Google Maps v3: Puis-je définir Zoom après fitBounds?

201

J'ai un ensemble de points que je veux tracer sur une carte Google intégrée (API v3). J'aimerais que les limites tiennent compte de tous les points, sauf si le niveau de zoom est trop bas (c.-à-d. Trop dézoomé). Mon approche a été comme ceci:

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

// extend bounds with each point

gmap.fitBounds(bounds); 
gmap.setZoom( Math.max(6, gmap.getZoom()) );

Ça ne marche pas. La dernière ligne "gmap.setZoom ()" ne change pas le niveau de zoom de la carte si elle est appelée directement après fitBounds.

Existe-t-il un moyen d'obtenir le niveau de zoom d'une limite sans l'appliquer à la carte? D'autres idées pour résoudre ce problème?

chris
la source
1
Voir stackoverflow.com/questions/4523023/using-setzoom-after-using-fitbounds-with-google-maps-api-v3
Mawg dit réintégrer Monica le

Réponses:

337

Edit : Voir le commentaire de Matt Diamond ci-dessous.

Je l'ai! Essaye ça:

map.fitBounds(bounds);
var listener = google.maps.event.addListener(map, "idle", function() { 
  if (map.getZoom() > 16) map.setZoom(16); 
  google.maps.event.removeListener(listener); 
});

Modifiez selon vos besoins.

LGT
la source
76
Excellente solution, m'a totalement sauvé beaucoup de problèmes. Je voulais juste ajouter que vous pouvez le simplifier davantage en utilisant la méthode addListenerOnce ... de cette façon, vous n'avez pas à enregistrer l'écouteur et à le supprimer manuellement, car la méthode s'en occupera pour vous.
Matt Diamond
9
Cela a le comportement de voir la carte "sauter". Écoutez plutôt l'événement "zoom_change" et configurez-le avant d'appeler fitBounds (). Voir ma réponse ci
Benjamin Sussman
Merci! google.maps.event.addListenerOnce (map, "idle", function () {} -> a très bien fonctionné pour mon package de cartes pour SugarCRM.
jjwdesign
L'auditeur ne se déclenche pas pour moi. J'ai essayé ceci dans document.ready et window.load. Des idées? l'objet de carte est OK et a également essayé addListener: `var map = $ (" # js-main-map-canvas "); var listener = google.maps.event.addListenerOnce (map, "idle", function () {alert ('hello');}); `
Henrik Erlandsson
Henrik, essayez $ ("# js-main-map-canvas") [0] ou $ ("# js-main-map-canvas"). Get (0);
Rafael
68

J'ai résolu un problème similaire dans l'une de mes applications. J'étais un peu confus par votre description du problème, mais je pense que vous avez le même objectif que j'avais ...

Dans mon application, je voulais tracer un ou plusieurs marqueurs et m'assurer que la carte les montrait tous. Le problème était que si je comptais uniquement sur la méthode fitBounds, le niveau de zoom serait maximisé lorsqu'il y avait un seul point - ce n'était pas bon.

La solution était d'utiliser fitBounds quand il y avait beaucoup de points, et setCenter + setZoom quand il n'y avait qu'un seul point.

if (pointCount > 1) {
  map.fitBounds(mapBounds);
}
else if (pointCount == 1) {
  map.setCenter(mapBounds.getCenter());
  map.setZoom(14);
}
Jim Garvin
la source
5
Votre réponse a résolu mon problème avec Google Maps V3. Merci!
FR6
1
J'ai eu exactement le même problème et votre solution a fonctionné! Merci!
manubkk
J'essayais la même approche par moi-même mais cela n'a pas fonctionné car je n'invoquais pas setCenter () avant de régler le zoom ... Je me demande toujours pourquoi cette étape est nécessaire, mais de toute façon maintenant ça marche ... merci a beaucoup Jim!
daveoncode
Map Center a résolu le problème que je rencontrais! Nice one +1
Piotr Kula
1
Merci pour votre bonne réponse +1
Bharat Chodvadiya
44

Je suis venu plusieurs fois sur cette page pour obtenir la réponse, et bien que toutes les réponses existantes aient été super utiles, elles n'ont pas résolu mon problème exactement.

google.maps.event.addListenerOnce(googleMap, 'zoom_changed', function() {
    var oldZoom = googleMap.getZoom();
    googleMap.setZoom(oldZoom - 1); //Or whatever
});

Fondamentalement, j'ai trouvé que l'événement «zoom_changed» empêchait l'interface utilisateur de la carte de «sauter», ce qui s'est produit lorsque j'ai attendu l'événement «inactif».

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

Benjamin Sussman
la source
4
Excellent, j'ai également eu le comportement de "saut / zoom automatique". Juste comme une note pour les autres lecteurs: assurez-vous d'utiliser "addListenerOnce" comme Benjamin ci-dessus au lieu de "addListener", ou brisez la tête pourquoi votre navigateur plante tout le temps ;-)
Geert-Jan
6
Notez également que l'écouteur doit être ajouté avant d'appeler fitBounds()si vous utilisezzoom_changed
gapple
1
Merci pour cela, il semble que la v4 devrait avoir un fitBounds (limites, minZoomLevel) :)
Richard
3
Benjamin, je pense qu'il vaut mieux l'utiliser bounds_changed, car il zoom_changedn'a pas besoin d'être déclenché dans le cas où on fitBoundsgarde le niveau de zoom. Ma tentative jsfiddle.net/rHeMp/10 ne le confirme pas, mais il ne faut pas se fier à un comportement non défini.
TMS
10

Je viens de résoudre ce problème en définissant maxZoom à l'avance, puis en le supprimant par la suite. Par exemple:

map.setOptions({ maxZoom: 15 });
map.fitBounds(bounds);
map.setOptions({ maxZoom: null });
Robin Whittleton
la source
La meilleure solution de loin pour éviter de trop zoomer. Simple et intuitif. Pas de dessin ni de nouveau dessin de la carte.
user2605793
C'est en effet la meilleure solution à ce jour.
Downhillski
2
J'ai constaté que cela ne fonctionne pas si vous réinitialisez maxZoom immédiatement après avoir appelé fitBounds, car le zoom se produit de manière asynchrone (donc maxZoom est de retour à null au moment où il effectue un zoom avant). Attendre jusqu'à ce que "inactif" pour le réinitialiser corrige cela, mais je suppose.
user987356
4

Si je ne me trompe pas, je suppose que vous voulez que tous vos points soient visibles sur la carte avec le niveau de zoom le plus élevé possible. J'ai accompli cela en initialisant le niveau de zoom de la carte à 16 (je ne sais pas si c'est le niveau de zoom le plus élevé possible sur V3).

var map = new google.maps.Map(document.getElementById('map_canvas'), {
  zoom: 16,
  center: marker_point,
  mapTypeId: google.maps.MapTypeId.ROADMAP
});

Ensuite, j'ai fait les trucs des limites:

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

// You can have a loop here of all you marker points
// Begin loop
bounds.extend(marker_point);
// End loop

map.fitBounds(bounds);

Résultat: succès!

Lester S
la source
3

J'utilise:

gmap.setZoom(24); //this looks a high enough zoom value
gmap.fitBounds(bounds); //now the fitBounds should make the zoom value only less

Cela utilisera le plus petit de 24 et le niveau de zoom nécessaire en fonction de votre code, mais cela modifie probablement le zoom de toute façon et ne se soucie pas de la quantité de zoom arrière.

ytg
la source
Je déteste dire cela, mais aussi étrange que cette réponse puisse paraître, c'est la seule chose qui a fonctionné jusqu'à présent et j'ai cherché pendant 4-5 heures sur une période de 3 jours. Sera toujours à la recherche d'une meilleure solution.
Allov
3

Veuillez essayer ceci:

map.fitBounds(bounds);

// CHANGE ZOOM LEVEL AFTER FITBOUNDS
zoomChangeBoundsListener = google.maps.event.addListenerOnce(map, 'bounds_changed', function(event) {
  if (this.getZoom()){
    this.setZoom(15);
  }
});
setTimeout(function(){
  google.maps.event.removeListener(zoomChangeBoundsListener)
}, 2000);
Atif Tariq
la source
2

J'ai eu le même problème et j'ai pu le résoudre en utilisant le code suivant. Cet google.maps.addListenerOnce()événement listener ( ) ne sera déclenché qu'une seule fois, juste après map.fitBounds()son exécution. Il n'est donc pas nécessaire de

  1. Gardez la trace de l'auditeur et supprimez-le manuellement, ou
  2. Attendez que la carte soit idle.

Il définit initialement le niveau de zoom approprié et permet à l'utilisateur d'effectuer un zoom avant et arrière au-delà du niveau de zoom initial car l'écouteur d'événements a expiré. Par exemple, si seulement google.maps.addListener()était appelé, l'utilisateur ne pourrait jamais zoomer au-delà du niveau de zoom indiqué (dans le cas, 4). Depuis que nous l'avons implémenté google.maps.addListenerOnce(), l'utilisateur pourra zoomer à n'importe quel niveau de son choix.

map.fitBounds(bounds);

var zoom_level_for_one_marker = 4;

google.maps.event.addListenerOnce(map, 'bounds_changed', function(event){
   if (this.getZoom() >= zoom_level_for_one_marker){  
       this.setZoom(zoom_level_for_one_marker) 
   }
});
9 singes
la source
2

Eu le même problème, avait besoin de tenir de nombreux marqueurs sur la carte. Cela a résolu mon cas:

  1. Déclarez les limites
  2. Schéma d'utilisation fourni par koderoid (pour chaque ensemble de marqueurs bounds.extend(objLatLng))
  3. Exécutez les fitbounds APRÈS que la carte soit terminée:

    google.maps.event.addListenerOnce(map, 'idle', function() { 
        map.fitBounds( bounds );
    });
ishubine
la source
2

J'ai trouvé une solution qui vérifie avant d'appeler fitBoundsafin de ne pas faire de zoom avant ni de zoom arrière soudain

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

// extend bounds with each point

var minLatSpan = 0.001;
if (bounds.toSpan().lat() > minLatSpan) {
    gmap.fitBounds(bounds); 
} else {
    gmap.setCenter(bounds.getCenter());
    gmap.setZoom(16);
}

Vous devrez jouer un peu avec la variable minLatSpan pour l'amener où vous le souhaitez. Il variera en fonction du niveau de zoom et des dimensions du canevas de carte.

Vous pouvez également utiliser la longitude au lieu de la latitude

CheapSteaks
la source
Fonctionne pour moi, mais je n'utilise pas minLatSpan - J'ai besoin de régler le zoom uniquement lorsque 1 marqueur est sur la carte. Par conséquent, je vérifie seulement s'il y a plus de 1 marqueurs.
Micer
2

J'ai vu de nombreuses solutions incorrectes ou trop compliquées, j'ai donc décidé de publier une solution fonctionnelle et élégante .

La raison pour laquelle setZoom()cela ne fonctionne pas comme vous vous y attendez est qu'il fitBounds()est asynchrone, donc cela ne donne aucune garantie qu'il mettra immédiatement à jour le zoom, mais votre appel à setZoom()s'appuie sur cela.

Ce que vous pourriez envisager est de définir l' minZoomoption de carte avant d'appeler fitBounds(), puis de la désactiver une fois qu'elle est terminée (afin que les utilisateurs puissent toujours effectuer un zoom arrière manuellement s'ils le souhaitent):

var bounds = new google.maps.LatLngBounds();
// ... (extend bounds with all points you want to fit)

// Ensure the map does not get too zoomed out when fitting the bounds.
gmap.setOptions({minZoom: 6});
// Clear the minZoom only after the map fits the bounds (note that
// fitBounds() is asynchronous). The 'idle' event fires when the map
// becomes idle after panning or zooming.
google.maps.event.addListenerOnce(gmap, 'idle', function() {
  gmap.setOptions({minZoom: null});
});

gmap.fitBounds(bounds);

De plus, si vous souhaitez également limiter le zoom max, vous pouvez appliquer la même astuce avec la maxZoompropriété.

Voir les documents MapOptions .

Svilen Marchev
la source
1

Je l'utilise pour m'assurer que le niveau de zoom ne dépasse pas un niveau défini afin que je sache que des images satellites seront disponibles.

Ajoutez un écouteur à l' zoom_changedévénement. Cela a l'avantage supplémentaire de contrôler également la commande de zoom sur l'interface utilisateur.

Exécutez uniquement setZoomsi vous en avez besoin, donc une ifinstruction est préférable à Math.maxou àMath.min

   google.maps.event.addListener(map, 'zoom_changed', function() { 
      if ( map.getZoom() > 19 ) { 
        map.setZoom(19); 
      } 
    });
    bounds = new google.maps.LatLngBounds( ... your bounds ... )
    map.fitBounds(bounds);

Pour éviter de trop dézoomer:

   google.maps.event.addListener(map, 'zoom_changed', function() { 
      if ( map.getZoom() < 6 ) { 
        map.setZoom(6); 
      } 
    });
    bounds = new google.maps.LatLngBounds( ... your bounds ... )
    map.fitBounds(bounds);
Mante
la source
1

Dans cette fonction, vous devez ajouter dynamiquement des métadonnées pour stocker le type de géométrie uniquement parce que la fonction accepte n'importe quelle géométrie.

"fitGeometries" est une fonction JSON qui étend un objet de carte.

"geometries" est un tableau javascript générique et non un MVCArray ().

geometry.metadata = { type: "point" };
var geometries = [geometry];

fitGeometries: function (geometries) {
    // go and determine the latLngBounds...
    var bounds = new google.maps.LatLngBounds();
    for (var i = 0; i < geometries.length; i++) {
        var geometry = geometries[i];
        switch (geometry.metadata.type)
        {
            case "point":
                var point = geometry.getPosition();
                bounds.extend(point);
                break;
            case "polyline":
            case "polygon": // Will only get first path
                var path = geometry.getPath();
                for (var j = 0; j < path.getLength(); j++) {
                    var point = path.getAt(j);
                    bounds.extend(point);
                }
                break;
        }
    }
    this.getMap().fitBounds(bounds);
},
CrazyEnigma
la source
Alternativement, j'ai fait tout le travail sans savoir qu'il existe une méthode extend () sur l'objet LatLngBounds. Ce serait beaucoup plus facile.
CrazyEnigma
1

ce travail est pour moi avec l'API v3 mais avec un zoom fixe:

var bounds = new google.maps.LatLngBounds();
// extend bounds with each point

gmap.setCenter(bounds.getCenter()); 
gmap.setZoom( 6 );
Pedro Blaszczak
la source
1

Comme moi, si vous n'êtes pas prêt à jouer avec des auditeurs, voici une solution simple que j'ai trouvée: Ajoutez une méthode sur la carte qui fonctionne strictement selon vos besoins comme celle-ci:

    map.fitLmtdBounds = function(bounds, min, max){
        if(bounds.isEmpty()) return;
        if(typeof min == "undefined") min = 5;
        if(typeof max == "undefined") max = 15;

        var tMin = this.minZoom, tMax = this.maxZoom;
        this.setOptions({minZoom:min, maxZoom:max});
        this.fitBounds(bounds);
        this.setOptions({minZoom:tMin, maxZoom:tMax});
    }

alors vous pouvez appeler map.fitLmtdBounds(bounds)au lieu de map.fitBounds(bounds)pour définir les limites sous la plage de zoom définie ... ou map.fitLmtdBounds(bounds,3,5)pour remplacer la plage de zoom ..

Kanak Singhal
la source
0

Veuillez essayer ceci.

// Find out what the map's zoom level is
zoom = map.getZoom();
if (zoom == 1) {
  // If the zoom level is that low, means it's looking around the
world.
  // Swap the sw and ne coords
  viewportBounds = new
google.maps.LatLngBounds(results[0].geometry.location, initialLatLng);
  map.fitBounds(viewportBounds);
}

Si cela vous sera utile.

Bonne chance

Kanak Vaghela
la source
0

Après le calcul des limites, vous pouvez vérifier la distance entre le coin supérieur gauche et le coin inférieur droit; alors vous pouvez comprendre le niveau de zoom en testant la distance (si la distance est trop éloignée, le niveau de zoom serait bas), vous pouvez sélectionner plus à l'aide de la méthode setbound ou setZoom ..

Orhun Alp Oral
la source
0

Je n'aime pas le suggérer, mais si vous devez essayer - premier appel

gmap.fitBounds(bounds);

Ensuite, créez un nouveau Thread / AsyncTask, laissez-le dormir pendant 20 à 50 ms environ, puis appelez

gmap.setZoom( Math.max(6, gmap.getZoom()) );

à partir du thread d'interface utilisateur (utilisez un gestionnaire ou la onPostExecuteméthode pour AsyncTask).

Je ne sais pas si cela fonctionne, juste une suggestion. En dehors de cela, vous devrez calculer vous-même le niveau de zoom à partir de vos points, vérifier s'il est trop bas, le corriger, puis appelergmap.setZoom(correctedZoom)

Joseph Earl
la source
0

Si «bounds_changed» ne se déclenche pas correctement (parfois, Google ne semble pas accepter parfaitement les coordonnées), envisagez plutôt d'utiliser «center_changed».

L'événement 'center_changed' se déclenche chaque fois que fitBounds () est appelé, bien qu'il s'exécute immédiatement et pas nécessairement après le déplacement de la carte.

Dans des cas normaux, «inactif» est toujours le meilleur écouteur d'événements, mais cela peut aider quelques personnes à rencontrer des problèmes étranges avec leurs appels fitBounds ().

Voir le rappel de Google Maps fitBounds

tempranova
la source
0

Pour jouer avec une autre solution - j'ai trouvé que l'approche «écouter les événements bounds_changed et ensuite définir un nouveau zoom» ne fonctionnait pas de manière fiable pour moi. Je pense que fitBoundsj'appelais parfois avant que la carte n'ait été complètement initialisée, et l'initialisation provoquait un événement bounds_changed qui utiliserait l'écouteur, avant de fitBoundschanger les limites et le niveau de zoom. Je me suis retrouvé avec ce code, qui semble fonctionner jusqu'à présent:

// If there's only one marker, or if the markers are all super close together,
// `fitBounds` can zoom in too far. We want to limit the maximum zoom it can
// use.
//
// `fitBounds` is asynchronous, so we need to wait until the bounds have
// changed before we know what the new zoom is, using an event handler.
//
// Sometimes this handler gets triggered by a different event, before
// `fitBounds` takes effect; that particularly seems to happen if the map
// hasn't been fully initialized yet. So we don't immediately remove the
// listener; instead, we wait until the 'idle' event, and remove it then.
//
// But 'idle' might happen before 'bounds_changed', so we can't set up the
// removal handler immediately. Set it up in the first event handler.

var removeListener = null;
var listener = google.maps.event.addListener(map, 'bounds_changed', () => {
  console.log(map.getZoom());
  if (map.getZoom() > 15) {
    map.setZoom(15);
  }

  if (!removeListener) {
    removeListener = google.maps.event.addListenerOnce(map, 'idle', () => {
      console.log('remove');
      google.maps.event.removeListener(listener);
    });
  }
});
philh
la source
0

Pour moi, la solution la plus simple était la suivante:

map.fitBounds(bounds);

function set_zoom() {
    if(map.getZoom()) {map.setZoom(map.getZoom() - 1);}
    else {setTimeout(set_zoom, 5);}
}
setTimeout(set_zoom, 5);
horace
la source
-1
google.maps.event.addListener(marker, 'dblclick', function () {
    var oldZoom = map.getZoom(); 
    map.setCenter(this.getPosition());
    map.setZoom(parseInt(oldZoom) + 1);
});
chétan
la source
-3

Tout ce que j'ai fait c'est:

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

Et cela fonctionne sur l'API V3.

Petr Svoboda
la source
map.setCenter n'accepte qu'un seul attribut, latlng, et la carte n'a aucune fonction comme getBoundsZoomLevel
Viktor
Je pensais qu'il y avait une fonction comme getBoundsZoomLevel après avoir vu ce post, et je suis déçu après avoir réalisé qu'il n'y en avait pas.
sedran
je pense que getBoundsZoomLevel () était disponible dans Google Maps V2 API et non dans V3 API
Kush