Google Maps API V3: Posso setZoom após FitBounds?
-
19-09-2019 - |
Pergunta
Tenho um conjunto de pontos que quero plotar em um mapa do Google incorporado (API V3). Eu gostaria que os limites acomodassem todos os pontos, a menos que o nível de zoom seja muito baixo (ou seja, ampliado demais). Minha abordagem tem sido assim:
var bounds = new google.maps.LatLngBounds();
// extend bounds with each point
gmap.fitBounds(bounds);
gmap.setZoom( Math.max(6, gmap.getZoom()) );
Isso não funciona. A última linha "gmap.setZoom ()" não altera o nível de zoom do mapa se chamado diretamente após o fitbounds.
Existe uma maneira de obter o nível de zoom de um limite sem aplicá -lo ao mapa? Outras idéias para resolver isso?
Solução
Editar: Veja o comentário de Matt Diamond abaixo.
Entendi! Experimente isso:
map.fitBounds(bounds);
var listener = google.maps.event.addListener(map, "idle", function() {
if (map.getZoom() > 16) map.setZoom(16);
google.maps.event.removeListener(listener);
});
Modificar para suas necessidades.
Outras dicas
Resolvi um problema semelhante em um dos meus aplicativos. Fiquei um pouco confuso com a sua descrição do problema, mas acho que você tem o mesmo objetivo que eu tinha ...
No meu aplicativo, eu queria traçar um ou mais marcadores e garantir que o mapa estivesse mostrando todos eles. O problema era que, se eu confiasse apenas no método FitBounds, o nível de zoom seria maximizado quando houvesse um único ponto - isso não era bom.
A solução era usar o FitBounds quando havia muitos pontos, e o SetCenter+Setzoom quando havia apenas um ponto.
if (pointCount > 1) {
map.fitBounds(mapBounds);
}
else if (pointCount == 1) {
map.setCenter(mapBounds.getCenter());
map.setZoom(14);
}
Eu vim a esta página várias vezes para obter a resposta e, embora todas as respostas existentes fossem super úteis, elas não resolveram exatamente meu problema.
google.maps.event.addListenerOnce(googleMap, 'zoom_changed', function() {
var oldZoom = googleMap.getZoom();
googleMap.setZoom(oldZoom - 1); //Or whatever
});
Basicamente, descobri que o evento 'Zoom_changed' impedia que a interface do usuário do mapa "pular", o que aconteceu quando eu esperei o evento 'Idle'.
Espero que isso ajude alguém!
Acabei de consertar isso definindo o Maxzoom com antecedência e depois removendo -o depois. Por exemplo:
map.setOptions({ maxZoom: 15 });
map.fitBounds(bounds);
map.setOptions({ maxZoom: null });
Se não me engano, suponho que você queira que todos os seus pontos sejam visíveis no mapa com o maior nível de zoom possível. Eu consegui isso inicializando o nível de zoom do mapa para 16(Não tenho certeza se é o nível de zoom mais alto possível no V3).
var map = new google.maps.Map(document.getElementById('map_canvas'), {
zoom: 16,
center: marker_point,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
Depois disso, fiz as coisas dos 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);
Resultado: Sucesso!
Eu uso:
gmap.setZoom(24); //this looks a high enough zoom value
gmap.fitBounds(bounds); //now the fitBounds should make the zoom value only less
Isso usará o menor de 24 e o nível de zoom necessário de acordo com o seu código, no entanto, provavelmente altera o zoom de qualquer maneira e não se importa com o quanto você diminuiu o zoom.
Eu tive o mesmo problema e pude resolvê -lo usando o seguinte código. Este ouvinte (google.maps.addListenerOnce()
) o evento só será demitido uma vez, logo depois map.fitBounds()
É executado. Então, não há necessidade de
- Acompanhe e remova manualmente o ouvinte, ou
- Espere até que o mapa seja
idle
.
Ele define o nível de zoom apropriado inicialmente e permite que o usuário amplie e faça o zoom além do nível inicial de zoom porque o ouvinte do evento expirou. Por exemplo, se apenas google.maps.addListener()
foi chamado, então o usuário faria Nunca ser capaz de aumentar o zoom após o nível de zoom declarado (no caso, 4). Desde que implementamos google.maps.addListenerOnce()
, o usuário poderá aumentar o zoom em qualquer nível que ele/ela escolher.
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)
}
});
Tinha o mesmo problema, necessário para ajustar muitos marcadores no mapa. Isso resolveu meu caso:
- Declarar limites
- Esquema de uso fornecido pelo Koderoid (para cada conjunto de marcadores
bounds.extend(objLatLng)
) Execute FitBounds após a conclusão do mapa:
google.maps.event.addListenerOnce(map, 'idle', function() { map.fitBounds( bounds ); });
Eu encontrei uma solução que faz o cheque antes de ligar fitBounds
Então você não diminui o zoom e de repente o zoom
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);
}
Você terá que brincar com a variável Minlatspan um pouco para obtê -la onde quiser. Ele variará com base no nível de zoom e nas dimensões da tela do mapa.
Você também pode usar longitude em vez de latitude
Por favor, tente isto:
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);
Eu vi muitas soluções incorretas ou muito complicadas, então decidi postar um Solução de trabalho, elegante.
A razão setZoom()
não funciona como você espera é isso fitBounds()
é assíncrono, por isso não dá garantia de que atualizaria imediatamente o zoom, mas sua chamada para setZoom()
confia nisso.
O que você pode considerar é definir o minZoom
Opção de mapa antes de ligar fitBounds()
e depois limpá -lo após a conclusão (para que os usuários ainda possam aumentar o zoom manualmente, se quiserem):
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);
Além disso, se você também deseja limitar o zoom máximo, poderá aplicar o mesmo truque com o maxZoom
propriedade.
Veja o MAPOPTions Docs.
Eu uso isso para garantir que o nível de zoom não exceda um nível definido para saber que as imagens de satélite estarão disponíveis.
Adicione um ouvinte ao zoom_changed
evento. Isso também tem o benefício adicional de controlar o controle de zoom na interface do usuário.
Executar apenas setZoom
Se você precisar, então um if
A declaração é preferível a Math.max
ou para 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);
Para evitar o zoom muito longe:
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);
Nesta função, você precisa adicionar metadados dinamicamente para armazenar o tipo de geometria apenas porque a função aceita qualquer geometria.
"FitgeOMetries" é uma função JSON estendendo um objeto de mapa.
"Geometries" é uma matriz JavaScript genérica que não é um 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);
},
Este trabalho é para mim com a API V3, mas com a definição de zoom fixo:
var bounds = new google.maps.LatLngBounds();
// extend bounds with each point
gmap.setCenter(bounds.getCenter());
gmap.setZoom( 6 );
Como eu, se você não está disposto a brincar com os ouvintes, esta é uma solução simples que eu criei: adicione um método no mapa que funciona estritamente de acordo com seus requisitos como este:
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});
}
Então você pode ligar map.fitLmtdBounds(bounds)
ao invés de map.fitBounds(bounds)
Para definir os limites sob o alcance de zoom definido ... ou map.fitLmtdBounds(bounds,3,5)
para substituir a faixa de zoom ..
Por favor, tente isso.
// 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);
}
Se isso for útil para você.
Tudo de bom
Após o cálculo dos limites, você pode verificar a distância entre o canto superior esquerdo e para baixo direito; Em seguida, você pode entender o nível de zoom testando a distância (se a distância estiver muito longe, o nível de zoom seria baixo), você pode selecionar o WHETER usando o método Setbound ou Setzoom.
Eu não gosto de sugerir, mas se você devo Tente - Primeira chamada
gmap.fitBounds(bounds);
Em seguida, crie um novo thread/assíncena, deixe-o dormir por 20-50ms ou mais e depois ligue
gmap.setZoom( Math.max(6, gmap.getZoom()) );
Do tópico da interface do usuário (use um manipulador ou o onPostExecute
método para assíncrogem).
Não sei se funciona, apenas uma sugestão. Fora isso, você teria que calcular de alguma forma o nível de zoom a partir de seus pontos, verifique se estiver muito baixo, corrija -o e depois ligue gmap.setZoom(correctedZoom)
Se 'Bounds_Changed' não estiver disparando corretamente (às vezes o Google não parece aceitar coordenadas perfeitamente), considere usar 'Center_changed'.
O evento 'Center_Changed' é chamado sempre que o FitBounds () é chamado, embora seja executado imediatamente e não necessariamente após a mudança do mapa.
Em casos normais, 'Idle' ainda é o melhor ouvinte de eventos, mas isso pode ajudar algumas pessoas a ter problemas estranhos com suas chamadas FitBounds ().
Para entrar em contato com outra solução - descobri que a abordagem "ouça para o evento Bounds_Changed e, em seguida, definir uma nova zoom" não funcionou de maneira confiável para mim. Eu acho que às vezes estava ligando fitBounds
antes do mapa ter sido totalmente inicializado, e a inicialização estava causando um evento Bounds_Changed que usaria o ouvinte antes fitBounds
mudou os limites e o nível de zoom. Acabei com este código, que parece funcionar até agora:
// 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);
});
}
});
Para mim, a solução mais fácil foi a seguinte:
map.fitBounds(bounds);
function set_zoom() {
if(map.getZoom()) {map.setZoom(map.getZoom() - 1);}
else {setTimeout(set_zoom, 5);}
}
setTimeout(set_zoom, 5);
google.maps.event.addListener(marker, 'dblclick', function () {
var oldZoom = map.getZoom();
map.setCenter(this.getPosition());
map.setZoom(parseInt(oldZoom) + 1);
});
Tudo o que fiz é:
map.setCenter(bounds.getCenter(), map.getBoundsZoomLevel(bounds));
E funciona na API V3.