Google Maps v3 fitBounds () Zoom muito próximo para um único marcador


92

Existe uma maneira de definir um nível máximo de zoom para fitBounds()? Meu problema é que, quando o mapa é alimentado apenas por um local, ele aumenta o zoom o máximo que pode, o que realmente tira o mapa do contexto e o torna inútil. Talvez eu esteja usando a abordagem errada?

Desde já, obrigado!


2
stackoverflow.com/questions/4523023/… é uma solução muito melhor. Resposta particular de @Nequins
Kennet

Respostas:


138

Eu gosto da solução do mrt (especialmente quando você não sabe quantos pontos irá mapear ou ajustar), exceto que ela joga o marcador para fora de forma que ele não fique mais no centro do mapa. Eu simplesmente o estendi por um ponto adicional subtraindo 0,01 do lat e do lng também, de modo que ele mantém o marcador no centro. Funciona muito bem, obrigado mrt!

// Pan & Zoom map to show all markers
function fitToMarkers(markers) {

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

    // Create bounds from markers
    for( var index in markers ) {
        var latlng = markers[index].getPosition();
        bounds.extend(latlng);
    }

    // Don't zoom in too far on only one marker
    if (bounds.getNorthEast().equals(bounds.getSouthWest())) {
       var extendPoint1 = new google.maps.LatLng(bounds.getNorthEast().lat() + 0.01, bounds.getNorthEast().lng() + 0.01);
       var extendPoint2 = new google.maps.LatLng(bounds.getNorthEast().lat() - 0.01, bounds.getNorthEast().lng() - 0.01);
       bounds.extend(extendPoint1);
       bounds.extend(extendPoint2);
    }

    map.fitBounds(bounds);

    // Adjusting zoom here doesn't work :/

}

4
Boa ideia em manter o centro original. A razão pela qual o nível de zoom não pode ser ajustado de forma confiável ao usar o fitBounds()método é porque o zoom está ocorrendo de forma assíncrona: stackoverflow.com/questions/2989858/…
Metro Smurf

1
Isso funcionou muito bem para mim. Eu tive que passar a referência do mapa para a função "function fitToMarkers (markers, map)" no V3, mas funciona perfeitamente depois disso!
Shane

4
Amo isso. Boa, @ryan. Funcionou muito bem para mim, mas 0,01 no meu caso diminuiu muito, 0,001 atingiu o ponto ideal.
willdanceforfun

Obrigado. Como @willdanceforfun no mesmo caso, 001 acertou em cheio.
Goran Jakovljevic

1
Eu recomendaria esta solução stackoverflow.com/questions/2437683/…
NinjaOnSafari

38

Você pode configurar seu mapa maxZoomno MapOptions (referência de API) assim:

var map = new google.maps.Map(document.getElementById("map"), { maxZoom: 10 });

Isso evitaria que o mapa aumentasse o zoom ao usar fitBounds()e até removeria os níveis de zoom do controle de zoom.


@candlejack Exatamente como descrito na minha resposta?
Flygenring de

6
Você pode definir o maxZoomantes de ajustar os limites e, em seguida, removê-lo novamente usandomap.setOptions({ maxZoom: undefined }) no idleevento disparado alterando os limites. Isso evita o efeito de zoom in, zoom out em vez de redefinir o zoom no idleevento.
El Yobo

29

Outra solução é expandir os limites se você detectar que eles são muito pequenos antes de executar fitBounds ():

var bounds = new google.maps.LatLngBounds();
// here you extend your bound as you like
// ...
if (bounds.getNorthEast().equals(bounds.getSouthWest())) {
   var extendPoint = new google.maps.LatLng(bounds.getNorthEast().lat() + 0.01, bounds.getNorthEast().lng() + 0.01);
   bounds.extend(extendPoint);
}
map.fitBounds(bounds);

19
var map = new google.maps.Map(document.getElementById("map"), { maxZoom: 10 });

Usar a opção MaxZoom funciona melhor para não aplicar zoom para fechar as marcas que você possui.


Fantástico! Salva-vidas!
Jaypee

18

Depois de adicionar todos os limites reais, adicione essas linhas

var offset = 0.002;     
var center = bounds.getCenter();                            
bounds.extend(new google.maps.LatLng(center.lat() + offset, center.lng() + offset));
bounds.extend(new google.maps.LatLng(center.lat() - offset, center.lng() - offset));

