Приложение Google Maps API 3 fitBounds - убедитесь, что маркеры не скрыты с помощью наложенных элементов управления
Я хотел бы, чтобы добавить дополнение к виду карты после вызова map.fitBounds()
, поэтому все маркеры могут быть видны независимо от элементов управления картой или вещей, таких как скользящие панели, которые будут закрывать маркеры при открытии. У Leaftlet есть возможность добавить дополнение к fitBounds, но Google Maps этого не делает.
Иногда северные маркеры частично скрываются над окном просмотра. Самые западные маркеры также часто лежат под ползунком масштабирования. С API 2 можно было создать виртуальный видовой экран, уменьшив данные прокладки из showBounds()
просмотра карты, а затем вызовите метод showBounds()
для вычисления и выполнения масштабирования и центрирования на основе этого виртуального видового экрана:
map.showBounds(bounds, {top:30,right:10,left:50});
Рабочий пример этого для API 2 можно найти здесь по ссылке showBounds().
Я не могу найти аналогичную функциональность в API V3, но, надеюсь, есть еще один способ, которым это может быть достигнуто. Может быть, я мог бы захватить северо-восточные и юго-западные точки, а затем добавить поддельные координаты, чтобы расширить границы дальше после их включения?
ОБНОВИТЬ
(Codepen, если код ниже не работает)
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
draggable: true,
streetViewControl: false,
zoomControl: false
});
var marker1 = new google.maps.Marker({
position: {lat: 37, lng: -121},
map: map,
});
var marker2 = new google.maps.Marker({
position: {lat: 39.3, lng: -122},
map: map,
});
var bounds = new google.maps.LatLngBounds();
bounds.extend(marker1.position);
bounds.extend(marker2.position);
map.fitBounds(bounds);
}
#map {
height: 640px;
width: 360px;
}
#overlays {
position: absolute;
height: 50px;
width: 340px;
background: white;
margin: -80px 10px;
text-align: center;
line-height: 50px;
}
/* Optional: Makes the sample page fill the window. */
html, body {
height: 100%;
margin: 0;
padding: 0;
}
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<title>Simple markers</title>
</head>
<body>
<div id="map"></div>
<div id="overlays">Controls / Order pizza / ETA / etc.</div>
<script async defer
src="https://maps.googleapis.com/maps/api/js?&callback=initMap">
</script>
</body>
</html>
Ответы
Ответ 1
Это какое-то хак-иш-решение, но после fitBounds
вы можете увеличить один уровень, так что вы получите достаточное количество отступов для своих маркеров.
Предположим, что переменная map
- это ваша ссылка на объект карты;
map.setZoom(map.getZoom() - 1);
Ответ 2
Я решил эту проблему, расширив границы карты, включив в нее latlng, которые достаточно продвинули маркеры.
Во-первых, вам нужно создать представление оверлея
var overlayHelper = new google.maps.OverlayView();
overlayHelper.onAdd = function() {};
overlayHelper.onRemove = function() {};
overlayHelper.draw = function() {};
overlayHelper.setMap(map);
Как только у вас есть помощник наложения, вам нужно получить проекцию карты и выполнить вычисления на основе этого.
Обратите внимание, что элемент управления, который у меня есть на моей карте, представляет собой развертку шириной 420 пикселей, 100% высоты в крайнем правом углу карты. Очевидно, вам нужно будет изменить код для размещения ваших элементов управления.
var mapCanvas = $("#map_canvas"),
controlLeft = mapCanvas.width() - 420, // canvas width minus width of the overlayed control
projection = overlayHelper.getProjection(),
widestPoint = 0,
latlng,
point;
// the markers were created elsewhere and already extended the bounds on creation
map.fitBounds(mapBounds);
// check if any markers are hidden behind the overlayed control
for (var m in markers) {
point = projection.fromLatLngToContainerPixel(markers[m].getPosition());
if (point.x > controlLeft && point.x > widestPoint) {
widestPoint = point.x;
}
}
if (widestPoint > 0) {
point = new google.maps.Point(
mapCanvas.width() + (widestPoint - controlLeft),
mapCanvas.height() / 2); // middle of map height, since we only want to reposition bounds to the left and not up and down
latlng = projection.fromContainerPixelToLatLng(point);
mapBounds.extend(latlng);
map.fitBounds(mapBounds);
}
Если вы делаете это, когда карта загружается в первый раз, вам нужно будет обернуть это в событие карты, чтобы дождаться простоя. Это позволяет инициализировать представление оверлея. Не включайте создание вспомогательного помощника в обратном вызове события.
google.maps.event.addListenerOnce(map, 'idle', function() { <above code> });
Ответ 3
По состоянию на июнь 2017 года API JavaScript Maps поддерживает параметр дополнения в методе fitBounds().
fitBounds(bounds:LatLngBounds|LatLngBoundsLiteral, padding?:number)
Подробнее см. в документации
https://developers.google.com/maps/documentation/javascript/reference#Map
Ответ 4
обновленный
API Карт Google теперь поддерживает собственный параметр "padding" в методе fitBounds (из версии 3.32, исправьте меня, если раньше).
У меня не было возможности проверить его, но если вы сможете обновить - я бы рекомендовал использовать родной путь. Если вы используете версию <3.32 и не можете обновить - мое решение для вас.
Я принял рабочее решение от erzzo и немного улучшил его.
пример
fitBoundsWithPadding(googleMapInstance, PolygonLatLngBounds, {left:250, bottom:10});
Описание аргументов:
- gMap - экземпляр карты Google
- bounds - google maps Объект LatLngBounds для соответствия
- paddingXY - Object Literal: 2 возможных формата:
- {x, y} - для горизонтальных и вертикальных paddings (x = left = right, y = top = bottom)
- {слева, справа, сверху, снизу}
список функций для копирования
function fitBoundsWithPadding(gMap, bounds, paddingXY) {
var projection = gMap.getProjection();
if (projection) {
if (!$.isPlainObject(paddingXY))
paddingXY = {x: 0, y: 0};
var paddings = {
top: 0,
right: 0,
bottom: 0,
left: 0
};
if (paddingXY.left){
paddings.left = paddingXY.left;
} else if (paddingXY.x) {
paddings.left = paddingXY.x;
paddings.right = paddingXY.x;
}
if (paddingXY.right){
paddings.right = paddingXY.right;
}
if (paddingXY.top){
paddings.top = paddingXY.top;
} else if (paddingXY.y) {
paddings.top = paddingXY.y;
paddings.bottom = paddingXY.y;
}
if (paddingXY.bottom){
paddings.bottom = paddingXY.bottom;
}
// copying the bounds object, since we will extend it
bounds = new google.maps.LatLngBounds(bounds.getSouthWest(), bounds.getNorthEast());
// SW
var point1 = projection.fromLatLngToPoint(bounds.getSouthWest());
// we must call fitBounds 2 times - first is necessary to set up a projection with initial (actual) bounds
// and then calculate new bounds by adding our pixel-sized paddings to the resulting viewport
gMap.fitBounds(bounds);
var point2 = new google.maps.Point(
( (typeof(paddings.left) == 'number' ? paddings.left : 0) / Math.pow(2, gMap.getZoom()) ) || 0,
( (typeof(paddings.bottom) == 'number' ? paddings.bottom : 0) / Math.pow(2, gMap.getZoom()) ) || 0
);
var newPoint = projection.fromPointToLatLng(new google.maps.Point(
point1.x - point2.x,
point1.y + point2.y
));
bounds.extend(newPoint);
// NE
point1 = projection.fromLatLngToPoint(bounds.getNorthEast());
point2 = new google.maps.Point(
( (typeof(paddings.right) == 'number' ? paddings.right : 0) / Math.pow(2, gMap.getZoom()) ) || 0,
( (typeof(paddings.top) == 'number' ? paddings.top : 0) / Math.pow(2, gMap.getZoom()) ) || 0
);
newPoint = projection.fromPointToLatLng(new google.maps.Point(
point1.x + point2.x,
point1.y - point2.y
));
bounds.extend(newPoint);
gMap.fitBounds(bounds);
}
}
Ответ 5
Я предоставлю более общее решение для этой проблемы.
Если у нас есть позиция, например. marker.getPosition()
, мы можем найти другую позицию (x, y)
от него, используя эту функцию.
function extendedLocation(position, x, y) {
var projection = map.getProjection();
var newMarkerX = projection.fromLatLngToPoint(position).x + x/(Math.pow(2, map.getZoom()))
var newMarkerY = projection.fromLatLngToPoint(position).y + y/(Math.pow(2, map.getZoom()))
var newMarkerPoint = new google.maps.Point(newMarkerX, newMarkerY);
return projection.fromPointToLatLng(newMarkerPoint)
}
Примечание: положительное x находится в правильном направлении, а положительное y - в нисходящем направлении. Итак, в общем случае, чтобы показать маркер, нам нужно передать отрицательное значение y, например. extendedLocation(marker.getPosition(), 4, -18)
Если у вас есть постоянный слайдер или любой такой элемент в верхней части, предположим, высота 30 px, просто используйте параметр y
в функции как -30
.
Может быть создана более обобщенная функция, которая возвращает массив из 4 точек, каждый (x, y)
пикселей от заданного направления вверх, вниз, вправо и влево.
function getAllExtendedPosition(position, x, y){
var positionArray = [];
postitionArray.push(extendedLocation(position, x, y);
postitionArray.push(extendedLocation(position, -x, -y);
postitionArray.push(extendedLocation(position, -x, y);
postitionArray.push(extendedLocation(position, x, -y);
return positionArray
}
Ответ 6
Вы можете использовать map.fitBounds()
с API V3 с тем же синтаксисом дополнения, который вы упомянули с помощью map.showBounds()
.
Просто используйте map.fitBounds(bounds, {top:30,right:10,left:50});
работал на меня.
(это может быть комментарий к xomena или Roman86 'post, у меня недостаточно репутации для комментариев)
Ответ 7
Другой способ сделать это - расширить границы с помощью дополнительной точки LatLong на расчетном расстоянии. Объект google.maps.LatLngBounds() имеет функции для получения точек SouthWest и NorthEast ограничивающего прямоугольника, которые могут быть использованы для вычисления расстояния X миль на север, юг, восток или запад.
Например, если вы пытались подтолкнуть маркеры вправо для учета элементов наложения в левой части карты, вы можете попробовать следующее:
// create your LatLngBounds object, like you're already probably doing
var bounds = new google.maps.LatLngBounds();
// for each marker call bounds.extend(pos) to extend the base boundaries
// once your loop is complete
// *** add a calculated LatLng point to the west of your boundary ***
bounds.extend(new google.maps.LatLng(bounds.getSouthWest().lat(), bounds.getSouthWest().lng() - .9));
// finally, center your map on the modified boundaries
map.fitBounds(bounds);
В приведенном выше примере добавление точки LatLong к границам путем вычитания .9 из долготы самой западной точки перемещает границу примерно в 52 милях дальше на запад.
Целая точка (pos.lng() - 1.0) составляет около 58 миль, поэтому вы можете либо угадать хорошее расстояние, либо использовать какой-либо другой метод для вычисления этого продольного смещения при определении того, какой тип прокладки вам нужен.