Como faço para limitar o pan na API V3 dos mapas do Google?

Na V2, havia uma maneira de limitar o deslocamento / arrastamento para que o mapa permanecesse dentro de certos limites. Como isso é feito na V3?

Digamos que eu queira que os usuários olhem apenas para a Europa. Eu já limitei o zoom, mas se eu permitir arrastar (o que devo fazer neste caso, por outros motivos), o usuário pode ir além da área que desejo mostrar.

Por favor, dê exemplo de trabalho ou trecho de código – Eu não sou um codificador especialista …

Obrigado!

Acho que estou um pouco atrasado para a festa, mas como isso era exatamente o que eu precisava agora e melhorei, pensei em postar uma resposta de qualquer maneira.

Com as duas respostas de Daniel Vassallo e brendo , o usuário ainda pode usar o controle pan (se estiver ativado) para se afastar da área desejada. A coisa @ Yauhen.F mencionado em um comentário.

Então, ao invés de usar o evento dragend, eu uso o evento center_changed. Isso é acionado continuamente durante o arrasto e toda vez que alguém usa o controle pan.

// bounds of the desired area var allowedBounds = new google.maps.LatLngBounds( new google.maps.LatLng(70.33956792419954, 178.01171875), new google.maps.LatLng(83.86483689701898, -88.033203125) ); var lastValidCenter = map.getCenter(); google.maps.event.addListener(map, 'center_changed', function() { if (allowedBounds.contains(map.getCenter())) { // still within valid bounds, so save the last valid position lastValidCenter = map.getCenter(); return; } // not valid anymore => return to last valid position map.panTo(lastValidCenter); }); 

Salvando a última posição válida continuamente durante o processo de arrastar, o movimento apenas parará quando estiver fora dos limites, em vez de retornar ao final do processo. ……

O truque é ouvir o evento dragend e, se o mapa for arrastado para fora dos limites permitidos, mova-o de volta para dentro. Se você definir seus limites permitidos como um object LatLngBounds , poderá usar o método contains() , já que ele retornará true se o argumento lat / lng fornecido estiver dentro dos limites.

Também é importante limitar o nível de zoom, mas parece que você já está fazendo isso.

Portanto, você pode querer tentar o seguinte exemplo:

     Google Maps JavaScript API v3 Example: Limit Panning    

Captura de canvas do exemplo acima. O usuário não poderá arrastar mais para o sul ou extremo leste neste caso:

Exemplo da API JavaScript do Google Maps v3: limitar o deslocamento

Minha versão, baseada na de @HenningJ, mas com alguma modificação do lastValidCenter para permitir arrastar suavemente ao longo das bordas dos limites.

          

Mexa aqui: http://jsfiddle.net/koenpunt/n7h6t/

Aqui está uma boa extensão para o que está acima, que irá redefinir o centro do Mapa para a última posição válida ouvindo o evento dragstart.

 // Limit panning var lastCenter = map.getCenter(); google.maps.event.addListener(map, 'dragstart', function() { lastCenter = map.getCenter(); }); google.maps.event.addListener(map, 'dragend', function() { if(allowedBounds.contains(map.getCenter())) return; map.setCenter(lastCenter); }); 

O melhor método para restringir é, defina o nível de zoom e o ponto central e desative os controles como zoom, rolar etc, como abaixo.

  var latlng = new google.maps.LatLng(18.283078,84.047556); var myOptions = { zoom: 12, center: latlng, zoomControl: false, mapTypeId: google.maps.MapTypeId.ROADMAP, scrollwheel: false, navigationControl: false, mapTypeControl: false, scaleControl: false, draggable: false, disableDoubleClickZoom: true, }; map = new google.maps.Map(document.getElementById("map_canvas"), myOptions); 

