【问题标题】:Google Maps API v3: Can I setZoom after fitBounds?Google Maps API v3:我可以在 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()”不会改变地图的缩放级别。

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

【问题讨论】:

  • 查看 stackoverflow.com/questions/4523023/using-setzoom-after-using-fitbounds-with-google-maps-api-v3

标签: javascript google-maps google-maps-api-3 fitbounds


【解决方案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() 函数时它都会改变。见stackoverflow.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】:

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

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

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

                    【讨论】:

                      【解决方案16】:

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

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

                      【讨论】:

                        【解决方案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 小时。但仍会寻找更好的解决方案。
                                猜你喜欢
                                • 2013-03-28
                                • 2015-08-27
                                • 2011-03-16
                                • 2013-02-24
                                • 1970-01-01
                                • 2023-03-05
                                • 2012-01-25
                                • 2012-08-23
                                相关资源
                                最近更新 更多