Google Maps API v3:是否可以在fitBounds之后设置zoom?


201

我想在嵌入式Google地图(API v3)上绘制一组点。我希望边界能够容纳所有点,除非缩放级别太低(即,缩小得太多)。我的方法是这样的:

var bounds = new google.maps.LatLngBounds();

// extend bounds with each point

gmap.fitBounds(bounds); 
gmap.setZoom( Math.max(6, gmap.getZoom()) );

这行不通。如果直接在fitBounds之后调用,最后一行“ gmap.setZoom()”不会更改地图的缩放级别。

有没有一种方法可以在不将其应用于地图的情况下获得边界的缩放级别?还有其他解决办法吗?


1
参见stackoverflow.com/questions/4523023/using-setzoom-after-using-fitbounds-with-google-maps-api-v3
Mawg说恢复Monica 2014年

Answers:


337

编辑:请参阅下面的马特·戴蒙德(Matt Diamond)评论。

得到它了!试试这个:

map.fitBounds(bounds);
var listener = google.maps.event.addListener(map, "idle", function() { 
  if (map.getZoom() > 16) map.setZoom(16); 
  google.maps.event.removeListener(listener); 
});

根据您的需求进行修改。


76
很棒的解决方案,完全免除了我的麻烦。只是想补充一点,您可以使用addListenerOnce方法来进一步简化它……那样,您不必保存侦听器并手动将其删除,因为该方法将为您解决。
马特·戴蒙德

9
这具有看到地图“跳过”的行为。而是监听“ zoom_change”事件,并在调用fitBounds()之前进行设置。请在下面查看我的答案
本杰明·萨斯曼2012年

