Как ограничить панорамирование в Google Maps API V3? - PullRequest
74 голосов
/ 26 июня 2010

В V2 был способ ограничить панорамирование / перетаскивание, чтобы карта оставалась в определенных пределах. Как это делается в V3?

Допустим, я хочу, чтобы пользователи смотрели только на Европу. Я уже ограничил масштаб, но если я разрешу перетаскивать (что в данном случае необходимо по другим причинам), тогда пользователь сможет перемещаться за пределы области, которую я хочу показать.

Пожалуйста, дайте рабочий пример или фрагмент кода - я не эксперт по программированию ...

Спасибо!

Ответы [ 14 ]

91 голосов
/ 11 октября 2011

Полагаю, я немного опоздал на вечеринку, но так как это было именно то, что мне было нужно сейчас, и я улучшил его, я все равно решил написать ответ.

С обоимиответы Даниэль Вассалло и brendo , пользователь все еще может использовать пан-контроль (если он активирован), чтобы отойти от желаемой области.То, что @ Yauhen.F упомянул в комментарии.

Поэтому вместо использования события dragend я использую событие center_changed.Это происходит непрерывно во время перетаскивания, и каждый раз, когда кто-то использует элемент управления панорамированием.

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

При сохранении последней действительной позиции непрерывно во время перетаскивания, движение будет просто останавливаться, как только оно выйдет за пределы, вместо того, чтобы возвращатьсякак только перетаскивание закончилось.......

21 голосов
/ 27 июня 2010

Хитрость заключается в том, чтобы прослушать событие dragend, и если карта перетаскивается за допустимые пределы, переместите ее обратно внутрь.Если вы определяете допустимые границы как объект LatLngBounds, вы можете использовать метод contains(), поскольку он возвращает true, если заданный аргумент lat / lng находится в пределах границ.

Также важно ограничить уровень масштабирования, но, похоже, вы уже это делаете.

Поэтому вы можете попробовать следующий пример:

<!DOCTYPE html>
<html> 
<head> 
   <meta http-equiv="content-type" content="text/html; charset=UTF-8"/> 
   <title>Google Maps JavaScript API v3 Example: Limit Panning</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"> 

   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 allowedBounds = 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 (allowedBounds.contains(map.getCenter())) return;

     // Out of bounds - Move the map back within the bounds

     var c = map.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;

     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>

Снимок экрана из вышеприведенного примера,Пользователь не сможет перетащить дальше на юг или дальний восток в этом случае:

Google Maps JavaScript API v3 Example: Limit Panning

9 голосов
/ 05 июня 2013

Моя версия, основанная на версии @HenningJ, но с некоторыми изменениями lastValidCenter, позволяющими плавное перетаскивание вдоль границ границ.

<!DOCTYPE html>
<html>
    <head>
        <style type="text/css">
            html { height: 100% }
            body { height: 100%; margin: 0; padding: 0 }
            #map-canvas { height: 100% }
        </style>
        <script type="text/javascript"
            src="http://maps.google.com/maps/api/js?sensor=false"></script>
        </script>
        <script type="text/javascript">
            function initialize() {
                var mapOptions = {
                    center: new google.maps.LatLng(28.70, -127.50),
                    zoom: 4,
                    mapTypeId: google.maps.MapTypeId.ROADMAP
                };
                var map = new google.maps.Map(document.getElementById("map-canvas"),
                        mapOptions);

                // bounds of the desired area
                var allowedBounds = new google.maps.LatLngBounds(
                  new google.maps.LatLng(28.70, -127.50),
                  new google.maps.LatLng(48.85, -55.90)
                );
                var boundLimits = {
                    maxLat : allowedBounds.getNorthEast().lat(),
                    maxLng : allowedBounds.getNorthEast().lng(),
                    minLat : allowedBounds.getSouthWest().lat(),
                    minLng : allowedBounds.getSouthWest().lng()
                };

                var lastValidCenter = map.getCenter();
                var newLat, newLng;
                google.maps.event.addListener(map, 'center_changed', function() {
                    center = map.getCenter();
                    if (allowedBounds.contains(center)) {
                        // still within valid bounds, so save the last valid position
                        lastValidCenter = map.getCenter();
                        return;
                    }
                    newLat = lastValidCenter.lat();
                    newLng = lastValidCenter.lng();
                    if(center.lng() > boundLimits.minLng && center.lng() < boundLimits.maxLng){
                        newLng = center.lng();
                    }
                    if(center.lat() > boundLimits.minLat && center.lat() < boundLimits.maxLat){
                        newLat = center.lat();
                    }
                    map.panTo(new google.maps.LatLng(newLat, newLng));
                });
            }
            google.maps.event.addDomListener(window, 'load', initialize);
        </script>
    </head>
    <body>
        <div id="map-canvas"/>
    </body>
