Google Maps API v3:我可以在 fitBounds 之后设置缩放吗?

Posted

技术标签:

【中文标题】Google Maps API v3:我可以在 fitBounds 之后设置缩放吗?【英文标题】:Google Maps API v3: Can I setZoom after fitBounds? 【发布时间】:2011-01-27 02:49:51 【问题描述】:

我想在嵌入式 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()”不会改变地图的缩放级别。

有没有办法在不将其应用于地图的情况下获得边界的缩放级别?解决这个问题的其他想法?

【问题讨论】:

查看 ***.com/questions/4523023/using-setzoom-after-using-fitbounds-with-google-maps-api-v3 【参考方案1】:

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

map.fitBounds(bounds);

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

setTimeout(set_zoom, 5);

【讨论】:

【参考方案2】:

加入另一个解决方案 - 我发现“监听 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);
    );
  
);

【讨论】:

【参考方案3】:

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

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

您可能会考虑在调用fitBounds() 之前设置minZoom 地图选项,然后在完成后将其清除(这样用户仍然可以根据需要手动缩小):

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 docs。

【讨论】:

【参考方案4】:

请试试这个:

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);

【讨论】:

【参考方案5】:

如果“bounds_changed”未正确触发(有时 Google 似乎无法完全接受坐标),请考虑改用“center_changed”。

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

在正常情况下,'idle' 仍然是最好的事件监听器,但这可能有助于一些人在调用 fitBounds() 时遇到奇怪的问题。

见google maps fitBounds callback

【讨论】:

【参考方案6】:

如果我没记错的话,我假设您希望您的所有点都以尽可能高的缩放级别在地图上可见。我通过将地图的缩放级别初始化为 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);

结果: 成功!

【讨论】:

【参考方案7】:

和我一样,如果你不愿意和听众一起玩,这是我想出的一个简单的解决方案: 在地图上添加一种严格按照您的要求工作的方法,如下所示:

    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) 来覆盖缩放范围。 .

【讨论】:

【参考方案8】:

编辑:见下方 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); 
);

根据您的需要进行修改。

【讨论】:

很好的解决方案,完全为我省去了很多麻烦。只是想补充一点,您可以使用 addListenerOnce 方法进一步简化它......这样,您不必保存侦听器并手动删除它,因为该方法会为您处理。 这具有看到地图“跳过”的行为。而是监听“zoom_change”事件,并在调用 fitBounds() 之前进行设置。请参阅下面的答案 谢谢! google.maps.event.addListenerOnce(map, "idle", function() --> 非常适合我的 SugarCRM 地图包。 如果 fitBounds 没有导致 'bounds_changed' 事件触发,则改用 'center_changed'。每次调用 fitBounds() 函数时它都会改变。见***.com/questions/35761416/… 您可以使用addListnerOnce 来避免删除它的逻辑。【参考方案9】:

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

在我的应用程序中,我想绘制一个或多个标记并确保地图显示所有标记。问题是,如果我只依赖 fitBounds 方法,那么当只有一个点时,缩放级别就会被最大化——这不好。

解决方法是点多的时候用fitBounds,只有一个点的时候用setCenter+setZoom。

if (pointCount > 1) 
  map.fitBounds(mapBounds);

else if (pointCount == 1) 
  map.setCenter(mapBounds.getCenter());
  map.setZoom(14);

【讨论】:

您的回答解决了我使用 Google Maps V3 的问题。谢谢! 我自己尝试了同样的方法,但它不起作用,因为我在设置缩放之前没有调用 setCenter() ......我仍然想知道为什么需要这一步,但无论如何现在它可以工作了......非常感谢吉姆! 这很好,因为您不必处理已接受答案的动画跳转。【参考方案10】:

我刚刚通过提前设置 maxZoom,然后将其删除来解决此问题。例如:

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

【讨论】:

迄今为止防止过度放大的最佳解决方案。简单直观。不绘制和重新绘制地图。 这确实是迄今为止最好的解决方案。 我发现如果你在调用 fitBounds 后立即重置 maxZoom,这将不起作用,因为缩放是异步发生的(所以 maxZoom 在它放大时会返回 null)。等到“空闲”重置它会解决这个问题。【参考方案11】:
google.maps.event.addListener(marker, 'dblclick', function () 
    var oldZoom = map.getZoom(); 
    map.setCenter(this.getPosition());
    map.setZoom(parseInt(oldZoom) + 1);
);

【讨论】:

【参考方案12】:

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

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

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

希望这对某人有所帮助!

【讨论】:

太好了,我也有“跳过/自动缩放”行为。就像给其他读者的注释一样:一定要像上面的 Benjamin 那样使用“addListenerOnce”而不是“addListener”,或者打破你的浏览器为什么总是崩溃的头脑;-) 另外注意,如果使用zoom_changed,在调用fitBounds()之前应该添加监听器 谢谢你,看来 v4 应该有一个 fitBounds(bounds,minZoomLevel) :) Benjamin,我认为最好使用bounds_changed,因为zoom_changedfitBounds 保持缩放级别的情况下不必触发。我的尝试jsfiddle.net/rHeMp/10 并未证实这一点,但不应依赖未定义的行为。【参考方案13】:

