API do Google Maps v3: Posso definir o Zoom após o fitBounds?

201

Eu tenho um conjunto de pontos que quero plotar em um Google Map incorporado (API v3). Eu gostaria que os limites acomodassem todos os pontos, a menos que o nível de zoom esteja muito baixo (ou seja, diminua o zoom 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 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?

chris
fonte
1
Consulte stackoverflow.com/questions/4523023/using-setzoom-after-using-fitbounds-with-google-maps-api-v3
Mawg diz para reinstalar Monica em

Respostas:

337

Editar : Veja o comentário de Matt Diamond abaixo.

Entendi! Tente o seguinte:

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

Modifique para suas necessidades.

LGT
fonte
76
Ótima solução, totalmente me salvou um monte de problemas. Só queria acrescentar que você poderia simplificá-lo ainda mais usando o método addListenerOnce ... dessa forma, você não precisa salvar o ouvinte e removê-lo manualmente, pois o método cuidará disso para você.
Matt Diamante
9
Isso tem o comportamento de ver o mapa "pular". Em vez disso, ouça o evento "zoom_change" e configure-o antes de chamar fitBounds (). Veja minha resposta abaixo
Benjamin Sussman
Obrigado! google.maps.event.addListenerOnce (mapa, "idle", function () {} -> funcionou muito bem para o meu pacote de mapas para SugarCRM.
jjwdesign
O ouvinte não é acionado para mim. Eu tentei isso em document.ready e window.load. Alguma ideia? O objeto map está OK e tentou addListener também: `var map = $ (" # js-main-map-canvas "); var listener = google.maps.event.addListenerOnce (map, "idle", function () {alert ('hello');}); `
Henrik Erlandsson
Henrik, tente $ ("# js-mapa-principal-tela") [0] ou $ ("# js-mapa-principal-tela"). Get (0);
Rafael
68

Resolvi um problema semelhante em um dos meus aplicativos. Fiquei um pouco confuso com a descrição do problema, mas acho que você tem o mesmo objetivo que eu ...

No meu aplicativo, eu queria plotar 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 seria bom.

A solução foi usar fitBounds quando havia muitos pontos e setCenter + setZoom quando havia apenas um ponto.

if (pointCount > 1) {
  map.fitBounds(mapBounds);
}
else if (pointCount == 1) {
  map.setCenter(mapBounds.getCenter());
  map.setZoom(14);
}
Jim Garvin
fonte
5
Sua resposta resolveu meu problema com o Google Maps V3. Obrigado!
FR6
1
Eu tive exatamente o mesmo problema e sua solução funcionou! Obrigado!
manubkk
Eu estava tentando a mesma abordagem sozinho, mas não funcionou porque não estava chamando setCenter () antes de definir o zoom ... Ainda estou me perguntando por que essa etapa é necessária, mas mesmo assim agora funciona ... obrigado muito Jim!
Daveoncode
O Map Center resolveu o problema que eu estava tendo! Um bom +1
Piotr Kula
1
Obrigado pela sua boa resposta +1
Bharat Chodvadiya
44

Eu vim a esta página várias vezes para obter a resposta e, embora todas as respostas existentes tenham sido super úteis, elas não resolveram exatamente o 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 "pulasse", o que aconteceu quando eu esperei pelo evento "ocioso".

Espero que isso ajude alguém!

Benjamin Sussman
fonte
4
Excelente, também tive o comportamento de pular / aplicar zoom automático. Assim como uma nota para outros leitores: certifique-se de usar "addListenerOnce", como Benjamin faz acima em vez de "addListener", ou quebrar a cabeça sobre o porquê de seu navegador trava o tempo todo ;-)
Geert-Jan
6
Observe também que o ouvinte deve ser adicionado antes de chamar fitBounds()se estiver usandozoom_changed
gapple
1
Obrigado por isso, parece que a v4 deve ter um fitBounds (limites, minZoomLevel) :)
Richard
3
Benjamin, acho melhor usar bounds_changed, porque zoom_changednão precisa ser acionado no caso em que fitBoundsmantém o nível de zoom. Minha tentativa jsfiddle.net/rHeMp/10 não confirma isso, mas não se deve confiar em um comportamento indefinido.
TMS
10

