Google Maps API V3 fitbounds() уменьшает масштаб, но никогда не увеличивает

Я создал своего рода довольно сложный локатор магазинов. Пользователь вводит свой почтовый индекс, и таблица возвращает результаты с соответствующими маркерами на карте. Они могут листать результаты, и маркеры перемещаются все дальше и дальше, а функция fitbounds() отлично работает для уменьшения масштаба до соответствующего уровня масштабирования, чтобы соответствовать маркерам. Проблема в том, что если вы пролистываете страницу назад к более близким местам, fitbounds() не увеличивается. Даже если вы вводите новый поиск, он не увеличивает масштаб вокруг этих новых маркеров — он центрируется над ними, но остается на том уровне масштабирования, который был. в ранее. Я надеюсь в этом есть смысл. Если кто-нибудь знает, что мне нужно добавить, чтобы увеличить масштаб более близких результатов, пожалуйста, помогите. Это функции Google, которые я вызываю в конце моей функции нажатия маркера:

  map.setCenter(bounds.getCenter());
  map.panToBounds(bounds);
  map.fitBounds(bounds);

Спасибо!


person abemonkey    schedule 15.07.2010    source источник


Ответы (12)


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

map.fitBounds(bounds);
map.panToBounds(bounds);
person Doug    schedule 06.09.2011
comment
Кажется, это работает. Интересно, что panToBounds должен делать без fitBounds. - person dbkaplun; 12.08.2012

Проблема в следующем: мы устанавливаем

var bounds = new google.maps.LatLngBounds();

чтобы позже мы могли подогнать наши маркеры к ограниченной области на карте. GMaps всегда будет уменьшать масштаб асинхронно с fitBounds() соответственно, но не будет увеличивать масштаб для достижения того же (как ранее отмечалось @broady). Это не идеально для многих приложений, так как после того, как вы перешли и отобразили ряд маркеров на карте, которые привели к уменьшению масштаба карты (возможно, ‹10), он не вернется к масштабу, если пользователь не сделает это вручную.

GMaps будет продолжать использовать границы (недостаток лучших слов) самого уменьшенного статуса коллекции маркеров (извините). Установка значения «null» перед каждым вызовом новых маркеров дает вам новую карту для работы.

Для автоматического увеличения просто установите LatLngBounds(); в 'null' вот так (см. псевдопример ниже, чтобы увидеть его размещение):

bounds = new google.maps.LatLngBounds(null);

Псевдопример:

// map stuff/initiation
...

var bounds = new google.maps.LatLngBounds();
var gmarkers = [];

function CreateMarker (obj) {
    myLatLng = new google.maps.LatLng(obj['latitude'], obj['longitude']);
    marker = new google.maps.Marker({
        position: myLatLng,
        map: map
    });
    google.maps.event.addListener(marker, 'click', (function(marker, i) {
        return function() {
            infowindow.setContent(obj['job']);
            infowindow.open(map, marker);
        }
    })(marker, i));
    bounds.extend(myLatLng);
    gmarkers.push(marker);
}

....

// here's an AJAX method I use to grab marker coords from a database:

$.ajax({
    beforeSend: function() {
        clear_markers(gmarkers); // see below for clear_markers() function declaration
    },
    cache: false,
    data: params,
    dataType: 'json',
    timeout: 0,
    type: 'POST',
    url: '/map/get_markers.php?_=<?php echo md5(session_id() . time() . mt_rand(1,9999)); ?>',
    success: function(data) {
        if (data) {
            if (data['count'] > 0) {
                var obj;
                var results = data['results'];

                // Plot the markers
                for (r in results) {
                    if (r < (data['count'])) {
                        CreateMarker(results[r]);
                    }
                }
            }
        }
    },
    complete: function() {
        map.fitBounds(bounds);
    }
});

// clear_markers()
function clear_markers(a) {
    if (a) {
        for (i in a) {
            a[i].setMap(null);
        }
        a.length = 0;
    }
    bounds = new google.maps.LatLngBounds(null); // this is where the magic happens; setting LatLngBounds to null resets the current bounds and allows the new call for zoom in/out to be made directly against the latest markers to be plotted on the map
}
person John Smith    schedule 24.04.2012
comment
Спасибо, Джон Смит! Ваше предложение было единственным способом, которым я смог увеличить масштаб после удаления маркера. Я ценю детали в вашем посте. - person gorelog; 16.08.2012

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

Вы можете сначала вызвать setZoom(20), а затем fitBounds.

person Chris Broadfoot    schedule 11.10.2010
comment
Для тех, кто читает это позже, fitBounds выполняет Zoom с текущими версиями, а panToBounds — нет, и соответствует тому, что описано выше. - person Camro; 25.06.2021