Aqui está uma solução que é uma mesclagem da resposta de Tom Andersen e a resposta HenningJ atualmente aceita. Os benefícios disso é que 1) permite uma rolagem mais suave ao longo das bordas (com a qual a solução de HenningJ parecia desajeitada), e 2) não tem nenhum problema ao aumentar o zoom em uma área (novamente a resposta de HenningJ pareceu quebrar ao aumentar o zoom e fora perto dos limites).

A resposta de Tom estava perto de trabalhar para mim, exceto que posicionou a área bloqueada no centro da canvas, o que não era aceitável para o aplicativo em que eu estava trabalhando.

 // bounds of the desired area var allowedBounds = new google.maps.LatLngBounds( new google.maps.LatLng(70.33956792419954, 178.01171875), new google.maps.LatLng(83.86483689701898, -88.033203125) ); var lastValidCenter = map.getCenter(); google.maps.event.addListener(map, 'center_changed', function() { var mapBounds = map.getBounds(); var mapNe = mapBounds.getNorthEast(); var mapSw = mapBounds.getSouthWest(); var center = map.getCenter(); if( allowedBounds.contains(mapNe) && allowedBounds.contains(mapSw) ) { //the user is scrolling within the bounds. lastValidCenter = center; return; } //the user has scrolled beyond the edge. var mapWidth = mapNe.lng() - mapSw.lng(); var mapHeight = mapNe.lat() - mapSw.lat(); var x = center.lng(); var y = center.lat(); var maxX = allowedBounds.getNorthEast().lng(); var maxY = allowedBounds.getNorthEast().lat(); var minX = allowedBounds.getSouthWest().lng(); var minY = allowedBounds.getSouthWest().lat(); //shift the min and max dimensions by 1/2 of the screen size, so the bounds remain at the edge of the screen maxX -= (mapWidth / 2); minX += (mapWidth / 2); maxY -= (mapHeight / 2); minY += (mapHeight / 2); if (x < minX) { x = minX; } if (x > maxX) { x = maxX; } if (y < minY){ y = minY; } if (y > maxY){ y = maxY; } map.panTo(new google.maps.LatLng(y, x)); }); 

Eu tentei a resposta de HenningJ e o mapa não parava de fazer pan até que o centro estivesse em um canto dos limites que não era o ideal. Aqui está a minha solução:

 google.maps.event.addListener(map, 'center_changed', function() { var mapBounds = map.getBounds(); if(allowedBounds.contains(mapBounds.getNorthEast()) && allowedBounds.contains(mapBounds.getSouthWest())) { lastCenter = map.getCenter(); return; } map.panTo(lastCenter); }, this)); 

Aqui está uma solução simples que funcionará em dispositivos móveis e computadores. Isso impedirá que o mapa ultrapasse a latitude máxima ou mínima do mundo e permita definir um nível de zoom mínimo, o que pode ajudar a evitar que as áreas cinzas se tornem visíveis com o zoom (dependendo do tamanho que você definiu para o seu mapa):