Eu consertei isso configurando o maxZoom com antecedência e removendo-o depois. Por exemplo:

map.setOptions({ maxZoom: 15 });
map.fitBounds(bounds);
map.setOptions({ maxZoom: null });
Robin Whittleton
fonte
A melhor solução, de longe, para evitar muito zoom. Simples e intuitivo. Nenhum desenho e re-desenho do mapa.
user2605793
Esta é realmente a melhor solução até agora.
Downhillski
2
Descobri que isso não funciona se você redefinir o maxZoom imediatamente após chamar fitBounds, porque o zoom ocorre de forma assíncrona (portanto, o maxZoom volta a ser nulo quando aumenta o zoom). Esperar até que "ocioso" para redefini-lo resolveria isso, embora eu ache.
user987356
4

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. 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 na V3).

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

Depois disso eu fiz as coisas de 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!

Lester S
fonte
3

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.

ytg
fonte
Eu odeio dizer isso, mas por mais estranha que pareça essa resposta, é a única coisa que funcionou até agora e eu tenho procurado por 4-5 horas em um período de 3 dias. Ainda estará procurando uma solução melhor.
Allov
3

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);
Atif Tariq
fonte
2

Eu tive o mesmo problema e consegui resolvê-lo usando o código a seguir. Este google.maps.addListenerOnce()evento listener ( ) será acionado apenas uma vez, logo após a map.fitBounds()execução. Portanto, não há necessidade de

  1. Acompanhe e remova manualmente o ouvinte ou
  2. Aguarde até o mapa estar idle.

Inicialmente, define o nível de zoom apropriado e permite ao usuário aumentar e diminuir o zoom além do nível de zoom inicial, porque o ouvinte de eventos expirou. Por exemplo, se apenas google.maps.addListener()fosse chamado, o usuário nunca seria capaz de aumentar o zoom além do nível de zoom indicado (no caso, 4). Desde que implementamos google.maps.addListenerOnce(), o usuário poderá aumentar o zoom para qualquer nível que 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) 
   }
});
9monkeys
fonte
2

Teve o mesmo problema, necessário para ajustar muitos marcadores no mapa. Isso resolveu meu caso:

  1. Declarar limites
  2. Esquema de uso fornecido pelo koderoid (para cada conjunto de marcadores bounds.extend(objLatLng))
  3. Execute fitbounds APÓS o mapa ser concluído:

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

Encontrei uma solução que faz a verificação antes de ligar, fitBoundspara você não aumentar o zoom e diminuir o zoom repentinamente

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 um pouco com a variável minLatSpan para chegar onde quiser. Isso 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

CheapSteaks
fonte
Funciona para mim, mas não estou usando o minLatSpan - só preciso definir o zoom quando 1 marcador estiver no mapa. Portanto, estou apenas verificando se há mais de 1 marcadores.
Micer
2

Vi muitas soluções incorretas ou muito complicadas, então decidi postar uma solução elegante e funcional .

O motivo setZoom()que não funciona como você espera é que fitBounds()é assíncrono, portanto não garante que atualizaria imediatamente o zoom, mas sua ligação setZoom()depende disso.

O que você pode considerar é definir a minZoomopção de mapa antes de ligar fitBounds()e limpá-la após a conclusão (para que os usuários ainda possam diminuir 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 quiser limitar o zoom máximo, poderá aplicar o mesmo truque com a maxZoompropriedade

Veja os documentos do MapOptions .

Svilen Marchev
fonte
1

Eu uso isso para garantir que o nível de zoom não exceda um nível definido, para que eu saiba que as imagens de satélite estarão disponíveis.

Adicione um ouvinte ao zoom_changed evento. Isso tem o benefício adicional de controlar também o controle de zoom na interface do usuário.

Execute apenas setZoomse for necessário; portanto, uma ifinstrução é preferível a Math.maxouMath.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 diminuir o zoom muito:

   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);
