【问题标题】:Google Maps API V3 fitbounds() zooms out but never inGoogle Maps API V3 fitbounds() 缩小但从不缩小
【发布时间】:2011-03-16 04:07:35
【问题描述】:

我创建了一个相当复杂的商店定位器。用户输入他们的 zip,然后表格会返回带有地图上相应标记的结果。他们可以翻阅结果,并且标记会越来越远,fitbounds() 功能非常适合缩小到适当的缩放级别以适合标记。问题是,如果您返回到更近的位置,fitbounds() 不会放大。即使您输入新的搜索,它也不会围绕这些新标记放大 - 它以它们为中心,但保持在任何缩放级别它是在以前。我希望这是有道理的。如果有人知道我需要添加什么来放大更接近的结果,请提供帮助。这些是我在标记推送函数结束时调用的谷歌函数:

  map.setCenter(bounds.getCenter());
  map.panToBounds(bounds);
  map.fitBounds(bounds);

谢谢!

【问题讨论】:

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


    【解决方案1】:

    查看marker.setMap(null); 上 GMap 文档中的引用(用于从地图中删除标记):

    请注意,上述方法不会删除标记。它删除了 地图上的标记。相反,如果您想删除标记,您可以 应将其从地图中删除,然后将标记本身设置为 null。

    我的问题是,当我从地图中删除标记时,它们仍然存储在 map.markers 中。因此,在设置 bounds 时,它也会抓取所有以前的标记:

    map.markers.forEach( (marker) => {
      var latlng = new google.maps.LatLng(marker.position.lat(), marker.position.lng())
      bounds.extend(latlng)
    })
    

    Console.logging bounds 表明边界将始终容纳所有早期的边界,因此。

    我的解决方案是跟踪单独的 markers 数组/对象中的标记,该数组/对象存储每个标记的唯一键(在我的情况下链接到位置自动完成输入字段),并在删除时从中删除标记地图上的标记。这样我可以在生成bounds 时运行检查,以查看map.markers 中的当前标记是否在(最新的)markers 数组中。

    map.markers.forEach( (marker) => {
      // check if map marker is in this.markers (to make sure only current)
      for (const [key, value] of Object.entries(markers)) {
        if (marker == value) {
          var latlng = new google.maps.LatLng(marker.position.lat(), marker.position.lng())
          bounds.extend(latlng)
        }
      }
    })
    

    现在我的地图在更改标记后可以正确放大。如果有人可以对上述方法提出任何改进,我很乐意听到!

    伦斯

    【讨论】:

      【解决方案2】:

      确保地图的宽度或高度上没有 CSS 动画。动画会干扰 fitBound() 的缩放行为

      昨天我花了大部分时间在这个问题上,我遇到过这个 StackOverflow 帖子至少十几次。但我最终不得不靠自己艰难地找到问题所在。

      删除下面的transition: all 0.5s ease; 行为我修复了它。

      .google-map {
        width: 100%;
        height: 0px;
        transition: all 0.5s ease;
      }
      
      .google-map.loaded {
          height: 400px;
      }
      
      

      【讨论】:

        【解决方案3】:

        帮助我的是使用 0 填充作为 fitBounds(bounds, padding) 的第二个参数,这是完整的代码示例:

        function initMap() {
            var mapOptions = {
                center: new google.maps.LatLng(0, 0),
                zoom: 1,
                minZoom: 1
            };
            map = new google.maps.Map(document.getElementById('officeMap'), mapOptions);
            google.maps.event.addListenerOnce(map, 'idle', function() {
                //Map is ready
                worldViewFit(map);
            });
        }
        function worldViewFit(mapObj) {
            var worldBounds = new google.maps.LatLngBounds(
                new google.maps.LatLng(70.4043,-143.5291),  //Top-left
                new google.maps.LatLng(-46.11251, 163.4288)  //Bottom-right
            );
            mapObj.fitBounds(worldBounds, 0);
            var actualBounds = mapObj.getBounds();
            if(actualBounds.getSouthWest().lng() == -180 && actualBounds.getNorthEast().lng() == 180) {
                mapObj.setZoom(mapObj.getZoom()+1);
            }
        }
        

        【讨论】:

        • 花了一天的搜索和调试后,这个答案就是解决方案。谢谢汤姆。
        【解决方案4】:

        嗯,有趣.. 我使用 PHP 循环遍历所有(待)标记坐标并计算西南和东北的值;原点坐标介于两者之间。如果所有标记坐标彼此非常接近,则由 fitBounds 设置的缩放因子比创建地图时使用的 15 高得多(放大)。这就是我添加最后一行的原因..

        var map;
        
        function mapInit() {
          var origin = new google.maps.LatLng(59.33344615, 18.0678188);
          var options = {
            zoom: 15,
            center: origin,
            mapTypeControlOptions: {
              mapTypeIds: [google.maps.MapTypeId.ROADMAP, google.maps.MapTypeId.HYBRID]
            },
            mapTypeId: google.maps.MapTypeId.ROADMAP
          };
        
          map = new google.maps.Map(document.getElementById("googlemap"), options);
        
          var southWest = new google.maps.LatLng(59.3308415, 18.0643054);
          var northEast = new google.maps.LatLng(59.3360508, 18.0713322);
          var bounds = new google.maps.LatLngBounds(southWest, northEast);
          map.fitBounds(bounds);
        
          google.maps.event.addListenerOnce(map, "idle", function() {
            if (map.getZoom() > 16) map.setZoom(16);
          });
        

        所以,要么 Google 在您发布问题后重新编程了该功能,要么.. 我需要有关您的代码的更多信息。

        【讨论】:

        • 感谢只有这件事对我有用 尝试了许多根据我的要求修改的解决方案 google.maps.event.addListenerOnce(map, "idle", function() { if (map.getZoom()
        【解决方案5】:

        我今天遇到了这个一般问题,想分享一个解决方案。我意识到这与您的“商店定位器”问题略有不同,但它确实适用于许多方面。就我而言,我在地图上有一组标记并正在添加一个,并希望确保所有标记现在都在视图中。此代码检查每个现有标记以查看其是否在视图中,并在此过程中构建一个包含所有标记的新边界框(如果需要)。最后,如果发现任何视图不在视图中,视图将被重置,因此它们都在视图中。

        (这使用了 Dojo 的数组模块,只是对基本数组迭代的方便包装)

        var origBounds = map.getBounds(),
            newBounds = new google.maps.LatLngBounds(null),
            anyFailed = false;
        array.forEach(markers, function (m) {
            newBounds.extend(m.position);
            if (!origBounds.contains(m.position)) {
                anyFailed = true;
            }
        });
        if (anyFailed) {
            map.setCenter(newBounds.getCenter());
            map.fitBounds(newBounds);
        }
        

        人们可以很容易地修改它,只确保新标记在视图中,不循环并且只对新标记进行 contains() 检查。

        【讨论】:

          【解决方案6】:

          在使用新标记在同一张地图上第二次调用 fitBounds 时,我还遇到了地图缩小的问题。这是对我有用的 frankensolution:

          // This is a stationary point tho dynamic will work too
          
          var myLat = someLat,
              myLng = someLong;
          
          var map = false,
              markersArray = [];
          
          function makeOrderMap(lat, lng) { // pass in dynamic point when updating map
          
            var mapOptions = {
                center: new google.maps.LatLng(myLat, myLng),
                zoom: 16,
                mapTypeId: google.maps.MapTypeId.ROADMAP
            };
            deleteOverlays(); // remove any existing markers..
            if(!map) {  
              map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
            } 
          
            // Find the mid-point to center the map
          
            midLat = (parseFloat(lat) + parseFloat(myLat)) / 2;
            midLng = (parseFloat(lng) + parseFloat(myLng)) / 2;
            map.setCenter(new google.maps.LatLng(midLat, midLng));
            var newSpot = new google.maps.LatLng(lat, lng); 
          
            placeMarker(mapOptions.center);    
            placeMarker(newSpot);   
          
            // determine the distance between points for deciding the zoom level
          
            var dist = distHaversine(mapOptions.center, newSpot);
          
            var zoom = 10;
            if(dist < 1.25) {
              zoom = 15;
            } else if(dist < 2.5) {
              zoom = 14;
            } else if(dist < 5) {
              zoom = 13;
            } else if(dist < 10) {
              zoom = 12;
            } else if(dist < 20) {
              zoom = 11;
            }
            map.setZoom(zoom);  
          }
          
          
          rad = function(x) {return x*Math.PI/180;}
          
          distHaversine = function(p1, p2) {
            var R = 6371; // earth's mean radius in km
            var dLat  = rad(p2.lat() - p1.lat());
            var dLong = rad(p2.lng() - p1.lng());
          
            var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
                    Math.cos(rad(p1.lat())) * Math.cos(rad(p2.lat())) * Math.sin(dLong/2) * Math.sin(dLong/2);
            var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
            var d = R * c;
          
            return d.toFixed(3);
          }
          
          function deleteOverlays() {
              if (markersArray) {
                  for (i in markersArray) {
                      markersArray[i].setMap(null);
                  }
              markersArray = [];    
              markersArray.length = 0;
              }    
          }
          
          function placeMarker(location, alt_icon) {
          
              var marker = new google.maps.Marker({
                  position: location, 
                  map: map
                });
          
              // add marker in markers array
              markersArray.push(marker);
          }
          

          【讨论】:

          【解决方案7】:

          事实证明,当您调用map.getBounds() 时,它会返回视口,并在边缘周围留出一点边距。由于这个新边界大于当前边界,因此地图将始终缩小。我能够通过完全避免使用当前地图的边界并维护一个单独的 LatLngBounds 变量来解决它。每次我添加一个点时,我都会调用:

          markersBounds.extend(newMarkersLatLng);
          map.fitBounds(markersBounds);
          map.panToBounds(markersBounds);
          

          要删除点(我一直在添加它们),您可以使用第一个点创建一个新的 LatLngBounds 对象,然后扩展每个剩余点以获得新的边界:

          var markersBounds = new google.maps.LatLngBounds(markers[0].getPosition(),
                                                           markers[0].getPosition());
          for(var i=1; i<markers.length; i++){
              markersBounds.extend(markers[i].getPosition());
          }
          
          map.fitBounds(markersBounds);
          map.panToBounds(markersBounds);
          

          【讨论】:

            【解决方案8】:

            问题是这样的:我们设置

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

            以便我们以后可以将标记匹配到地图上的有界区域。 GMaps 将始终相应地异步缩小到 fitBounds() ,但不会放大以实现相同的效果(如@broady 之前所述)。这对于许多应用程序来说并不理想,因为一旦您在地图上显示了一系列导致地图缩小(可能

            GMaps 将继续使用(缺少更好的词)最缩小的标记集合状态的边界(抱歉)。在每次调用新标记之前设置为“null”,可为您提供新的地图。

            要自动放大,只需设置 LatLngBounds();像这样'null'(请参阅下面的伪示例以查看其位置):

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

            伪例子:

            // map stuff/initiation
            ...
            
            var bounds = new google.maps.LatLngBounds();
            var gmarkers = [];
            
            function CreateMarker (obj) {
                myLatLng = new google.maps.LatLng(obj['latitude'], obj['longitude']);
                marker = new google.maps.Marker({
                    position: myLatLng,
                    map: map
                });
                google.maps.event.addListener(marker, 'click', (function(marker, i) {
                    return function() {
                        infowindow.setContent(obj['job']);
                        infowindow.open(map, marker);
                    }
                })(marker, i));
                bounds.extend(myLatLng);
                gmarkers.push(marker);
            }
            
            ....
            
            // here's an AJAX method I use to grab marker coords from a database:
            
            $.ajax({
                beforeSend: function() {
                    clear_markers(gmarkers); // see below for clear_markers() function declaration
                },
                cache: false,
                data: params,
                dataType: 'json',
                timeout: 0,
                type: 'POST',
                url: '/map/get_markers.php?_=<?php echo md5(session_id() . time() . mt_rand(1,9999)); ?>',
                success: function(data) {
                    if (data) {
                        if (data['count'] > 0) {
                            var obj;
                            var results = data['results'];
            
                            // Plot the markers
                            for (r in results) {
                                if (r < (data['count'])) {
                                    CreateMarker(results[r]);
                                }
                            }
                        }
                    }
                },
                complete: function() {
                    map.fitBounds(bounds);
                }
            });
            
            // clear_markers()
            function clear_markers(a) {
                if (a) {
                    for (i in a) {
                        a[i].setMap(null);
                    }
                    a.length = 0;
                }
                bounds = new google.maps.LatLngBounds(null); // this is where the magic happens; setting LatLngBounds to null resets the current bounds and allows the new call for zoom in/out to be made directly against the latest markers to be plotted on the map
            }
            

            【讨论】:

            • 感谢约翰·史密斯!您的建议是我在删除标记后能够让我重新放大的唯一方法。我很欣赏你帖子中的细节。
            【解决方案9】:

            这里不需要花哨的东西。首先适合边界,然后平移到它。这将为您提供适当的缩放并包含整个边界。

            map.fitBounds(bounds);
            map.panToBounds(bounds);
            

            【讨论】:

            • 这似乎有效。我想知道如果没有fitBoundspanToBounds 应该做什么。
            【解决方案10】:
            fitBounds: function(bounds, mapId)
                {
                    //bounds: bounds, id: map id
                    if (bounds==null) return false;
                    maps[mapId].fitBounds(bounds);
                },  
            

            这应该会有所帮助,我使用这种方法并且工作正常,在地图 v2 上有点不同。

            【讨论】:

              【解决方案11】:

              没错,fitBounds 只是确保提供的边界是可见的。它没有放大到适当的水平。

              您可以先调用setZoom(20),然后调用fitBounds。

              【讨论】:

              • 对于稍后阅读本文的任何人,fitBounds 会使用当前版本进行缩放,而 panToBounds 不会并匹配上述内容。
              【解决方案12】:
              map.setZoom(10);
              

              我认为可接受的范围是 1-20。仅整数,根据我的经验,小数破坏了地图。

              【讨论】:

                猜你喜欢
                • 2015-08-27
                • 2011-01-27
                • 1970-01-01
                • 2019-02-05
                • 2013-03-28
                • 1970-01-01
                • 2011-12-31
                • 1970-01-01
                相关资源
                最近更新 更多