谢谢!google.maps.event.addListenerOnce(地图, “闲”,功能(){} - >我的地图包,SugarCRM的伟大的工作。
jjwdesign

监听器不会为我触发。我在document.ready和window.load中尝试过。有任何想法吗?地图对象可以,并尝试使用addListener:`var map = $(“#js-main-map-canvas”); var listener = google.maps.event.addListenerOnce(map,“ idle”,function(){alert('hello');});`
Henrik Erlandsson 2014年

Henrik,尝试$(“#js-main-map-canvas”)[0]或$(“#js-main-map-canvas”)。get(0);
拉斐尔

68

我在其中一个应用程序中解决了类似的问题。您对问题的描述让我有些困惑,但是我认为您的目标与我相同。

在我的应用中,我想绘制一个或多个标记,并确保地图将其全部显示。问题是,如果我仅依靠fitBounds方法,那么在只有一个点的情况下,缩放级别将达到最大值-这是不好的。

解决方案是在有很多点时使用fitBounds,在只有一个点时使用setCenter + setZoom。

if (pointCount > 1) {
  map.fitBounds(mapBounds);
}
else if (pointCount == 1) {
  map.setCenter(mapBounds.getCenter());
  map.setZoom(14);
}

5
您的答案已解决了我对Google Maps V3的问题。谢谢!
FR6

1
我遇到了完全相同的问题,您的解决方案成功了!谢谢!
manubkk 2011年

我自己尝试了相同的方法,但是它没有用,因为在设置缩放比例之前我没有调用setCenter()...我仍然想知道为什么需要此步骤,但是无论如何现在它都可以工作...谢谢吉姆!
daveoncode

地图中心解决了我遇到的问题!一位不错的+1
Piotr Kula,

1
感谢您的良好回答+1
Bharat Chodvadiya

44

我已经多次访问此页面以获得答案,尽管所有现有答案都非常有帮助,但它们并不能完全解决我的问题。

google.maps.event.addListenerOnce(googleMap, 'zoom_changed', function() {
    var oldZoom = googleMap.getZoom();
    googleMap.setZoom(oldZoom - 1); //Or whatever
});

基本上,我发现'zoom_changed'事件阻止了地图的UI“跳过”,这是在我等待“ idle”事件时发生的。

希望这对某人有帮助!


4
太好了,我也有“跳过/自动缩放”的行为。就像其他读者的注释一样:确保像本杰明一样使用“ addListenerOnce”而不是“ addListener”,否则请弄乱为什么浏览器一直崩溃;-)
Geert-Jan

6
另请注意,fitBounds()如果使用zoom_changed
gapple,

1
谢谢你,似乎v4应该有一个fitBounds(bounds,minZoomLevel):)
理查德(Richard

3
本杰明,我认为最好使用bounds_changed,因为zoom_changedfitBounds保持缩放级别的情况下不必触发。我的尝试jsfiddle.net/rHeMp/10不能证实这一点,但不应依赖未定义的行为。
TMS

10

我已经通过预先设置maxZoom,然后再将其删除来解决此问题。例如:

map.setOptions({ maxZoom: 15 });
map.fitBounds(bounds);
map.setOptions({ maxZoom: null });

迄今为止最好的解决方案,可以防止放大过多。简单直观。没有绘制和重新绘制地图。
user2605793 2014年

这确实是迄今为止最好的解决方法。
Downhillski

2
我发现,如果在调用fitBounds之后立即重置maxZoom,这将不起作用,因为缩放是异步发生的(因此maxZoom在放大时会恢复为null)。等待,直到“空闲”重置它会解决此问题,尽管我猜。
user987356 '02

4

如果我没记错的话,我假设您希望所有点在地图上以尽可能高的缩放级别显示。我通过将地图的缩放级别初始化为16来实现此目的(不确定是否是V3上的最高缩放级别)。

var map = new google.maps.Map(document.getElementById('map_canvas'), {
  zoom: 16,
  center: marker_point,
  mapTypeId: google.maps.MapTypeId.ROADMAP
});

然后在那之后我做了边界的事情:

var bounds = new google.maps.LatLngBounds();

// You can have a loop here of all you marker points
// Begin loop
bounds.extend(marker_point);
// End loop

map.fitBounds(bounds);

结果:成功!


3

我用:

gmap.setZoom(24); //this looks a high enough zoom value
gmap.fitBounds(bounds); //now the fitBounds should make the zoom value only less

根据您的代码,这将使用24中的较小者和必要的缩放级别,但是无论如何它可能会更改缩放并且并不关心您缩小了多少。


我不想这么说,但是这个答案看起来很奇怪,这是到目前为止唯一有效的方法,我一直在3天的时间里搜寻4-5小时。仍然会在寻找更好的解决方案。
Allov

3

请尝试以下方法:

map.fitBounds(bounds);

// CHANGE ZOOM LEVEL AFTER FITBOUNDS
zoomChangeBoundsListener = google.maps.event.addListenerOnce(map, 'bounds_changed', function(event) {
  if (this.getZoom()){
    this.setZoom(15);
  }
});
setTimeout(function(){
  google.maps.event.removeListener(zoomChangeBoundsListener)
}, 2000);

2

我遇到了同样的问题,可以使用以下代码解决它。google.maps.addListenerOnce()map.fitBounds()执行之后,此listener()事件只会被触发一次。因此,无需

  1. 跟踪并手动删除侦听器,或者
  2. 等到地图idle

它最初设置适当的缩放级别,并且由于事件侦听器已过期,因此允许用户放大和缩小超出初始缩放级别。例如,如果仅google.maps.addListener()被调用,则用户将永远无法放大超过指定的缩放级别(在这种情况下为4)。自实施以来google.maps.addListenerOnce(),用户将能够缩放到他/她选择的任何级别。

map.fitBounds(bounds);

var zoom_level_for_one_marker = 4;

google.maps.event.addListenerOnce(map, 'bounds_changed', function(event){
   if (this.getZoom() >= zoom_level_for_one_marker){  
       this.setZoom(zoom_level_for_one_marker) 
   }
});

2

遇到同样的问题,需要在地图上放置许多标记。这解决了我的情况:

  1. 声明范围
  2. koderoid提供的使用方案(针对每个标记集bounds.extend(objLatLng)
  3. 贴图完成后执行fitbounds:

    google.maps.event.addListenerOnce(map, 'idle', function() { 
        map.fitBounds( bounds );
    });

2

我找到了一种解决方案,可以在致电前进行检查,fitBounds这样您就不会放大并突然缩小

var bounds = new google.maps.LatLngBounds();

// extend bounds with each point

var minLatSpan = 0.001;
if (bounds.toSpan().lat() > minLatSpan) {
    gmap.fitBounds(bounds); 
} else {
    gmap.setCenter(bounds.getCenter());
    gmap.setZoom(16);
}

您必须稍微玩弄minLatSpan变量才能将其获取到所需位置。它会根据缩放级别和地图画布的尺寸而有所不同。

您也可以使用经度代替纬度


对我有用,但我没有使用minLatSpan-仅在地图中有1个标记时才需要设置缩放比例。因此,我只检查是否有1个以上的标记。
Micer

2

我看到了许多不正确或过于复杂的解决方案,因此决定发布一个可行的,优雅的解决方案

原因setZoom()不符合您的预期fitBounds(),因为它是异步的,因此无法保证会立即更新缩放,但您的调用setZoom()依赖于此。

您可能考虑的是minZoom在调用之前设置map选项fitBounds(),然后在完成后清除它(以便用户仍然可以手动缩小):

var bounds = new google.maps.LatLngBounds();
// ... (extend bounds with all points you want to fit)

// Ensure the map does not get too zoomed out when fitting the bounds.
gmap.setOptions({minZoom: 6});
// Clear the minZoom only after the map fits the bounds (note that
// fitBounds() is asynchronous). The 'idle' event fires when the map
// becomes idle after panning or zooming.
google.maps.event.addListenerOnce(gmap, 'idle', function() {
  gmap.setOptions({minZoom: null});
});

gmap.fitBounds(bounds);

此外,如果您还想限制最大缩放比例,则可以对该maxZoom属性应用相同的技巧。

请参阅MapOptions文档


1

我使用它来确保缩放级别不超过设置的级别,以便我知道可以使用卫星图像。

zoom_changed事件添加侦听器。这具有在UI上也控制缩放控件的额外好处。

仅在setZoom需要时才执行,因此if语句优于Math.maxMath.min

   google.maps.event.addListener(map, 'zoom_changed', function() { 
      if ( map.getZoom() > 19 ) { 
        map.setZoom(19); 
      } 
    });
    bounds = new google.maps.LatLngBounds( ... your bounds ... )
    map.fitBounds(bounds);

为防止缩小得太远:

   google.maps.event.addListener(map, 'zoom_changed', function() { 
      if ( map.getZoom() < 6 ) { 
        map.setZoom(6); 
      } 
    });
    bounds = new google.maps.LatLngBounds( ... your bounds ... )
    map.fitBounds(bounds);

1

在此函数中,仅由于该函数接受任何几何图形,才需要动态添加元数据以存储几何图形类型。

“ fitGeometries”是扩展地图对象的JSON函数。

“ geometries”是通用的javascript数组,而不是MVCArray()。

geometry.metadata = { type: "point" };
var geometries = [geometry];

fitGeometries: function (geometries) {
    // go and determine the latLngBounds...
    var bounds = new google.maps.LatLngBounds();
    for (var i = 0; i < geometries.length; i++) {
        var geometry = geometries[i];
        switch (geometry.metadata.type)
        {
            case "point":
                var point = geometry.getPosition();
                bounds.extend(point);
                break;
            case "polyline":
            case "polygon": // Will only get first path
                var path = geometry.getPath();
                for (var j = 0; j < path.getLength(); j++) {
                    var point = path.getAt(j);
                    bounds.extend(point);
                }
                break;
        }
    }
    this.getMap().fitBounds(bounds);
},

另外,我做所有工作时都不知道LatLngBounds对象上有一个extend()方法。这样会容易得多。
CrazyEnigma


1

像我一样,如果您不愿意与听众一起玩,这是我想到的一个简单解决方案:在地图上添加一种方法,该方法严格按照您的要求进行,例如:

    map.fitLmtdBounds = function(bounds, min, max){
        if(bounds.isEmpty()) return;
        if(typeof min == "undefined") min = 5;
        if(typeof max == "undefined") max = 15;

        var tMin = this.minZoom, tMax = this.maxZoom;
        this.setOptions({minZoom:min, maxZoom:max});
        this.fitBounds(bounds);
        this.setOptions({minZoom:tMin, maxZoom:tMax});
    }

那么您可以调用map.fitLmtdBounds(bounds)而不是map.fitBounds(bounds)在定义的缩放范围内设置边界...或map.fitLmtdBounds(bounds,3,5)覆盖缩放范围。


0

请尝试这个。

// Find out what the map's zoom level is
zoom = map.getZoom();
if (zoom == 1) {
  // If the zoom level is that low, means it's looking around the
world.
  // Swap the sw and ne coords
  viewportBounds = new
google.maps.LatLngBounds(results[0].geometry.location, initialLatLng);
  map.fitBounds(viewportBounds);
}

如果这对您有帮助。

祝一切顺利


0

计算边界后,您可以检查左上角和右下角之间的距离。然后您可以通过测试距离来了解缩放级别(如果距离太远,则缩放级别会很低),然后可以使用setbound方法或setZoom选择Wheter。


0

我不建议这样做,但是,如果您必须尝试-请先致电

gmap.fitBounds(bounds);

然后创建一个新的Thread / AsyncTask,让它休眠20-50ms左右,然后调用

gmap.setZoom( Math.max(6, gmap.getZoom()) );

从UI线程(使用处理程序或onPostExecuteAsyncTask方法)。

我不知道它是否有效,只是一个建议。除此之外,您还必须自己通过点来计算缩放级别,检查其是否过低,进行校正,然后致电gmap.setZoom(correctedZoom)


0

如果'bounds_changed'未正确触发(有时Google似乎无法完美接受坐标),则可以考虑使用'center_changed'。

每次调用fitBounds()时都会触发'center_changed'事件,尽管该事件立即运行,并且不一定在地图移动后运行。

在正常情况下,“ idle”仍然是最好的事件侦听器,但这可能有助于一对夫妇通过fitBounds()调用遇到奇怪的问题。

查看Google Maps fitBounds回调


0

为了配合其他解决方案-我发现“监听bounds_changed事件然后设置新的缩放”方法对我来说并不可靠。我认为有时我是fitBounds在地图完全初始化之前调用的,而初始化是在fitBounds更改边界和缩放级别之前引起bounds_changed事件,该事件将耗尽侦听器。我最终得到了这段代码,到目前为止,它似乎仍然有效:

// If there's only one marker, or if the markers are all super close together,
// `fitBounds` can zoom in too far. We want to limit the maximum zoom it can
// use.
//
// `fitBounds` is asynchronous, so we need to wait until the bounds have
// changed before we know what the new zoom is, using an event handler.
//
// Sometimes this handler gets triggered by a different event, before
// `fitBounds` takes effect; that particularly seems to happen if the map
// hasn't been fully initialized yet. So we don't immediately remove the
// listener; instead, we wait until the 'idle' event, and remove it then.
//
// But 'idle' might happen before 'bounds_changed', so we can't set up the
// removal handler immediately. Set it up in the first event handler.

var removeListener = null;
var listener = google.maps.event.addListener(map, 'bounds_changed', () => {
  console.log(map.getZoom());
  if (map.getZoom() > 15) {
    map.setZoom(15);
  }

  if (!removeListener) {
    removeListener = google.maps.event.addListenerOnce(map, 'idle', () => {
      console.log('remove');
      google.maps.event.removeListener(listener);
    });
  }
});

0

对我来说,最简单的解决方案是:

map.fitBounds(bounds);

function set_zoom() {
    if(map.getZoom()) {map.setZoom(map.getZoom() - 1);}
    else {setTimeout(set_zoom, 5);}
}
setTimeout(set_zoom, 5);

-1
google.maps.event.addListener(marker, 'dblclick', function () {
    var oldZoom = map.getZoom(); 
    map.setCenter(this.getPosition());
    map.setZoom(parseInt(oldZoom) + 1);
});

-3

我所做的就是:

map.setCenter(bounds.getCenter(), map.getBoundsZoomLevel(bounds));

它适用于V3 API。


map.setCenter仅接受一个属性latlng,并且地图没有像getBoundsZoomLevel这样的功能
Viktor 2010年

看到这篇文章后,我以为会有一个类似getBoundsZoomLevel的函数,当我意识到没有这个功能后,我感到很失望。
sedran,2012年

我认为getBoundsZoomLevel()在Google Maps V2 API中可用,而在V3 API中不可用
Kush 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.