louva a Deus
fonte
1

Nesta função, você precisa adicionar dinamicamente metadados para armazenar o tipo de geometria apenas porque a função aceita qualquer geometria.

"fitGeometries" é uma função JSON que estende um objeto de mapa.

"geometries" é uma matriz javascript genérica, não uma 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
fonte
Como alternativa, eu fiz todo o trabalho sem saber que existe um método extend () no objeto LatLngBounds. Isso seria muito mais fácil.
22410 CrazyEnigma
1

este trabalho é para mim com a API v3, mas com a configuração de zoom fixo:

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

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

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 funcione 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});
    }

em seguida, você pode ligar em map.fitLmtdBounds(bounds)vez de map.fitBounds(bounds)definir os limites sob o intervalo de zoom definido ... ou map.fitLmtdBounds(bounds,3,5)substituir o intervalo de zoom.

Kanak Singhal
fonte
0

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ê.

Muito bem sucedida

Kanak Vaghela
fonte
0

Após o cálculo das fronteiras, você pode verificar a distância entre o canto superior esquerdo e o inferior direito; então, 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), então você pode selecionar se usa o método definido ou o setZoom.

Orhun Alp Oral
fonte
0

Não gosto de sugerir, mas se você deve tentar - primeira chamada

gmap.fitBounds(bounds);

Em seguida, crie um novo Thread / AsyncTask, deixe-o dormir por 20 a 50 ms ou mais e chame

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

do thread da interface do usuário (use um manipulador ou o onPostExecutemétodo para AsyncTask).

Não sei se funciona, apenas uma sugestão. Fora isso, você teria que calcular o nível de zoom de seus pontos, verificar se está muito baixo, corrigi-lo e ligar paragmap.setZoom(correctedZoom)

Joseph Earl
fonte
0

Se 'bounds_changed' não estiver sendo disparado corretamente (às vezes o Google parece não aceitar coordenadas perfeitamente), considere usar 'center_changed'.

O evento 'center_changed' é acionado toda vez que fitBounds () é chamado, embora seja executado imediatamente e não necessariamente após a movimentação do mapa.

Em casos normais, 'inativo' ainda é o melhor ouvinte de eventos, mas isso pode ajudar algumas pessoas a enfrentar problemas estranhos com suas chamadas fitBounds ().

Ver retorno de chamada fitBounds do google maps

tempranova
fonte
0

Para entrar em contato com outra solução - descobri que a abordagem "escute bounds_changed e depois defina um novo zoom" não funcionou de maneira confiável para mim. Acho que às vezes estava ligando fitBoundsantes que o mapa fosse totalmente inicializado e a inicialização estava causando um evento bounds_changed que usaria o ouvinte, antes de fitBoundsalterar 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);
    });
  }
});
philh
fonte
0

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);
horace
fonte
-1
google.maps.event.addListener(marker, 'dblclick', function () {
    var oldZoom = map.getZoom(); 
    map.setCenter(this.getPosition());
    map.setZoom(parseInt(oldZoom) + 1);
});
chetan
fonte
-3

Tudo o que fiz foi:

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

E funciona na API V3.

Petr Svoboda
fonte
O map.setCenter aceita apenas um atributo, latlng, e o mapa não tem função como getBoundsZoomLevel
Viktor
Eu pensei que há uma função como getBoundsZoomLevel depois de ver este post, e estou decepcionado depois de perceber que não há.
Sedran
eu acho que getBoundsZoomLevel () estava disponível no Google Maps API V2 e não na API V3
Kush