it-swarm.com.ru

Google Maps API 3 fitBounds padding - убедитесь, что маркеры не скрыты наложенными элементами управления

Я хотел бы иметь возможность добавлять отступы к представлению карты после вызова map.fitBounds() , чтобы все маркеры могли быть видны независимо от элементов управления картой или таких вещей, как скользящие панели, которые закрывали бы маркеры при открытии. В Leaftlet есть опция для добавления отступов в fitBounds , а в Google Maps - нет.

Иногда самые северные маркеры частично скрываются над окном просмотра. Самые западные маркеры также часто лежат под ползунком масштабирования. С помощью API 2 можно было сформировать виртуальный видовой экран, уменьшив заданные отступы из видового экрана карты, а затем вызвать метод 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>

Проблема заключается в следующем:

 enter image description here

Я попытался добавить элемент управления, как описано в Пользовательские элементы управления , но карта точно не знает об этом - см. эту скрипку разветвлено в примере Пользовательский элемент управления Maps . Один из маркеров все еще скрыт контролем.

25
jsurf

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

Предположим, переменная map является вашей ссылкой на объект карты;

map.setZoom(map.getZoom() - 1);
23
keune

По состоянию на июнь 2017 года JavaScript API Карт поддерживает параметр padding в методе fitBounds ().

fitBounds(bounds:LatLngBounds|LatLngBoundsLiteral, padding?:number)

Пожалуйста, обратитесь к документации для получения более подробной информации

https://developers.google.com/maps/documentation/javascript/reference#Map

11
xomena

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

Во-первых, вам нужно создать вид наложения

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> });
10
Seain Malkin

Обновленный

API Карт Google теперь поддерживает собственный параметр "padding" в методе fitBounds (с версии 3.32, исправьте меня, если раньше).

У меня еще не было возможности протестировать его, но если вы сможете обновить - я бы порекомендовал использовать нативный способ. Если вы используете версию <3.32 и не можете выполнить обновление - мое решение для вас.


Я взял рабочее решение by erzzo и немного его улучшил .
Пример

fitBoundsWithPadding(googleMapInstance, PolygonLatLngBounds, {left:250, bottom:10});

Описание аргументов:

  1. gMap - экземпляр карты Google
  2. bounds - Google отображает объект LatLngBounds, чтобы соответствовать
  3. paddingXY - Object Literal: 2 возможных формата:
    • {x, y} - для горизонтального и вертикального заполнения (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);
        }
    }
8
Roman86

Вы можете использовать map.fitBounds() с API V3 с тем же синтаксисом заполнения, который вы упомянули в map.showBounds()

Просто использование map.fitBounds(bounds, {top:30,right:10,left:50}); сработало для меня. 

(это может быть комментарий к посту xomena или Roman86 ', у меня недостаточно репутации, чтобы комментировать)

4
Milan Švehla

Я предоставлю более общее решение для этой проблемы . Если у нас есть позиция, например, 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)
}

Примечание: положительный х в правильном направлении и положительный у в направлении вниз. Таким образом, в общем случае, чтобы увидеть маркер, нам нужно передать отрицательное значение y, например. extendedLocation(marker.getPosition(), 4, -18)

Если у вас есть постоянный ползунок или любой такой элемент в верхней части, предположительно, высотой 30 пикселей, просто используйте параметр 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
}
1
Gaurav Mukherjee