我找到了一个解决方案,可以在调用 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 个标记。【参考方案14】:

这项工作适用于我使用 API v3 但设置固定缩放:

var bounds = new google.maps.LatLngBounds();
// extend bounds with each point

gmap.setCenter(bounds.getCenter()); 
gmap.setZoom( 6 );

【讨论】:

【参考方案15】:

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

    声明边界 使用 koderoid 提供的方案(针对每个标记集 bounds.extend(objLatLng)

    在地图完成后执行 fitbounds:

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

【讨论】:

【参考方案16】:

我遇到了同样的问题,我可以使用以下代码解决它。此侦听器 (google.maps.addListenerOnce()) 事件只会在 map.fitBounds() 执行后立即触发一次。所以,没必要

    跟踪并手动删除监听器,或者 等到地图是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) 
   
);

【讨论】:

【参考方案17】:

我所做的只是:

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

它适用于 V3 API。

【讨论】:

map.setCenter 只接受一个属性,latlng,map 没有getBoundsZoomLevel 之类的功能 看到这个帖子我还以为有getBoundsZoomLevel之类的功能,发现没有后很失望。 我认为 getBoundsZoomLevel() 在 Google Maps V2 API 中可用,在 V3 API 中不可用【参考方案18】:

在此函数中,您需要动态添加元数据来存储几何类型,只是因为该函数接受任何几何图形。

“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() 方法的情况下完成了所有工作。这会容易得多。【参考方案19】:

我不喜欢推荐它,但如果你必须试试 - 先打电话

gmap.fitBounds(bounds);

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

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

来自 UI 线程(对 AsyncTask 使用处理程序或 onPostExecute 方法)。

我不知道它是否有效,只是一个建议。除此之外,您必须以某种方式自己根据您的点计算缩放级别,检查它是否太低,纠正它,然后调用gmap.setZoom(correctedZoom)

【讨论】:

【参考方案20】:

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

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);

【讨论】:

【参考方案21】:

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

【讨论】:

【参考方案22】:

请试试这个。

// 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);

如果这对你有帮助。

一切顺利

【讨论】:

【参考方案23】:

我用:

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 小时。但仍会寻找更好的解决方案。

以上是关于Google Maps API v3:我可以在 fitBounds 之后设置缩放吗?的主要内容,如果未能解决你的问题,请参考以下文章

Google Maps v3 - 防止 API 加载 Roboto 字体

可以吗? GMap API V2 中的 clearOverlays() 到 Google Maps API V3?

如何在 Google Maps API v3 中使用 SVG 标记

是否可以在Google Maps API v3上编写自定义文字?

Google Maps API v3 infowindow 关闭事件/回调?

Google Maps Api v3 - 查找最近的标记