Google Maps v3: 使用fitBounds时强制最小缩放级别

93

我正在使用v3版的地图API在地图上绘制一系列标记。

在v2中,我的代码如下:

  bounds = new GLatLngBounds();

  ... loop thru and put markers on map ...
  bounds.extend(point);
  ... end looping

  map.setCenter(bounds.getCenter());
  var level = map.getBoundsZoomLevel(bounds);
  if ( level == 1 ) 
    level = 5;
  map.setZoom(level > 6 ? 6 : level);

这样做可以确保地图上始终显示适当级别的细节。

我正在尝试在v3中复制此功能,但是setZoom和fitBounds似乎并不合作:

... loop thru and put markers on the map
  var ll = new google.maps.LatLng(p.lat,p.lng);
  bounds.extend(ll);
... end loop

var zoom = map.getZoom();
map.setZoom(zoom > 6 ? 6 : zoom);
map.fitBounds(bounds);

我尝试了不同的排列方式(例如将fitBounds放在setZoom之前),但是我对setZoom所做的任何操作似乎都不会影响地图。我有什么遗漏吗?有没有办法解决这个问题?

9个回答

155

Google Groups上的这个讨论中,我发现当你执行fitBounds时,缩放是异步发生的,因此你需要捕获缩放和边界变化事件。最后一篇帖子中的代码对我有用,只需进行小修改即可……它阻止你完全缩放大于15,因此使用第四篇帖子中的想法设置一个标志,仅在第一次执行时才执行。

// Do other stuff to set up map
var map = new google.maps.Map(mapElement, myOptions);
// This is needed to set the zoom after fitbounds, 
google.maps.event.addListener(map, 'zoom_changed', function() {
    zoomChangeBoundsListener = 
        google.maps.event.addListener(map, 'bounds_changed', function(event) {
            if (this.getZoom() > 15 && this.initialZoom == true) {
                // Change max/min zoom here
                this.setZoom(15);
                this.initialZoom = false;
            }
        google.maps.event.removeListener(zoomChangeBoundsListener);
    });
});
map.initialZoom = true;
map.fitBounds(bounds);

安东尼。

2023年4月更新:

根据下面的评论,使用现代JS和Google Maps API V3,这个块应该看起来像这样:

map = new google.maps.Map(mapElement, myOptions);
map.maxDefaultZoom = 15;

google.maps.event.addListenerOnce(map, "bounds_changed", function () {
  this.setZoom(Math.min(this.getZoom(), this.maxDefaultZoom));
});


4
这是一个很好的方法。另一种方法是检查当前边界并扩展边界,即访问https://dev59.com/bHA75IYBdhLWcg3wW3y8#5345708。虽然这里链接的答案只是将边界扩大了一小部分,但您可以使用相同的方法将边界扩大更多;我发现将所有角落添加7可以做得很好。 - Metro Smurf
2
我想更正我的先前评论。我认为设置initialZoom属性可能是必要的。在代码中省略了这部分后,我在IE 9上缩放到非常接近时遇到了一些问题...很棒的解决方案! - Andrew
28
使用 google.maps.event.addListenerOnce(),这样您就不必手动删除监听器了。 - pstadler
9
因为我已经看了三遍,这是压缩版本。感谢 @pstadler。google.maps.event.addListenerOnce(map, 'bounds_changed', function() { this.setZoom(Math.min(15, this.getZoom())); }); - sba
2
使用 addListenerOnce 时,您可以简单地侦听 zoom_changed。我正在在 map.fitBounds(bounds); 之前使用 zoom_changed,在 Chrome 上运行得非常好。 - Milk Man
显示剩余4条评论

68

没有试过,但我认为你只需要在获取缩放级别之前使用fitBounds()就可以实现,即:

map.fitBounds(bounds);
var zoom = map.getZoom();
map.setZoom(zoom > 6 ? 6 : zoom);
如果您已经尝试过那样做,但它没有起作用,您可以在MapOptions 中使用minZoom设置您的地图。 (api-reference)像这样:
var map = new google.maps.Map(document.getElementById("map"), { minZoom: 6 });

使用fitBounds()时,这会防止地图进一步缩小。


不错的简单而优雅的解决方案! - Falantar014
3
设置minZoom和maxZoom值会限制用户缩放超出这些值,因此如果您只想将初始缩放设置为合理的值(这是我认为OP所说的内容),则设置这些值没有帮助。 - Izazael
6
基本上就是和我在回答中写的一样吗? - Flygenring
@Izazael提出了一个很好的观点,答案中没有涉及到。它非常适用于阻止fitBounds()缩放得太远,但它还限制了用户与地图缩放按钮的交互。如果您希望用户拥有完全控制权,接受的答案是更好的选择。 - Rich Court
我不是很确定我的回答没有涵盖到它,因为我提到了第二种技术:“这将防止地图进一步缩放”。 - Flygenring
1
可能因为新版本而无法正常工作。fitBounds() 是异步工作的! - RubbelDeCatc

