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?
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.
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);
}
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!
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 });
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!
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.
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);
Avait le même problème, nécessaire pour adapter de nombreux marqueurs sur la carte . Cela a résolu mon cas:
bounds.extend(objLatLng)
)Exécuter fitbounds APRES que la carte est terminée:
google.maps.event.addListenerOnce(map, 'idle', function() {
map.fitBounds( bounds );
});
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
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 );
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
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)
}
});
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 ..
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 .
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);
},
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);
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 ().
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.
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);
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)
.
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
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);
});
}
});