(Recomendo caucanvas ao usar o evento center_changed como sugerido na resposta aceita por HenningJ. No meu caso, o número de events que isso causou causou erros de estouro de pilha no Google Chrome. Em vez disso, o evento ‘dragend’ pode ser usado – embora isso permita o usuário arrastar para fora das áreas e, em seguida, imediatamente “retrocederá” para uma área válida do mapa.

 var lastValidCenter; var minZoomLevel = 2; setOutOfBoundsListener(); function setOutOfBoundsListener() { google.maps.event.addListener(map, 'dragend', function () { checkLatitude(map); }); google.maps.event.addListener(map, 'idle', function () { checkLatitude(map); }); google.maps.event.addListener(map, 'zoom_changed', function () { checkLatitude(map); }); }; function checkLatitude(map) { if (this.minZoomLevel) { if (map.getZoom() < minZoomLevel) { map.setZoom(parseInt(minZoomLevel)); } } var bounds = map.getBounds(); var sLat = map.getBounds().getSouthWest().lat(); var nLat = map.getBounds().getNorthEast().lat(); if (sLat < -85 || nLat > 85) { //the map has gone beyone the world's max or min latitude - gray areas are visible //return to a valid position if (this.lastValidCenter) { map.setCenter(this.lastValidCenter); } } else { this.lastValidCenter = map.getCenter(); } } 

Há outro tópico sobre o assunto que também é muito bom. O problema que tive de resolver foi que, em vez de definir limites manualmente e verificar a contenção do centro, eu queria um conjunto de limites no carregamento da página e, em seguida, permitir arrastar até a borda, se ampliado.

Então eu defini limites de panning no carregamento do mapa, uma vez. Então eu verifico se o mapa ainda está no zoom máximo e, em caso afirmativo, retorne o centro inicial. Se ampliada, quero deslocar para o EDGE dos limites iniciais, e não apenas verificar se o CENTER continha, porque isso estenderia o panorama permitido pela metade do viewport.

Infelizmente, embora isso funcione bem e funcione bem ao se movimentar lentamente, é um pouco irregular se você se movimentar rapidamente.

Se você tiver sugestões sobre como isso pode ser evitado, eu ficaria grato.

  map = new google.maps.Map( // defaults document.getElementById("map22"), { disableDefaultUI : true, zoomControl : true, zoom : 7, minZoom : 7, maxZoom : 10, center : new google.maps.LatLng( 64.99473104134819, -19.22332763671875 ), mapTypeId : google.maps.MapTypeId.ROADMAP } ); function borders(){ return { maxLat : map.getBounds().getNorthEast().lat(), maxLng : map.getBounds().getNorthEast().lng(), minLat : map.getBounds().getSouthWest().lat(), minLng : map.getBounds().getSouthWest().lng(), center : map.getCenter() } } google.maps.event.addListenerOnce(map,'idle',function() { limit = borders(); }); google.maps.event.addListener(map,'drag',function() { if(map.getZoom() == 7) return map.setCenter(limit.center); current = borders(); if( current.maxLng < limit.maxLng && current.minLng > limit.minLng ) activeCenterLng = current.center.lng(); if( current.maxLat < limit.maxLat && current.minLat > limit.minLat ) activeCenterLat = current.center.lat(); map.setCenter( new google.maps.LatLng( activeCenterLat, activeCenterLng ) ); }); 

Quando estou usando arrastar ou arrastar ou o que for, o mapa pula de volta aos limites permitidos, em vez de simplesmente restringir o movimento de transbordamento. Basta alterar o evento para ‘center_changed’ para impedir que ele pule desse jeito.

Jsfiddle modificado: http://jsfiddle.net/Vjdde/1/

Edit: Não tenho certeza porque o violino não produz um estouro de pilha, mas deveria, porque o setCenter vai chamar center_changed novamente .. Apenas atente

As soluções aqui me deixaram com 2 problemas. Primeiro de tudo, se você mantivesse pressionada a tecla de seta para que ela começasse a se mover rapidamente, quando atingisse a borda, ela não iria até a borda porque, devido à aceleração de panning, tomando grandes “etapas”, a próxima ” passo “teria ido fora dos limites, por isso não leva esse último” passo “. Então, quando parasse, você poderia soltar a tecla de seta e pressioná-la novamente, e ela se moveria um pouco mais. Em segundo lugar, essas soluções não contêm adequadamente o pan após uma alteração de zoom. Consegui resolver ambos e publiquei a minha solução em outro tópico , mas achei que poderia vinculá-lo aqui, já que esse foi o primeiro tópico que me iniciou na direção certa.

Este é o HenningJ – mas o HenningJ no ios usa lastValidCentre – o que não é bom, já que é antigo, então eu clamp, o que o torna melhor no iOS.

 var mapObject = plugin_map.gmap3('get'); var allowedBounds = new google.maps.LatLngBounds( new google.maps.LatLng(41.3957556, -88.4345472), new google.maps.LatLng(49.4010417, -78.4286389) ); google.maps.event.addListener(mapObject, 'center_changed', function() { if (allowedBounds.contains(mapObject.getCenter())) { // still within valid bounds, so save the last valid position return; } // not valid anymore => return to last valid position var c = mapObject.getCenter(), x = c.lng(), y = c.lat(), maxX = allowedBounds.getNorthEast().lng(), maxY = allowedBounds.getNorthEast().lat(), minX = allowedBounds.getSouthWest().lng(), minY = allowedBounds.getSouthWest().lat(); if (x < minX) x = minX; if (x > maxX) x = maxX; if (y < minY) y = minY; if (y > maxY) y = maxY; //mapObject.setCenter(new google.maps.LatLng(y, x)); mapObject.panTo(new google.maps.LatLng(y, x)); }); 

Vou postar minha resposta caso alguém esteja interessado porque não consegui o que precisava com qualquer uma das outras soluções postadas aqui.

O que eu precisava era restringir os limites verticais (latitude) do mapa para que o usuário não pudesse se mover além dos limites de latitude do planeta (~ +/- 85 graus), mas qualquer outro limite também funcionaria.

Essa abordagem usa o mesmo evento center_changed como descrito em outros lugares e simplesmente fixa o centro caso partes dos limites proibidos sejam mostradas.

Esse mecanismo só funciona se o zoom mínimo do mapa estiver definido, de modo que o afastamento nunca mostre mais área do que dentro dos limites permitidos.

Exemplo de trabalho: http://jsbin.com/vizihe

 function initMap() { // sample bounds, can be anything and goes hand in hand with minZoom var northBoundary = 40 var southBoundary = -40 var map = new google.maps.Map(document.getElementById('map'), { center: {lat: 0, lng: 0}, zoom: 4, // it's important to set this to a large enough value // so that zooming out does not show an area larger than allowed minZoom: 4 }) map.addListener('center_changed', function () { var bounds = map.getBounds(); var ne = bounds.getNorthEast() var sw = bounds.getSouthWest() var center = map.getCenter() if(ne.lat() > northBoundary) { map.setCenter({lat: center.lat() - (ne.lat() - northBoundary), lng: center.lng()}) } if(sw.lat() < southBoundary) { map.setCenter({lat: center.lat() - (sw.lat() - southBoundary), lng: center.lng()}) } }) } 
 html, body, #map { height: 100%; margin: 0; padding: 0; } 
     Simple Map     

Eu sei que estou atrasado para a festa, mas parece que a partir de meados de 2016 , não há maneira oficial de restringir a área visível.

Existem algumas soluções para restringir os limites (alguns deles nesta questão), mas para mim eles têm uma falha, porque eles não restringem os limites exatamente para se ajustarem à visualização do mapa, eles apenas restringem o centro do mapa a ser contido dentro do mapa. limites especificados. Se você quiser restringir os limites à sobreposição de imagens como eu, isso pode resultar em um comportamento como ilustrado abaixo, onde o mapa subjacente é visível sob a sobreposição da imagem:

insira a descrição da imagem aqui

Para resolver esse problema, criei uma biblioteca que restringe os limites com êxito, para que você não possa aproveitar a superposição.

No entanto, como outras soluções existentes, tem um problema de “vibração”. Quando o usuário movimenta o mapa de forma agressiva o suficiente, depois de soltar o botão esquerdo do mouse, o mapa continua a percorrer sozinho, diminuindo gradualmente. Eu sempre devolvo o mapa de volta aos limites, mas isso resulta em um tipo de vibração, que se instala depois de um momento. Esse efeito de panning não pode ser interrompido com qualquer meio fornecido pela API do Js no momento. Parece que até o google adicionar suporte para algo como map.stopPanningAnimation () não poderemos criar uma experiência tranquila.

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

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