22

在调用fitBounds()之前,您还可以设置maxZoom选项,并在之后重置该值:

if(!bounds.isEmpty()) {
    var originalMaxZoom = map.maxZoom;
    map.setOptions({maxZoom: 18});
    map.fitBounds(bounds);
    map.setOptions({maxZoom: originalMaxZoom});
}

我喜欢这个选项,因为它不像其他选项那样会导致“zoom_changed”事件触发两次。 - Greg
当最大对象定义了maxZoom选项时,这是一个很棒的解决方案。 - Alexey Domanski

21

Anthony的解决方案非常好。我只需要为初始页面加载修复缩放(确保您开始时不要缩放得太远),这对我有效了:

var zoomChangeBoundsListener =
    google.maps.event.addListener(map, 'bounds_changed', function(event) {
        google.maps.event.removeListener(zoomChangeBoundsListener);
        map.setZoom( Math.min( 15, map.getZoom() ) );
    });


map.fitBounds( zoomBounds );

7
你可以使用 addListenerOnce 来代替移除监听器,但我选择使用了这个解决方案。 - Derek

11

当您在一个项目上调用map.fitBounds()时,地图可能会缩得太近。要解决此问题,只需将'maxZoom'添加到mapOptions中即可...

var mapOptions = {
  maxZoom: 15
};

8
在我的情况下,我只是想将缩放级别设置为比Google Maps在fitBounds期间选择的级别低一级。 目的是使用fitBounds,但也确保没有标记位于任何地图工具下面等。 我的地图早期创建,然后页面的许多其他动态组件有机会添加标记,在每次添加后调用fitBounds。
这是在最初创建地图对象的初始块中...
var mapZoom = null;

然后将这个内容添加到每个标记所在的块中,在调用map.fitBounds之前...
google.maps.event.addListenerOnce(map, 'bounds_changed', function() { 
    if (mapZoom != map.getZoom()) { 
        mapZoom = (map.getZoom() - 1); 
        map.setZoom(mapZoom); 
    } 
});

使用'bounds_changed'时,如果没有进行检查,则无论是否需要,地图都会因每个标记而缩小一次。相反,当我使用'zoom_changed'时,有时会出现地图工具下面的标记,因为缩放实际上并未发生变化。现在它总是被触发,但是检查确保它只在需要时缩小一次。希望这可以帮到你。

这似乎是唯一一个应该实际使用addListener而不是在每个map.fitBounds()之前重复(并依赖于记住)addListenerOnce的答案。 - Flygenring

3
自从Google Maps V3采用了事件驱动,你可以在zoom_changed事件触发时告诉API将缩放级别设置回适当的大小:
var initial = true
google.maps.event.addListener(map, "zoom_changed", function() {
    if (initial == true){
       if (map.getZoom() > 11) {
         map.setZoom(11);
         initial = false;
       }
    }
}); 

我使用了initial,使得在最终的fitBounds执行时地图不会缩放太多,但是让用户可以自由缩放。如果没有这个条件,用户可以进行任何大于11的缩放操作。


3
我发现以下方法非常有效。这是对Ryan的答案的变体,针对https://dev59.com/bHA75IYBdhLWcg3wW3y8。它保证至少显示一个面积为offset度数两倍的区域。
const center = bounds.getCenter()
const offset = 0.01
const northEast = new google.maps.LatLng(
    center.lat() + offset,
    center.lng() + offset
)
const southWest = new google.maps.LatLng(
    center.lat() - offset,
    center.lng() - offset
)
const minBounds = new google.maps.LatLngBounds(southWest, northEast)
map.fitBounds(bounds.union(minBounds))

0

我刚刚有同样的任务需要解决,使用了一个简单的函数来解决它。

它不关心边界内有多少标记 - 如果有很多标记且缩放已经很远,它会稍微缩小一点,但是当只有一个标记(或者很多非常靠近彼此的标记)时,缩小的幅度就会很大(可以通过extendBy变量进行自定义):

var extendBounds = function() {
  // Extends the Bounds so that the Zoom Level on fitBounds() is a bit farer away
  var extendBy = 0.005;
  var point1 = new google.maps.LatLng(
    bounds.getNorthEast().lat() + extendBy,
    bounds.getNorthEast().lng() + extendBy
  )
  var point2 = new google.maps.LatLng(
    bounds.getSouthWest().lat() - extendBy,
    bounds.getSouthWest().lng() - extendBy
  )
  bounds.extend(point1);
  bounds.extend(point2);
}

为了使用它,我使用自己的函数来执行fitBounds()
map是我的GoogleMap对象

var refreshBounds = function() {
  extendBounds();
  map.fitBounds(bounds);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接