obtém o centro dos limites reais, em seguida, adiciona dois pontos adicionais, um a nordeste e outro a sudoeste de seu centro

Isso define efetivamente o zoom mínimo, altere o valor do deslocamento para aumentar ou diminuir o zoom



11

você pode usar

map.setOptions({
    maxZoom: [what u want],
    minZoom: [what u want]
});

desta forma, você define as propriedades do mapa após o mapa ter sido inicializado ... você pode defini-las quantas vezes quiser ... mas no seu caso ... você pode defini-las antes de fitBounds ()

boa sorte rarutu


7

A maneira de evitar que o mapa amplie muito é adicionando esta linha de código:

var zoomOverride = map.getZoom();
        if(zoomOverride > 15) {
        zoomOverride = 15;
        }
      map.setZoom(zoomOverride);

Imediatamente após esta linha:

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

Sinta-se à vontade para alterar o nível de zoom para qualquer nível que você não deseja que o mapa passe de zoom.

Se você tiver qualquer problema ou dúvida, deixe-me um comentário na postagem do blog que escrevi sobre isso em http://icode4you.net/creating-your-own-store-locator-map-how-to-prevent-the- mapa-de-zoom-muito-perto-em-um-único-marcador


1
Eu gosto dessa solução, mas insira o setzoom dentro do if para não chamá-lo todas as vezes. Também pode haver um efeito colateral de tempo que retorna 'indefinido' de getzoom (). Solução: zoom = map.getZoom (); if (typeof zoom! == 'undefined' && zoom> 8) map.setZoom (8);
Le Droid

5

Gosto muito da solução do mrt e funciona perfeitamente se você sempre tiver apenas um ponto para trabalhar. No entanto, descobri que, se a caixa delimitadora não fosse baseada em um ponto, mas os pontos estivessem muito próximos, isso ainda poderia fazer com que o mapa fosse ampliado demais.

Esta é uma maneira de primeiro verificar se os pontos estão dentro de uma distância definida um do outro, então, se eles forem menores do que essa distância mínima, estenda os limites por essa distância mínima:

var bounds = new google.maps.LatLngBounds();
// here you extend your bound as you like

// ...

var minDistance = 0.002;
var sumA = bounds.getNorthEast().lng() - bounds.getSouthWest().lng();
var sumB = bounds.getNorthEast().lat() - bounds.getSouthWest().lat();

if((sumA < minDistance && sumA > -minDistance) 
&& (sumB < minDistance && sumB > -minDistance)){
var extendPoint1 = new google.maps.LatLng(bounds.getNorthEast().lat() + minDistance, bounds.getNorthEast().lng() + minDistance);
    var extendPoint2 = new google.maps.LatLng(bounds.getNorthEast().lat() - minDistance, bounds.getNorthEast().lng() - minDistance);
    bounds.extend(extendPoint1);
    bounds.extend(extendPoint2);
}

Espero que isso ajude alguém!


3

Isso lhe dá um controle direto sobre o zoom máximo permitido no ajuste de limites.

var fitToMarkers = function(map, markers, maxZoom) {
    if (typeof maxZoom == 'undefined') maxZoom = 15;

    google.maps.event.addListenerOnce(map, 'bounds_changed', function(event) {
        if (this.getZoom() > maxZoom) {
            this.setZoom(maxZoom);
        }
    });

    var bounds = new google.maps.LatLngBounds();
    for (var m = 0; m < markers.length; m++) {
        var marker = markers[m];
        var latlng = marker.getPosition();
        bounds.extend(latlng);
    }

    map.fitBounds(bounds);
};

3

Quanto a mim, eu resolvo isso criando um evento ocioso após fitBounds. Funcionando perfeitamente. Acho que essa é uma das soluções mais limpas aqui

var locations = [['loc', lat, lng], ['loc', lat, lng]];
.....
for (i = 0; i < locations.length; i++) { 
  var map = new google.maps.Map(document.getElementById('map'), {
    zoom: 10
  });
  .... create markers, etc.
}
....
map.fitBounds(bounds);  
google.maps.event.addListenerOnce(map, 'idle', function() {
  if (locations.length == 1) {
    map.setZoom(11);
  }
});

2

Resolvi com esse pedaço, já que o Google Maps V3 é orientado a eventos:

