Google Maps v3 - limite a área visível e o nível de zoom

97

é possível limitar o Google map v3 a uma determinada área? Desejo permitir a exibição de apenas uma área (por exemplo, um país) e impedir que o usuário deslize para outro lugar. Também quero restringir o nível de zoom - por exemplo, apenas entre os níveis 6 e 9. E quero usar todos os tipos de mapa básicos.

Existe alguma maneira de conseguir isso?

Tive um sucesso parcial em limitar o nível de zoom usando o StyledMap, mas só consegui restringir o ROADMAP, não consegui limitar o zoom em outros tipos básicos dessa maneira.

Obrigado por qualquer ajuda

Tomik
fonte

Respostas:

119

Você pode ouvir o dragendevento e, se o mapa for arrastado para fora dos limites permitidos, mova-o de volta para dentro. Você pode definir seus limites permitidos em um LatLngBoundsobjeto e usar o contains()método para verificar se o novo centro de latitude / longitude está dentro dos limites.

Você também pode limitar o nível de zoom com muita facilidade.

Considere o seguinte exemplo: Fiddle Demo

<!DOCTYPE html>
<html> 
<head> 
   <meta http-equiv="content-type" content="text/html; charset=UTF-8"/> 
   <title>Google Maps JavaScript API v3 Example: Limit Panning and Zoom</title> 
   <script type="text/javascript" 
           src="http://maps.google.com/maps/api/js?sensor=false"></script>
</head> 
<body> 
   <div id="map" style="width: 400px; height: 300px;"></div> 

   <script type="text/javascript"> 

   // This is the minimum zoom level that we'll allow
   var minZoomLevel = 5;

   var map = new google.maps.Map(document.getElementById('map'), {
      zoom: minZoomLevel,
      center: new google.maps.LatLng(38.50, -90.50),
      mapTypeId: google.maps.MapTypeId.ROADMAP
   });

   // Bounds for North America
   var strictBounds = new google.maps.LatLngBounds(
     new google.maps.LatLng(28.70, -127.50), 
     new google.maps.LatLng(48.85, -55.90)
   );

   // Listen for the dragend event
   google.maps.event.addListener(map, 'dragend', function() {
     if (strictBounds.contains(map.getCenter())) return;

     // We're out of bounds - Move the map back within the bounds

     var c = map.getCenter(),
         x = c.lng(),
         y = c.lat(),
         maxX = strictBounds.getNorthEast().lng(),
         maxY = strictBounds.getNorthEast().lat(),
         minX = strictBounds.getSouthWest().lng(),
         minY = strictBounds.getSouthWest().lat();

     if (x < minX) x = minX;
     if (x > maxX) x = maxX;
     if (y < minY) y = minY;
     if (y > maxY) y = maxY;

     map.setCenter(new google.maps.LatLng(y, x));
   });

   // Limit the zoom level
   google.maps.event.addListener(map, 'zoom_changed', function() {
     if (map.getZoom() < minZoomLevel) map.setZoom(minZoomLevel);
   });

   </script> 
</body> 
</html>

Captura de tela do exemplo acima. O usuário não conseguirá arrastar mais ao sul ou ao leste neste caso:

Exemplo da API JavaScript v3 do Google Maps: forçar a interrupção do arrasto do mapa

Daniel Vassallo
fonte
2
A decisão não parece clara. Por que if (x < minX) x = minX;e if (x > maxX) x = maxX;não se excluem? Por que você centraliza a tela nas coordenadas minX / maxX e maxX / maxY embora elas não sejam coordenadas de centro?
Alexander Palamarchuk
1
Em vez de dragendevento, você pode usar draggable: falsena instância do mapa ( exemplo de trabalho )
machineaddict
Esta não é uma boa técnica para usar o evento "zoom_changed" para restringir o usuário. Porque na primeira vez ele sempre vai além do nível mínimo e, em seguida, usando seu código, você está configurando o zoom mínimo novamente, que irá flikr a tela.
Jitendra Pancholi
verifique zillow.com/homes/for_sale/days_sort/… Eles fizeram isso da maneira correta, não tenho certeza de como.
Jitendra Pancholi
1
Isso funcionou perfeitamente para mim se eu mudasse para o center_changedevento em vez de dragend.
Johan B de
182

