Google Maps API 3 уменьшает масштаб fitBounds

Я столкнулся с проблемой, когда вызов map.fitBounds, кажется, уменьшает масштаб. Я пытаюсь использовать маршрутизатор backbone.js, чтобы сохранить границы карты в URL-адресе. Я хочу иметь возможность добавить URL-адрес в закладки, а позже карта будет выглядеть точно так же.

Я заметил, что вызов map.fitBounds(map.getBounds()) в консоли всегда будет уменьшать масштаб. Куда как хотелось бы не менять карту.

Это нормальное поведение? Как я могу обеспечить это, чтобы карта выглядела одинаково от одного шага к другому?

Спасибо


person codr    schedule 17.11.2011    source источник
comment
stackoverflow.com/a/51270624/434697 работал у меня.   -  person Kayote    schedule 24.04.2020


Ответы (7)


Эта проблема Google Map API обсуждалась несколько раз. Видеть:

Функция map.fitBounds() устанавливает область просмотра, чтобы она содержала границы. Но функция map.getBounds() возвращает границы области просмотра с некоторым дополнительным запасом (обратите внимание, что это нормальное поведение, а не ошибка). Увеличенные границы больше не помещаются в предыдущую область просмотра, поэтому карта уменьшается.

Простое решение вашей проблемы — использовать вместо этого центр карты и уровень масштабирования. См. функции map.getCenter(), map.setCenter(), map.getZoom() и map.setZoom().

person Tomik    schedule 17.11.2011
comment
Мне потребовалось более 16 часов, чтобы приземлиться здесь. Даже если это не ошибка, для тех, кто пытается это сделать, должны быть обходные пути. - person Yugal Jindle; 07.03.2013

Для тех, кто видит этот вопрос в 2018 году, API Google Maps v3 теперь поддерживает второй аргумент padding, который указывает количество отступов, которые должны быть включены вокруг указанных вами границ.

Чтобы избежать уменьшения масштаба, просто вызовите fitBounds с отступом 0. Для этого примера это будет map.fitBounds(map.getBounds(), 0)

person Chang Liu    schedule 08.03.2018

Решение этой проблемы в 2017 году

Немного уменьшите ограничивающую рамку перед отправкой на map.fitBounds().

Вот функция для уменьшения ограничивающей рамки:

// Values between 0.08 and 0.28 seem to work
// Any lower and the map will zoom out too much
// Any higher and it will zoom in too much
var BOUNDS_SHRINK_PERCENTAGE = 0.08; // 8%

/**
 * @param  {google.maps.LatLngLiteral} southwest
 * @param  {google.maps.LatLngLiteral} northeast
 * @return {Array[google.maps.LatLngLiteral]}
 */
function slightlySmallerBounds(southwest, northeast) {
  function adjustmentAmount(value1, value2) {
    return Math.abs(value1 - value2) * BOUNDS_SHRINK_PERCENTAGE;
  }

  var latAdjustment = adjustmentAmount(northeast.lat, southwest.lat);
  var lngAdjustment = adjustmentAmount(northeast.lng, southwest.lng);

  return [
    {lat: southwest.lat + latAdjustment, lng: southwest.lng + lngAdjustment},
    {lat: northeast.lat - latAdjustment, lng: northeast.lng - lngAdjustment}
  ]
}

Используйте это так:

// Ensure `southwest` and `northwest` are objects in google.maps.LatLngLiteral form:
// southwest == {lat: 32.79712, lng: -117.13931}
// northwest == {lat: 32.85020, lng: -117.09356}

var shrunkBounds = slightlySmallerBounds(southwest, northeast);
var newSouthwest = shrunkBounds[0];
var newNortheast = shrunkBounds[1];

// `map` is a `google.maps.Map`
map.fitBounds(
  new google.maps.LatLngBounds(newSouthwest, newNortheast)
);

У меня есть приложение, делающее то же самое, что и codr: сохранение текущих границ карты в URL-адресе и инициализация карты из URL ограничивается при обновлении. Это решение прекрасно работает для этого.

Почему это работает?

По сути, Google Maps делает это, когда вызывается fitBounds():

  1. Сосредоточьте карту на центральной точке заданного ограничивающего прямоугольника.
  2. Увеличьте масштаб до самого высокого уровня масштабирования, при котором область просмотра будет содержать заданные границы внутри окна области просмотра.

