web-dev-qa-db-fra.com

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

Je souhaite tracer un ensemble de points 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 faible (c'est-à-dire qu'il effectue un zoom arrière trop important). Mon approche a été comme ça:

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 modifie 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?

191
chris

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.

319
LGT

J'ai résolu un problème similaire dans l'une de mes applications. Votre description du problème me laissait un peu perplexe, mais je pense que vous avez le même objectif que moi ...

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

La solution consistait à utiliser fitBounds lorsqu'il y avait beaucoup de points et setCenter + setZoom lorsqu'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);
}
65
Jim Garvin

Je suis venu plusieurs fois sur cette page pour obtenir la réponse. Bien que toutes les réponses existantes aient été extrêmement utiles, elles n'ont pas résolu mon problème avec précision. 

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

En gros, j'ai constaté que l'événement 'zoom_changed' empêchait l'interface utilisateur de la carte de "sauter", ce qui se produisait lorsque j'attendais l'événement "inactif".

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

43
Benjamin Sussman

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

map.setOptions({ maxZoom: 15 });
map.fitBounds(bounds);
map.setOptions({ maxZoom: null });
10
Robin Whittleton

Si je ne me trompe pas, je suppose que vous souhaitez 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 sur 16 (je ne suis pas sûr qu'il s'agisse du 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 choses suivantes:

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!

4
Lester S

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 des 24 et le niveau de zoom nécessaire en fonction de votre code. Cependant, il modifie probablement le zoom de toute façon et ne se soucie pas de l'importance du zoom.

3
ytg

S'il vous plaît essayez 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);
2
Atif Tariq

Avait le même problème, nécessaire pour adapter de nombreux marqueurs sur la carte . Cela a résolu mon cas:

  1. Déclarer les limites 
  2. Utiliser le schéma fourni par koderoid (pour chaque ensemble de marqueurs bounds.extend(objLatLng))
  3. Exécuter fitbounds APRES que la carte est terminée:

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

J'ai trouvé une solution qui vérifie avant d'appeler fitBounds pour ne pas effectuer un zoom avant ou un zoom arrière

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 avec la variable minLatSpan un peu pour l’obtenir où vous le souhaitez. Il varie en fonction du niveau de zoom et des dimensions de la carte. 

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

2
CheapSteaks

ce travail est pour moi avec API v3 mais avec le réglage zoom fixe:

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

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

J'ai eu le même problème et j'ai pu le résoudre en utilisant le code suivant. Cet événement d'écoute (google.maps.addListenerOnce()) ne sera déclenché qu'une seule fois, juste après l'exécution de map.fitBounds(). Donc, il n'y a pas besoin de 

  1. Gardez une trace et supprimez manuellement l'auditeur, 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 le programme d'écoute d'événement a expiré. Par exemple, si seulement google.maps.addListener() était appelé, l’utilisateur jamais pouvoir zoomer au-delà du niveau de zoom indiqué (dans le cas, 4). Depuis que nous avons implémenté google.maps.addListenerOnce(), l’utilisateur pourra zoomer sur 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) 
   }
});
1
9monkeys

Comme moi, si vous ne voulez pas jouer avec les auditeurs, voici une solution simple que je propose: Ajoutez une méthode sur une carte qui fonctionne strictement selon vos exigences, 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});
    }

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

1
Kanak Singhal

J'ai vu beaucoup de solutions incorrectes ou trop compliquées, alors j'ai décidé de poster un solution efficace et élégante.

La raison pour laquelle setZoom() ne fonctionne pas comme prévu est que fitBounds() est asynchrone. Elle ne garantit donc pas l'actualisation immédiate du zoom, mais votre appel à setZoom() s'appuie sur cela.

Ce que vous pourriez envisager est de définir l'option de carte minZoom avant d'appeler fitBounds(), puis de l'effacer une fois l'opération 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);

En outre, si vous souhaitez également limiter le zoom maximal, vous pouvez appliquer la même astuce avec la propriété maxZoom.

Voir le la documentation MapOptions .

1
Svilen Marchev

Dans cette fonction, vous devez ajouter dynamiquement des métadonnées pour stocker le type de géométrie uniquement, car la fonction accepte toutes les géométries.

"fitGeometries" est une fonction JSON qui étend un objet de la 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);
},
1
CrazyEnigma

J'utilise ceci pour m'assurer que le niveau de zoom ne dépasse pas un niveau défini afin de savoir que des images satellites seront disponibles.

Ajoutez un écouteur à l'événement zoom_changed . Cela offre également l'avantage de contrôler également le contrôle de zoom sur l'interface utilisateur.

N'exécutez setZoom que si vous en avez besoin. Une instruction if est préférable à Math.max ou à 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);
1
Mantis

Si "bounds_changed" ne se déclenche pas correctement (parfois, Google ne semble pas accepter les coordonnées parfaitement), utilisez plutôt "center_changed". 

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

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

Voir google maps rappel fitBounds

0
tempranova

Après le calcul des limites, vous pouvez vérifier la distance entre le coin supérieur gauche et le coin inférieur droit; vous pouvez alors comprendre le niveau de zoom en testant la distance (si la distance est trop grande, le niveau de zoom serait faible), puis vous pouvez sélectionner si vous utilisez la méthode setbound ou setZoom.

0
Orhun Alp Oral

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);
0
horace

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

gmap.fitBounds(bounds);

Créez ensuite 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 méthode onPostExecute pour AsyncTask).

Je ne sais pas si cela fonctionne, juste une suggestion. Sinon, vous devrez peut-être calculer vous-même le niveau de zoom à partir de vos points, vérifier s'il est trop faible, le corriger, puis appeler simplement gmap.setZoom(correctedZoom).

0
Joseph Earl

S'il vous plaît essayez 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 aidera.

Bonne chance

0
Kanak Vaghela

Pour ajouter une autre solution, j'ai constaté que l'approche "écoutez l'événement bounds_changed puis définissez un nouveau zoom" ne fonctionnait pas de manière fiable pour moi. Je pense que j’appelais parfois fitBounds avant l’initialisation complète de la carte et que l’initialisation provoquait un événement bounds_changed qui utiliserait l’auditeur, avant que fitBounds ne modifie les limites et le niveau de zoom. J'ai fini 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);
    });
  }
});
0
philh