A melhor maneira de restringir o nível de zoom seria usar as opções minZoom/ em maxZoomvez de reagir aos eventos?

var opt = { minZoom: 6, maxZoom: 9 };
map.setOptions(opt);

Ou as opções podem ser especificadas durante a inicialização do mapa, por exemplo:

var map = new google.maps.Map(document.getElementById('map-canvas'), opt);

Consulte: Referência da API JavaScript V3 do Google Maps

ChrisV
fonte
3
Esta é certamente a melhor maneira de restringir o nível de zoom. Quando eu estava escrevendo a postagem, o recurso não estava presente na API do Google Maps v3. Felizmente, eles continuam melhorando a API.
Tomik
2
Isso funciona perfeitamente, essa deve ser a melhor resposta para o zoom.
paullb
3
Isso deve ser marcado como a resposta para aqueles que olham apenas para a resposta escolhida.
ErJab
9
definir o nível de zoom não tem efeito na panorâmica.
simpatico
1
Definitivamente, a melhor maneira de ir
ChrisRich
16

Boas notícias. A partir da versão 3.35 da Maps JavaScript API, lançada em 14 de fevereiro de 2019, você pode usar a nova restrictionopção para limitar a janela de visualização do mapa.

De acordo com a documentação

Interface MapRestriction

Uma restrição que pode ser aplicada ao Mapa. A janela de visualização do mapa não excederá essas restrições.

fonte: https://developers.google.com/maps/documentation/javascript/reference/map#MapRestriction

Então, agora você acabou de adicionar a opção de restrição durante a inicialização do mapa e isso. Dê uma olhada no exemplo a seguir que limita a janela de visualização à Suíça

var map;
function initMap() {
  map = new google.maps.Map(document.getElementById('map'), {
    center: {lat: 46.818188, lng: 8.227512},
    minZoom: 7,
    maxZoom: 14,
    zoom: 7,
    restriction: {
      latLngBounds: {
        east: 10.49234,
        north: 47.808455,
        south: 45.81792,
        west: 5.95608
      },
      strictBounds: true
    },
  });
}
#map {
  height: 100%;
}
html, body {
  height: 100%;
  margin: 0;
  padding: 0;
}
<div id="map"></div>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyDztlrk_3CnzGHo7CFvLFqE_2bUKEq1JEU&callback=initMap" async defer></script>

Eu espero que isso ajude!

xomena
fonte
O link não está funcionando. Aqui estão algumas novidades sobre este tópico: EXEMPLO: developers-dot-devsite-v2-prod.appspot.com/maps/documentation/… DOCS: developers-dot-devsite-v2-prod.appspot.com/maps/documentation/ …
Adam
1
Link de documentação fixo.
xomena
Obrigado, esse código meio que funcionou. Ou seja, se você limitar o zoom a apenas 1 nível possível com minZoom e maxZoom. Parece que você precisa definir um sul, oeste, noth, leste diferente para cada nível de zoom, caso funcione conforme o esperado. Seria ótimo ter uma configuração de restrição diferente para cada nível de zoom. Eu usei meu nível máximo de zoom out e defini as coordenadas a partir daí, tornando possível fazer uma panorâmica bem fora dos limites se você aumentar o zoom e, em seguida, panoramizar.
Kim Steinhaug
6

Para limitar o zoom em v.3 +. na configuração do mapa, adicione o nível de zoom padrão e os níveis de zoom minZoom ou maxZoom (ou ambos, se necessário) são de 0 a 19. Você deve declarar o nível de zoom surdo se a limitação for necessária. todos são sensíveis a maiúsculas e minúsculas!