Если заданные границы точно соответствуют области просмотра, Карты Google не считают это «содержащим» границы, поэтому уменьшают масштаб еще на один уровень.

person Paul Statezny    schedule 19.01.2017

У меня возникла та же проблема, когда после инициализации карты с именем map.fitBounds(...). Поведение, с которым я столкнулся, заключалось в том, что если метод fitBounds вызывался через несколько секунд после инициализации карты, то проблем не возникало (масштаб был соответствующим). Итак, сначала я начал вызывать метод fitBounds после того, как карта была загружена, что на картах Google означает, что карта idle.

google.maps.event.addListener(map, 'idle', function() {
   var bounds = //define bounds...
   map.fitBounds(bounds);
});

Это действительно работает, однако событие idle запускается почти постоянно. И если есть какие-либо изменения на карте (перетаскивание, масштабирование и т. д.), когда это изменение прекратится, карта снова будет соответствовать границам... Проблема в том, что вызов метода только один раз не работать (либо с логическим значением, чтобы проверить, был ли он уже вызван, либо с google.maps.event.addListenerOnce, потому что в первый раз, когда карта простаивает, она все еще «не готова» для установки границ. (Из опыта).

Итак, мое решение состояло в том, чтобы активировать fitBounds в другом событии. Вместо idle, который вызывается слишком рано для метода fitBounds, событие tilesloaded фактически выполняет свою работу (вызывается только один раз)!

Решение:

google.maps.event.addListenerOnce(map, 'tilesloaded', function() {
   var bounds = //define bounds...
   map.fitBounds(bounds);
});
person Miguel Rebocho    schedule 15.05.2020

Я заметил такое поведение при использовании fitBounds() в скрытом представлении карты (с использованием внешней среды рендеринга, такой как Angular). Поскольку это было мобильное представление, я сначала показывал список местоположений и заполнял маркеры на скрытой карте по мере загрузки списка (одновременная загрузка). Таким образом, когда пользователь хочет просмотреть карту и переключает вид сегмента/вкладку/что угодно, карта будет отображаться с уже загруженными и видимыми маркерами. Но это вышло из строя и увеличило масштаб, чтобы показать весь мир на карте.

<div [hidden]="view !== 'map'>
    <google-map></google-map>
</div>

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

Решение было простым: при переключении представления снова вызывать fitBounds().

<button (click)="showMap()">Show Map</button>

public showMap() {
    this.view = 'map';
    setTimeout(() => {
        if (typeof this.map !== 'undefined') this.map.fitBounds(this.bounds);
    });
}

Примечание. Я обернул setTimeout вызов fitBounds(), чтобы Angular мог завершить жизненный цикл и отобразить карту до ее вызова.

person Kevin Chung    schedule 05.06.2019
comment
+1 Столкнулся именно с этим сценарием, и это исправление сработало для меня. Я хотел бы отметить, что в моем случае я просто использовал setTimeout и ждал 500 мс, потому что this.map уже был определен на моей странице. Проблема возникала только при выполнении show(), hide(), затем снова show(). Задержки в полсекунды было достаточно, чтобы все на карте перезагрузилось. - person lhan; 18.02.2020
comment
Я использую скрытую карту на сайте Django, и это было проблемой. Я обнаружил, что карта должна быть буквально видна, прежде чем fitBounds() будет работать правильно. Спасибо. - person alstr; 07.08.2020

Я тоже заметил эту проблему. Мое решение состоит в том, чтобы сравнить map.getBounds() с тем, для чего я устанавливаю границы; если они совпадают, я пропускаю вызов map.fitBounds().

person Jon Onstott    schedule 01.11.2012

Я столкнулся с той же проблемой, и ответ @Tomik помог мне ее решить. Вот фрагменты кода, который я использовал.

Чтобы сохранить предыдущий масштаб и центр.

const lastMapZoom = this.map.getZoom();
const lastMapCenter = this.map.getCenter();

Чтобы вернуть значения.

this.map.setCenter(lastMapCenter);
this.map.setZoom(lastMapZoom);
person jkumaranc    schedule 04.02.2019