Fitbounds API Google Maps V3 () уменьшает, но никогда не
Я создал довольно сложный локатор магазинов. Пользователь вводит свой почтовый индекс, и таблица возвращает результаты с соответствующими маркерами на карте. Они могут пролистывать результаты, а маркеры двигаться дальше и дальше, а fitbounds()
Функция отлично работает для уменьшения масштаба до соответствующего уровня масштабирования, чтобы соответствовать маркерам. Проблема в том, что если вы вернетесь к более близким fitbounds()
не увеличивает масштаб. Даже если вы вводите новый поиск, он не приближается к этим новым маркерам - он центрируется над ними, но остается на том же уровне масштабирования, на котором он находился ранее. Я надеюсь это имеет смысл. Если кто-нибудь знает, что мне нужно добавить, чтобы увеличить приблизительные результаты, помогите. Это функции Google, которые я вызываю в конце своей функции нажатия маркеров:
map.setCenter(bounds.getCenter());
map.panToBounds(bounds);
map.fitBounds(bounds);
Спасибо!
10 ответов
Проблема заключается в следующем: мы устанавливаем
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
}
Ничего особенного здесь не нужно. Сначала подгоните границы, затем передвиньте к нему. Это даст вам правильный масштаб и содержит все границы.
map.fitBounds(bounds);
map.panToBounds(bounds);
Вот так, fitBounds
только гарантирует, что указанные границы видны. Это не увеличивает масштаб до соответствующего уровня.
Вы могли бы сначала позвонить setZoom(20)
, тогда fitBounds.
Хм, интересно.. Я использую PHP, чтобы пройти через все (чтобы быть) координаты маркера и вычислить значения southWest и northEast; координаты происхождения находятся на полпути между ними. Если все координаты маркера очень близки друг к другу, коэффициент масштабирования, установленный 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 перепрограммировал функцию с тех пор, как вы опубликовали вопрос, либо... Мне нужна дополнительная информация о вашем коде.
Что мне помогло, так это использование 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);
}
}
У меня также была проблема с уменьшением масштаба карты при повторном вызове 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);
}
Оказывается, когда вы звоните 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);
Проверьте эту цитату из документации 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)
}
}
})
Теперь моя карта правильно масштабируется после смены маркеров. Если кто-то может придумать какие-либо улучшения к вышеуказанному методу, я хотел бы это услышать!
Rens
Я столкнулся с этой общей проблемой сегодня, думал, что поделюсь решением. Я понимаю, что это немного отличается от вашей проблемы с "магазинным локатором", но применимо во многих отношениях. В моем случае у меня есть коллекция маркеров на карте, и я добавляю один, и хочу убедиться, что все маркеры теперь видны. Этот код проверяет каждый существующий маркер, чтобы увидеть, находится ли он в представлении, и в процессе строит новый ограничивающий прямоугольник, который будет содержать их все, если потребуется. В конце, если было обнаружено, что что-то не видно, представление сбрасывается, поэтому все они.
(здесь используется модуль массива 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);
}
Можно легко изменить это, чтобы только убедиться, что новый маркер находится в поле зрения, не зацикливаясь и просто выполняя проверку содержит () на новом маркере.
fitBounds: function(bounds, mapId)
{
//bounds: bounds, id: map id
if (bounds==null) return false;
maps[mapId].fitBounds(bounds);
},
Это должно помочь, я использую этот метод и работает нормально, на карте v2 немного по-другому.
map.setZoom(10);
Я считаю, что приемлемый диапазон составляет 1-20. Только целые числа, десятичные дроби сломали карту в моем опыте.
Убедитесь, что на вашей карте нет CSS-анимации по ширине или высоте. Анимации мешают масштабированию fitBound()
Вчера я потратил большую часть дня на решение этой проблемы и встречал этот пост на Stackru по крайней мере десяток раз. Но в конце концов мне пришлось самостоятельно найти проблему.
Удаление transition: all 0.5s ease;
строка ниже исправила это для меня.
.google-map {
width: 100%;
height: 0px;
transition: all 0.5s ease;
}
.google-map.loaded {
height: 400px;
}