function initialize() {
   var mapOptions = {
      maxZoom:17,
      minZoom:15,
      zoom:15,
      ....
PRATA PROFUNDO
fonte
3

Uma maneira muito melhor de limitar o intervalo ... usei a lógica contém do pôster acima.

var dragStartCenter;

google.maps.event.addListener(map, 'dragstart', function(){
                                       dragStartCenter = map.getCenter();
                                         });

google.maps.event.addListener(this.googleMap, 'dragend', function(){
                            if (mapBounds.contains(map.getCenter())) return;
                    map.setCenter(this.dragStart);
                           });
Pat
fonte
Por que você adiciona em this.googleMapvez de mappara o segundo ouvinte? Também não deveria dragStartser dragStartCenter? Por último, o que é mapBounds?
hobbes3
2
Certamente tudo o que isso faz é impedir o usuário de arrastar para longe com um movimento de arrastar? Eles ainda podem fazer muitas pequenas tragadas e acabar em qualquer lugar, não?
James
1

Isso pode ser usado para centralizar novamente o mapa em um local específico. Era disso que eu precisava.

    var MapBounds = new google.maps.LatLngBounds(
    new google.maps.LatLng(35.676263, 13.949096),
    new google.maps.LatLng(36.204391, 14.89038));

    google.maps.event.addListener(GoogleMap, 'dragend', function ()
    {
        if (MapBounds.contains(GoogleMap.getCenter()))
        {
            return;
        }
        else
        {
            GoogleMap.setCenter(new google.maps.LatLng(35.920242, 14.428825));
        }
    });
Jonathan Busuttil
fonte
1
myOptions = {
        center: myLatlng,
        minZoom: 6,
        maxZoom: 9,
        styles: customStyles,
        mapTypeId: google.maps.MapTypeId.ROADMAP
    };
Anup
fonte
1
Isso não responde à pergunta.
Kit Sunde
0

Aqui está minha variante para resolver o problema de limitação da área visível.

        google.maps.event.addListener(this.map, 'idle', function() {
            var minLat = strictBounds.getSouthWest().lat();
            var minLon = strictBounds.getSouthWest().lng();
            var maxLat = strictBounds.getNorthEast().lat();
            var maxLon = strictBounds.getNorthEast().lng();
            var cBounds  = self.map.getBounds();
            var cMinLat = cBounds.getSouthWest().lat();
            var cMinLon = cBounds.getSouthWest().lng();
            var cMaxLat = cBounds.getNorthEast().lat();
            var cMaxLon = cBounds.getNorthEast().lng();
            var centerLat = self.map.getCenter().lat();
            var centerLon = self.map.getCenter().lng();

            if((cMaxLat - cMinLat > maxLat - minLat) || (cMaxLon - cMinLon > maxLon - minLon))
            {   //We can't position the canvas to strict borders with a current zoom level
                self.map.setZoomLevel(self.map.getZoomLevel()+1);
                return;
            }
            if(cMinLat < minLat)
                var newCenterLat = minLat + ((cMaxLat-cMinLat) / 2);
            else if(cMaxLat > maxLat)
                var newCenterLat = maxLat - ((cMaxLat-cMinLat) / 2);
            else
                var newCenterLat = centerLat;
            if(cMinLon < minLon)
                var newCenterLon = minLon + ((cMaxLon-cMinLon) / 2);
            else if(cMaxLon > maxLon)
                var newCenterLon = maxLon - ((cMaxLon-cMinLon) / 2);
            else
                var newCenterLon = centerLon;

            if(newCenterLat != centerLat || newCenterLon != centerLon)
                self.map.setCenter(new google.maps.LatLng(newCenterLat, newCenterLon));
        });

strictBoundsé um objeto do new google.maps.LatLngBounds()tipo. self.gmaparmazena um objeto Google Map ( new google.maps.Map()).

Realmente funciona, mas não se esqueça de levar em consideração apenas as hemorróidas ao cruzar o 0º meridiano e os paralelos se seus limites os cobrirem.

Alexander Palamarchuk
fonte
O algoritmo de Daniel Vassallo aceito não funciona corretamente para mim. Existem várias diferenças principais aqui.
Alexander Palamarchuk
0

Por algum motivo

if (strictBounds.contains(map.getCenter())) return;

não funcionou para mim (talvez um problema do hemisfério sul). Tive que mudar para:

    function checkBounds() {
        var c = map.getCenter(),
            x = c.lng(),
            y = c.lat(),
            maxX = strictBounds.getNorthEast().lng(),
            maxY = strictBounds.getNorthEast().lat(),
            minX = strictBounds.getSouthWest().lng(),
            minY = strictBounds.getSouthWest().lat();

        if(x < minX || x > maxX || y < minY || y > maxY) {
            if (x < minX) x = minX;
            if (x > maxX) x = maxX;
            if (y < minY) y = minY;
            if (y > maxY) y = maxY;
            map.setCenter(new google.maps.LatLng(y, x));
        }
    }

Espero que ajude alguém.

Mayko
fonte
0

Uma solução é, se você souber a lat / lng específica.

google.maps.event.addListener(map, 'idle', function() {

    map.setCenter(new google.maps.LatLng(latitude, longitude));
    map.setZoom(8);

});

Se não tiver lat / lng específico

google.maps.event.addListener(map, 'idle', function() {

    map.setCenter(map.getCenter());
    map.setZoom(8);

});

ou

google.maps.event.addListener(map, 'idle', function() {

    var bounds = new google.maps.LatLngBounds();
    map.setCenter(bounds.getCenter());
    map.setZoom(8);

});
Jaison
fonte
0

Em meados de 2016 , não havia uma maneira oficial de restringir a área visível. A maioria das soluções ad-hoc para restringir os limites tem uma falha, porque não restringem os limites exatamente para caber na visualização do mapa, elas apenas o restringem se o centro do mapa estiver fora dos limites especificados. Se você quiser restringir os limites para imagens de sobreposição como eu, isso pode resultar em um comportamento como o ilustrado abaixo, onde o mapa de subjacência é visível sob nossa sobreposição de imagem:

insira a descrição da imagem aqui

Para resolver esse problema, criei uma biblioteca , que restringe os limites com sucesso para que você não possa deslocar-se para fora da sobreposição.

No entanto, como outras soluções existentes, ele tem um problema de "vibração". Quando o usuário move o mapa de forma agressiva o suficiente, depois de soltar o botão esquerdo do mouse, o mapa ainda continua a fazer panorâmica por si mesmo, diminuindo gradualmente a velocidade. Eu sempre coloco o mapa de volta nos limites, mas isso resulta em uma espécie de vibração. Este efeito panorâmico não pode ser interrompido por nenhum meio fornecido pela API Js no momento. Parece que até que o Google adicione suporte para algo como map.stopPanningAnimation (), não seremos capazes de criar uma experiência tranquila.

Exemplo usando a biblioteca mencionada, a experiência de limites estritos mais suave que consegui obter:

function initialise(){
  
  var myOptions = {
     zoom: 5,
     center: new google.maps.LatLng(0,0),
     mapTypeId: google.maps.MapTypeId.ROADMAP,
  };
  var map = new google.maps.Map(document.getElementById('map'), myOptions);
  
  addStrictBoundsImage(map);
}

function addStrictBoundsImage(map){
	var bounds = new google.maps.LatLngBounds(
		new google.maps.LatLng(62.281819, -150.287132),
		new google.maps.LatLng(62.400471, -150.005608));

	var image_src = 'https://developers.google.com/maps/documentation/' +
		'javascript/examples/full/images/talkeetna.png';

	var strict_bounds_image = new StrictBoundsImage(bounds, image_src, map);
}
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
      <script type="text/javascript">
        google.load("maps", "3",{other_params:"sensor=false"});
      </script>
<body style="margin:0px; padding:0px;" onload="initialise()">
	 <div id="map" style="height:400px; width:500px;"></div>
     <script  type="text/javascript"src="https://raw.githubusercontent.com/matej-pavla/StrictBoundsImage/master/StrictBoundsImage.js"></script>
</body>

A biblioteca também é capaz de calcular a restrição mínima de zoom automaticamente. Em seguida, ele restringe o nível de zoom usando minZoomo atributo do mapa.

Esperançosamente, isso ajude alguém que deseja uma solução que respeite totalmente os limites dados e não queira permitir que eles sejam ultrapassados.

Matej P.
fonte
-4

Isso pode ser útil.

  var myOptions = {
      center: new google.maps.LatLng($lat,$lang),
      zoom: 7,
      disableDefaultUI: true,
      mapTypeId: google.maps.MapTypeId.ROADMAP
    };

O nível de zoom pode ser personalizado de acordo com a necessidade.

Samir Dash
fonte
Isso não resolve a questão original sobre restringir o nível de zoom a um intervalo e.g. only between levels 6 and 9, ele define o nível de zoom padrão e remove a IU padrão (ou seja, +/ -), que é um pouco exagero.
Alastair