</html>

Fiddleздесь: http://jsfiddle.net/koenpunt/n7h6t/

3 голосов
/ 05 октября 2013

Лучший способ ограничения - установить уровень масштабирования и центральную точку и отключить элементы управления, такие как масштабирование, прокрутка и т. Д., Как показано ниже.

 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);
3 голосов
/ 22 ноября 2010

Вот хорошее расширение выше , которое вернет центр карты к последней действительной позиции, прослушивая событие 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);
});
2 голосов
/ 22 мая 2015

Вот решение, которое представляет собой объединение ответа Тома Андерсена и принятого в настоящее время ответа HenningJ. Преимущества этого заключаются в том, что 1) позволяет более плавно прокручивать вдоль краев (с чем решение HenningJ показалось неуклюжим), и 2) не возникает проблем при увеличении масштаба вне области (опять же, ответ HenningJ, кажется, прерывается при увеличении масштаба). и около границ).

Ответ Тома был близок к работе для меня, за исключением того, что он поместил заблокированную область в центр экрана, что было неприемлемо для приложения, над которым я работал.

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

});
1 голос
/ 31 октября 2017

Вот простое решение, которое будет работать на мобильных и настольных компьютерах.Он остановит панорамирование карты за пределами максимальной или минимальной широты мира и позволит установить минимальный уровень масштабирования, что может помочь предотвратить появление серых областей при слишком большом удалении (в зависимости от размера, установленного для вашей карты):

(Я рекомендую соблюдать осторожность при использовании события center_changed, как предложено в принятом ответе от HenningJ. В моем случае количество событий, которое это вызывает, вызвало ошибки переполнения стека в Google Chrome. Вместо этого событие 'dragend' может бытьиспользуется - хотя это позволит пользователю перетаскивать за пределы областей, а затем сразу же «вернется» к действительной области карты).

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();
    }
}
1 голос
/ 09 апреля 2013

Я попробовал ответ от Хеннинга, и карта не остановится, пока центр не окажется в углу границ, что не было идеальным. Вот мое решение:

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));
1 голос
/ 13 января 2012

Есть другая тема на эту тему, что тоже очень хорошо. Проблема, которую мне пришлось решить, заключалась в том, что вместо того, чтобы устанавливать границы вручную и проверять содержание центра, я хотел установить границу при загрузке страницы, а затем разрешить перетаскивание на край при увеличении.

Итак, я установил границы панорамирования при загрузке карты, один раз. Затем я проверяю, находится ли карта на максимальном увеличении, и если да, возвращаю начальный центр. При увеличении я хочу перемещаться по КРАЮ начальных границ, а не просто проверять, содержится ли CENTER, потому что это расширит допустимое панорамирование на половину области просмотра.

К сожалению, несмотря на то, что это хорошо выполнено и хорошо работает при медленном панорамировании, при быстром панорамировании это немного прерывисто.

Если у вас есть предложения о том, как этого можно избежать, я был бы признателен.

    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
            )
        );
    });
0 голосов
/ 10 июня 2016

Я знаю, что немного опаздываю на вечеринку, но, похоже, по состоянию на середину 2016 года , нет официального способа ограничить видимую область.

Существуют некоторые решения для ограничения границ (некоторые из них в этом вопросе), но для меня у них есть недостаток, потому что они не ограничивают границы точно так, чтобы соответствовать виду карты, они только ограничивают центр карты. содержится в указанных пределах. Если вы хотите ограничить границы наложенным изображением, как я, это может привести к поведению, как показано ниже, когда карта наложения видна под наложением нашего изображения:

enter image description here

Чтобы решить эту проблему, я создал библиотеку , которая успешно ограничивает границы, поэтому вы не можете перемещаться из оверлея.

Однако, как и у других существующих решений, у него есть «вибрирующая» проблема. Когда пользователь достаточно агрессивно перемещается по карте, после того, как он отпустил левую кнопку мыши, карта все равно продолжает панорамирование, постепенно замедляясь. Я всегда возвращаю карту к границам, но это приводит к вибрации, которая проходит через мгновение. Этот эффект панорамирования не может быть остановлен никакими средствами, предоставляемыми Js API в данный момент. Кажется, что пока Google не добавит поддержку чего-то вроде map.stopPanningAnimation (), мы не сможем создать плавный опыт.

Пример использования упомянутой библиотеки, самый гладкий опыт строгих границ, который я смог получить:

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:500px; width:1000px;"></div>
     <script  type="text/javascript"src="https://raw.githubusercontent.com/matej-pavla/StrictBoundsImage/master/StrictBoundsImage.js"></script>
</body>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...