32

我希望能够在调用 a 后向地图视图添加填充map.fitBounds(),因此无论地图控件或打开时会覆盖标记的滑动面板之类的东西如何,所有标记都可以看到。Leaftlet 可以选择向 fitBounds 添加填充,但谷歌地图没有。

有时,最北端的标记部分隐藏在视口上方。最西端的标记也经常位于缩放滑块下方。使用 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>

问题是这样的:

在此处输入图像描述

我已尝试添加自定义控件中记录的控件,但地图并不完全了解它 - 请参阅从地图自定义控件示例分叉的这个小提琴。其中一个标记仍被控件遮挡。

4

8 回答 8

25

这是某种 hack-ish 解决方案,但在 之后fitBounds,您可以缩小一个级别,这样您就可以为标记获得足够的填充。

假设map变量是您对地图对象的引用;

map.setZoom(map.getZoom() - 1);
于 2012-04-26T19:34:16.687 回答
17

自 2017 年 6 月起,Maps JavaScript API 支持 fitBounds() 方法中的填充参数。

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

请参阅文档以获取更多详细信息

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

于 2017-07-06T08:38:48.327 回答
10

我通过扩展地图边界以包含一个足以将标记推入视野的 latlng 解决了这个问题。

首先你需要创建一个覆盖视图

var overlayHelper = new google.maps.OverlayView();
overlayHelper.onAdd = function() {};
overlayHelper.onRemove = function() {};
overlayHelper.draw = function() {};
overlayHelper.setMap(map);

一旦你有一个叠加助手,你需要获取地图投影并基于它执行计算。

请注意,我在地图上的控件是地图最右侧的一个 420 像素宽、100% 高度的 div。您显然需要更改代码以适应您的控件。

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> });
于 2012-12-29T09:22:42.550 回答
9

您可以使用map.fitBounds()API V3,其填充语法与您提到的map.showBounds().

简单地使用map.fitBounds(bounds, {top:30,right:10,left:50});对我有用。

(这可能是对 xomena 或 Roman86 帖子的评论,我没有足够的声誉来评论)

于 2018-11-30T21:58:42.337 回答
9

更新

Google Maps API 现在支持fitBounds方法中的原生“填充”参数(从版本 3.32 开始,如果更早,请更正我)。

我还没有机会测试它,但如果你能够升级 - 我会建议使用原生方式。如果您使用的是版本 < 3.32 并且无法升级 - 我的解决方案适合您。


我采用了erzzo的工作解决方案并对其进行了一些改进。 例子

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

参数说明:

  1. gMap - 谷歌地图实例
  2. bounds - 谷歌地图 LatLngBounds 对象以适应
  3. paddingXY - 对象文字: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);
        }
    }
于 2017-05-03T13:21:29.047 回答
1

我将为这个问题提供一个更通用的解决方案。如果我们有一个位置 eg 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 为下。所以,在一般情况下,要看到标记,我们需要传递 y 的负值,例如extendedLocation(marker.getPosition(), 4, -18)

如果您在假设 30 px 高度的顶部有一个持久滑块或任何此类元素,只需y在函数中使用参数 as -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
}
于 2016-02-11T07:31:36.240 回答
0

我做的方式看起来很干净。例如,在地图的每一侧使用像素坐标基础应用 10% 的填充。这是 Maps API v3.44:

map.fitBounds(bounds)
let mapDiv = map.getDiv()

let padding = {
  bottom: mapDiv.offsetHeight * 0.1,
  left: mapDiv.offsetWidth * 0.1,
  right: mapDiv.offsetWidth * 0.1,
  top: mapDiv.offsetHeight * 0.1,
}
map.fitBounds(bounds, padding);
于 2021-02-25T20:16:32.703 回答
-1

另一种方法是使用一个额外的 LatLong 点来扩展您的边界,并计算距离。google.maps.LatLngBounds() 对象具有获取边界框的西南和东北点的功能,可用于计算北、南、东或西 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);

在上面的示例中,通过从最西点的经度中减去 0.9 将 LatLong 点添加到边界会使边界向西移动约 52 英里。

一个整点 (pos.lng() - 1.0) 大约为 58 英里,因此在确定需要哪种填充时,您可以猜测一个合适的距离或使用其他方法来计算纵向偏移量。

于 2016-09-22T17:03:43.083 回答