Google Maps v3 - ограничьте видимую область и уровень масштабирования

98

Можно ли ограничить карту Google v3 определенной областью? Я хочу разрешить отображение только некоторой области (например, страны) и запретить пользователю скользить в другом месте. Также я хочу ограничить уровень масштабирования - например, только между уровнями 6 и 9. И я хочу использовать все типы базовых карт.

Есть ли способ добиться этого?

У меня был частичный успех с ограничением уровня масштабирования с помощью StyledMap, но я добился успеха только с ограничением ROADMAP, я не смог таким образом ограничить масштабирование для других базовых типов.

Спасибо за любую помощь

Томик
источник

Ответы:

119

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

Вы также можете очень легко ограничить уровень масштабирования.

Рассмотрим следующий пример: 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>

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

Пример Google Maps JavaScript API v3: принудительно остановить перетаскивание карты

Даниэль Вассалло
источник
2
Решение не выглядит чистым. Почему if (x < minX) x = minX;и if (x > maxX) x = maxX;не исключают друг друга? Почему вы центрируете холст по координатам minX / maxX и maxX / maxY, хотя они не являются координатами центра?
Александр Паламарчук
1
Вместо dragendсобытия вы можете использовать draggable: falseэкземпляр карты ( рабочий пример )
machineaddict
Это не лучший способ использовать событие «zoom_changed» для ограничения пользователя. Поскольку в первый раз он всегда выходит за пределы минимального уровня, а затем, используя ваш код, вы снова устанавливаете минимальное масштабирование, которое будет мигать на экране.
Jitendra Pancholi
проверьте zillow.com/homes/for_sale/days_sort/… Они сделали это правильно, не знаю как.
Jitendra Pancholi
1
Это отлично сработало для меня, если я перешел на center_changedмероприятие вместо dragend.
Johan B
182

Лучшим способом ограничить уровень масштабирования может быть использование параметров minZoom/ maxZoomвместо реакции на события?

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

Или параметры могут быть указаны во время инициализации карты, например:

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

См .: Справочник по Google Maps JavaScript API V3.

ChrisV
источник
3
Теперь это, безусловно, лучший способ ограничить уровень масштабирования. Когда я писал пост, этой функции не было в Maps API v3. К счастью, они продолжают улучшать API.
Tomik
2
Это работает отлично, это лучший ответ для увеличения.
paullb
3
Это следует отметить как ответ для тех, кто смотрит только на выбранный ответ.
ErJab
9
установка уровня масштабирования не влияет на панорамирование.
simpatico
1
Определенно лучший способ пойти
ChrisRich
17

Хорошие новости. Начиная с версии 3.35 Maps JavaScript API, которая была запущена 14 февраля 2019 года, вы можете использовать новую restrictionопцию, чтобы ограничить область просмотра карты.

Согласно документации

Интерфейс MapRestriction

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

источник: https://developers.google.com/maps/documentation/javascript/reference/map#MapRestriction

Итак, теперь вы просто добавляете параметр ограничения во время инициализации карты и все. Взгляните на следующий пример, который ограничивает область просмотра до Швейцарии.

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>

Надеюсь, это поможет!

Xomen
источник
Ссылка не работает. Вот новые по этой теме: ПРИМЕР: developers-dot-devsite-v2-prod.appspot.com/maps/documentation/… DOCS: developers-dot-devsite-v2-prod.appspot.com/maps/documentation/ …
Адам
1
Исправлена ​​ссылка на документацию.
xomen 01
Спасибо, этот код вроде сработал. То есть, если вы ограничиваете масштабирование только одним уровнем, возможным с помощью minZoom и maxZoom. Похоже, что вам нужно установить разные юг, запад, север, восток для каждого уровня масштабирования, если это сработает так, как задумано. Было бы неплохо иметь разные настройки ограничений для каждого уровня масштабирования. Я выбрал свой максимальный уровень с уменьшенным масштабом и определил координаты оттуда, что сделало возможным панорамирование за пределы границ, если вы увеличиваете масштаб, а затем панорамируете.
Kim Steinhaug
6

Чтобы ограничить зум на v.3+. в настройках карты добавьте уровень масштабирования по умолчанию, а уровни масштабирования minZoom или maxZoom (или оба, если требуется) составляют от 0 до 19. Если требуется ограничение, вы должны объявить уровень масштабирования по умолчанию. все чувствительны к регистру!

function initialize() {
   var mapOptions = {
      maxZoom:17,
      minZoom:15,
      zoom:15,
      ....
ГЛУБОКО-СЕРЕБРЯНЫЙ
источник
3

Гораздо лучший способ ограничить диапазон ... использовал логику из приведенного выше плаката.

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);
                           });
Пэт
источник
Почему вы добавляете this.googleMapвместо mapвторого слушателя? И быть не dragStartдолжно dragStartCenter? Наконец, что есть mapBounds?
hobbes3 02
2
Наверняка все, что это делает, - это не дать пользователю уйти слишком далеко одним движением перетаскивания? Они все еще могут сделать много мелких затяжек и оказаться где угодно, не так ли?
Джеймс
1

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

    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));
        }
    });
Джонатан Бусуттил
источник
1
myOptions = {
        center: myLatlng,
        minZoom: 6,
        maxZoom: 9,
        styles: customStyles,
        mapTypeId: google.maps.MapTypeId.ROADMAP
    };
Ануп
источник
1
Это не отвечает на вопрос.
Кит Сунд
0

Вот мой вариант решения проблемы ограничения видимой области.

        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это объект new google.maps.LatLngBounds()типа. self.gmapхранит объект Google Map ( new google.maps.Map()).

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

Александр Паламарчук
источник
Принято. Алгоритм Даниэля Вассалло у меня не работает. Здесь есть несколько принципиальных отличий.
Александр Паламарчук
0

По какой-то причине

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

у меня не сработало (возможно, проблема южного полушария). Мне пришлось изменить его на:

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

Надеюсь, это кому-то поможет.

Майко
источник
0

Одно из решений: если вы знаете конкретную широту / долготу.

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

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

});

Если нет конкретной широты / долготы

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

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

});

или

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

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

});
Джейсон
источник
0

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

введите описание изображения здесь

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

Однако, как и другие существующие решения, у него есть "вибрирующая" проблема. Когда пользователь достаточно агрессивно перемещает карту, после того, как он отпускает левую кнопку мыши, карта все еще продолжает панорамирование сама по себе, постепенно замедляясь. Я всегда возвращаю карту в исходное положение, но это приводит к некоторой вибрации. В настоящий момент этот эффект панорамирования нельзя остановить никакими средствами, предоставляемыми 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:400px; width:500px;"></div>
     <script  type="text/javascript"src="https://raw.githubusercontent.com/matej-pavla/StrictBoundsImage/master/StrictBoundsImage.js"></script>
</body>

Библиотека также может автоматически рассчитывать минимальное ограничение масштабирования. Затем он ограничивает уровень масштабирования с помощью minZoomатрибута карты.

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

Матей П.
источник
-4

Это может быть полезно.

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

Уровень масштабирования можно настроить в соответствии с требованиями.

Самир Даш
источник
Это не решает исходный вопрос об ограничении уровня масштабирования диапазоном e.g. only between levels 6 and 9, он устанавливает уровень масштабирования по умолчанию и удаляет пользовательский интерфейс по умолчанию (т.е. +/ -), что немного избыточно.
Аластер