Хм, интересно .. Я использую PHP для перебора всех (будущих) координат маркеров и вычисления значений юго-запада и северо-востока; координаты происхождения находятся на полпути между ними. Если все координаты маркеров очень близки друг к другу, коэффициент масштабирования, установленный fitBounds, намного выше (при увеличении), чем 15, использованный при создании карты. Вот почему я добавил последнюю строку.

var map;

function mapInit() {
  var origin = new google.maps.LatLng(59.33344615, 18.0678188);
  var options = {
    zoom: 15,
    center: origin,
    mapTypeControlOptions: {
      mapTypeIds: [google.maps.MapTypeId.ROADMAP, google.maps.MapTypeId.HYBRID]
    },
    mapTypeId: google.maps.MapTypeId.ROADMAP
  };

  map = new google.maps.Map(document.getElementById("googlemap"), options);

  var southWest = new google.maps.LatLng(59.3308415, 18.0643054);
  var northEast = new google.maps.LatLng(59.3360508, 18.0713322);
  var bounds = new google.maps.LatLngBounds(southWest, northEast);
  map.fitBounds(bounds);

  google.maps.event.addListenerOnce(map, "idle", function() {
    if (map.getZoom() > 16) map.setZoom(16);
  });

Итак, либо Google перепрограммировал функцию с тех пор, как вы разместили вопрос, либо... Мне нужно больше информации о вашем коде.

person LGT    schedule 04.11.2010
comment
спасибо, только эта вещь сработала для меня, перепробовал много решений, немного измененных с моими требованиями google.maps.event.addListenerOnce(map, idle, function() { if (map.getZoom() ‹ parseInt(getParameterByName(zoomlevel))) map.setZoom (parseInt(getParameterByName(уровень масштабирования))); }); - person Darkcoder; 03.06.2019

Что мне помогло, так это использование 0 padding в качестве второго параметра для fitBounds(bounds, padding), вот полный пример кода:

function initMap() {
    var mapOptions = {
        center: new google.maps.LatLng(0, 0),
        zoom: 1,
        minZoom: 1
    };
    map = new google.maps.Map(document.getElementById('officeMap'), mapOptions);
    google.maps.event.addListenerOnce(map, 'idle', function() {
        //Map is ready
        worldViewFit(map);
    });
}
function worldViewFit(mapObj) {
    var worldBounds = new google.maps.LatLngBounds(
        new google.maps.LatLng(70.4043,-143.5291),  //Top-left
        new google.maps.LatLng(-46.11251, 163.4288)  //Bottom-right
    );
    mapObj.fitBounds(worldBounds, 0);
    var actualBounds = mapObj.getBounds();
    if(actualBounds.getSouthWest().lng() == -180 && actualBounds.getNorthEast().lng() == 180) {
        mapObj.setZoom(mapObj.getZoom()+1);
    }
}
person Tom G    schedule 10.07.2018
comment
Потратив день на поиск и отладку, этот ответ стал решением. Спасибо, Том. - person Kayote; 24.04.2020

У меня также была проблема с масштабированием карты при повторном вызове fitBounds на той же карте с новыми маркерами. Это франкенрешение, которое работает для меня:

// This is a stationary point tho dynamic will work too

var myLat = someLat,
    myLng = someLong;

var map = false,
    markersArray = [];

function makeOrderMap(lat, lng) { // pass in dynamic point when updating map

  var mapOptions = {
      center: new google.maps.LatLng(myLat, myLng),
      zoom: 16,
      mapTypeId: google.maps.MapTypeId.ROADMAP
  };
  deleteOverlays(); // remove any existing markers..
  if(!map) {  
    map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
  } 

  // Find the mid-point to center the map

  midLat = (parseFloat(lat) + parseFloat(myLat)) / 2;
  midLng = (parseFloat(lng) + parseFloat(myLng)) / 2;
  map.setCenter(new google.maps.LatLng(midLat, midLng));
  var newSpot = new google.maps.LatLng(lat, lng); 

  placeMarker(mapOptions.center);    
  placeMarker(newSpot);   

  // determine the distance between points for deciding the zoom level

  var dist = distHaversine(mapOptions.center, newSpot);

  var zoom = 10;
  if(dist < 1.25) {
    zoom = 15;
  } else if(dist < 2.5) {
    zoom = 14;
  } else if(dist < 5) {
    zoom = 13;
  } else if(dist < 10) {
    zoom = 12;
  } else if(dist < 20) {
    zoom = 11;
  }
  map.setZoom(zoom);  
}


rad = function(x) {return x*Math.PI/180;}

distHaversine = function(p1, p2) {
  var R = 6371; // earth's mean radius in km
  var dLat  = rad(p2.lat() - p1.lat());
  var dLong = rad(p2.lng() - p1.lng());

  var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
          Math.cos(rad(p1.lat())) * Math.cos(rad(p2.lat())) * Math.sin(dLong/2) * Math.sin(dLong/2);
  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
  var d = R * c;

  return d.toFixed(3);
}

function deleteOverlays() {
    if (markersArray) {
        for (i in markersArray) {
            markersArray[i].setMap(null);
        }
    markersArray = [];    
    markersArray.length = 0;
    }    
}

function placeMarker(location, alt_icon) {

    var marker = new google.maps.Marker({
        position: location, 
        map: map
      });

    // add marker in markers array
    markersArray.push(marker);
}
person Ryan Charmley    schedule 11.10.2013
comment
Спасибо, у вас получилось реализовать его как угловой сервис: gist.github.com/zmijevik/047c40f4fc0bea27fd7c - person Joseph Persie III; 08.03.2016

Оказывается, когда вы вызываете map.getBounds(), он возвращает область просмотра с небольшим запасом по краям. Поскольку эти новые границы больше текущих границ, масштаб карты всегда будет уменьшаться. Я смог решить эту проблему, полностью избегая использования границ текущей карты и поддерживая отдельную переменную LatLngBounds. Каждый раз, когда я добавлял точку, я звонил:

markersBounds.extend(newMarkersLatLng);
map.fitBounds(markersBounds);
map.panToBounds(markersBounds);

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

var markersBounds = new google.maps.LatLngBounds(markers[0].getPosition(),
                                                 markers[0].getPosition());
for(var i=1; i<markers.length; i++){
    markersBounds.extend(markers[i].getPosition());
}

map.fitBounds(markersBounds);
map.panToBounds(markersBounds);
person charltoons    schedule 12.04.2013

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

(здесь используется модуль массива Dojo, просто удобная оболочка для базовой итерации массива)

var origBounds = map.getBounds(),
    newBounds = new google.maps.LatLngBounds(null),
    anyFailed = false;
array.forEach(markers, function (m) {
    newBounds.extend(m.position);
    if (!origBounds.contains(m.position)) {
        anyFailed = true;
    }
});
if (anyFailed) {
    map.setCenter(newBounds.getCenter());
    map.fitBounds(newBounds);
}

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

person Neek    schedule 06.01.2014

Проверьте эту цитату из документов GMap на marker.setMap(null); (которая используется для удаления маркеров с карты):

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

Моя проблема заключалась в том, что когда я удалял маркеры с карты, они все еще хранились в map.markers. Поэтому при установке bounds он также захватывает все предыдущие маркеры:

map.markers.forEach( (marker) => {
  var latlng = new google.maps.LatLng(marker.position.lat(), marker.position.lng())
  bounds.extend(latlng)
})

Console.logging bounds показал, что из-за этого границы всегда будут соответствовать всем предыдущим границам.

Мое решение состояло в том, чтобы отслеживать маркеры в отдельном массиве/объекте markers, в котором хранится уникальный ключ для каждого маркера (в моем случае связанный с полем ввода автозаполнения мест) и удалять из него маркер при удалении маркера с карты. Таким образом, я могу запустить проверку при создании bounds, чтобы увидеть, находится ли текущий маркер в map.markers в (актуальном) массиве markers.

map.markers.forEach( (marker) => {
  // check if map marker is in this.markers (to make sure only current)
  for (const [key, value] of Object.entries(markers)) {
    if (marker == value) {
      var latlng = new google.maps.LatLng(marker.position.lat(), marker.position.lng())
      bounds.extend(latlng)
    }
  }
})

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

Ренс

person Rens    schedule 22.10.2020

map.setZoom(10);

Я считаю приемлемым диапазоном 1-20. Только целые числа, десятичные дроби по моему опыту сломали карту.

person Greg W    schedule 15.07.2010

fitBounds: function(bounds, mapId)
    {
        //bounds: bounds, id: map id
        if (bounds==null) return false;
        maps[mapId].fitBounds(bounds);
    },  

Это должно помочь, я использую этот метод и работает нормально, на карте v2 немного по-другому.

person localtime    schedule 13.03.2011

Убедитесь, что по ширине или высоте вашей карты нет CSS-анимации. Анимации мешают поведению масштабирования fitBound()

Вчера я потратил большую часть дня на эту проблему и столкнулся с этим сообщением StackOverflow не менее дюжины раз. Но в конце концов мне пришлось найти проблему самостоятельно.

Удаление строки transition: all 0.5s ease; ниже исправило это для меня.

.google-map {
  width: 100%;
  height: 0px;
  transition: all 0.5s ease;
}

.google-map.loaded {
    height: 400px;
}

person Mike Olund    schedule 23.01.2020