você pode dizer à API para restaurar o zoom para uma quantidade adequada quando o evento zoom_changed for acionado:

var initial = true
google.maps.event.addListener(map, "zoom_changed", function() {
    if (intial == true){
       if (map.getZoom() > 11) {
         map.setZoom(11);
         intial = false;
       }
    }
}); 

Usei o inicial para fazer o mapa não aumentar muito o carregamento quando o eventual fitBounds permorfed, sem ele qualquer evento de zoom acima de 11 seria impossível para o usuário.


1

Depois de chamar o fitBounds()método, tente configurar o nível de zoom novamente. Isso forçará o mapa a ficar naquele nível de zoom enquanto estiver centralizado no lugar certo.


0

Eu tenho uma explicação baseada na limitação do zoom máximo ao ajustar os limites. Funciona para mim (testado no Win 7 - IE 9, FF 13, Chrome 19):

// When fitting bounds:
var bounds = new google.maps.LatLngBounds();
// ...
// extend bounds as you like
// ..

// now set global variable when fitting bounds
window.fittingBounds = true;
map.fitBounds(bounds);
window.fittingBounds = false;


// attach this event listener after map init
google.maps.event.addListener(map, 'zoom_changed', function() {
    // set max zoom only when fitting bounds
    if (window.fittingBounds && map.getZoom() > 16) {
        this.setZoom(16);
    }
});

0

E .. aqui está outro.
Mesma ideia que o sr. E Ryan, mas

  • também funciona se o tamanho dos limites não for exatamente zero (*)
  • evita distorção perto dos pólos
  • usa getCenter () em vez de getNorthEast ()

(*) Nota: Se a caixa já for grande o suficiente, adicionar esses dois pontos extras não terá efeito. Portanto, não precisamos de mais verificações.

function calcBounds(markers) {
  // bounds that contain all markers
  var bounds = new google.maps.LatLngBounds();
  // Using an underscore _.each(). Feel free to replace with standard for()
  _.each(markers, function(marker) {
    bounds.extend(marker.getPosition());
  });
  // prevent lat/lng distortion at the poles
  var lng0 = bounds.getNorthEast().lng();
  var lng1 = bounds.getSouthWest().lng();
  if (lng0 * lng1 < 0) {
    // Take the cos at the equator.
    var cos = 1;
  }
  else {
    var cos0 = Math.cos(lng0);
    var cos1 = Math.cos(lng1);
    // Prevent division by zero if the marker is exactly at the pole.
    var cos_safe = Math.max(cos0, cos1, 0.0001);
  }
  var cos0 = Math.cos(bounds.getNorthEast.lng() * Math.PI / 180);
  var cos1 = Math.cos(bounds.getSouthWest.lng() * Math.PI / 180);
  // "radius" in either direction.
  // 0.0006 seems to be an ok value for a typical city.
  // Feel free to make this value a function argument.
  var rLat = 0.0006;
  var rLng = rLat / cos_safe;
  // expand the bounds to a minimum width and height
  var center = bounds.getCenter();
  var p0 = new google.maps.LatLng(center.lat() - rLat, center.lng() - rLng);
  var p1 = new google.maps.LatLng(lat.center() + rLat, center.lng() + rLng);
  bounds.extend(p0);
  bounds.extend(p1);
  return bounds;
}

EDITAR: Não tenho certeza se meu cálculo de razão está correto, considerando que temos uma projeção de Mercator. Posso reeditar isso ..



-1

Aqui está minha chance de uma solução, que também funciona quando dois marcadores estão muito próximos. O nível de zoom máximo efetivo é o mesmo em ambas as situações. Portanto, não acabamos diminuindo o zoom desnecessariamente, quando há mais de um marcador

O efeito, novamente, é garantir um zoom máximo, sem usar a opção maxZoom, que tem o efeito provavelmente indesejado de tornar impossível para o usuário aumentar o zoom além do nível de maxZoom com o controle de zoom

Calculei maxLat, minLat, maxLng e minLng de antemão ...

var minLatSpan = 0.002;
if (maxLat - minLat < minLatSpan) {
  // ensures that we do not zoom in too much
  var delta = (minLatSpan - (maxLat - minLat)) / 2;
  maxLat += delta;
  minLat -= delta;
}

map.fitBounds({
  east: maxLng,
  west: minLng,
  north: maxLat,
  south: minLat,
});
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.