jQuery Google Maps API V3 fitbounds() 缩小但从不缩小

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3251774/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 15:07:58  来源:igfitidea点击:

Google Maps API V3 fitbounds() zooms out but never in

jquerygoogle-mapsgoogle-maps-api-3fitbounds

提问by abemonkey

I've created a quite complex store locator of sorts. The user enters their zip and a table returns results with corresponding markers on a map. They can page through results and the markers move further and further out and the fitbounds()function works great for zoom out to the appropriate zoom level to fit the markers. The problem is that if you page back to closer locations the fitbounds()doesn't zoom in. Even if you enter a new search it doesn't zoom in around those new markers -- it centers over them but stays at whatever zoom level it was at previously. I hope this makes sense. If anyone knows what I need to add to get it to zoom back in on closer results please help. These are the google functions that I'm call at the end of my marker pushing function:

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

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

Thanks!

谢谢!

回答by Doug

Nothing fancy needed here. First fit bounds then pan to it. This will give you the proper zoom and contain the entire bounds.

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

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

回答by John Smith

The problem is this: we set

问题是这样的:我们设置

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

so that we can later fit our markers to a bounded area on the map. GMaps will always zoom out asynchronously to fitBounds() accordingly, but will not zoom in to achieve the same (as previously noted by @broady). This is not ideal for many applications as once you have gone and displayed a series of markers on the map that caused the map to zoom out (maybe <10), it will not zoom back in without the user manually doing so.

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

GMaps will continue to use the bounds of the (lack of better words) most zoomed out marker collection status (sorry). Setting to 'null' before each call for new markers gives you a fresh map to work with.

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

To auto-zoom in, simply set the LatLngBounds(); to 'null' like so (see pseudo example below to see its placement):

要自动放大,只需设置 LatLngBounds(); 像这样“空”(参见下面的伪示例以查看其位置):

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

Pseudo example:

伪示例:

// 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
}

回答by Chris Broadfoot

That's right, fitBoundsonly ensuresthat the provided bounds are visible. It doesn't zoom in to an appropriate level.

没错,fitBounds确保提供的边界是可见的。它不会放大到适当的级别。

You could first call setZoom(20), then fitBounds.

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

回答by LGT

Hmm, interesting.. I use PHP to loop through all (to be) marker coordinates and calculate the values of southWest and northEast; the coords of origin are halfway between the two. If all marker coordinates are very close to each other, the zoom factor set by fitBounds is much higher (zoomed in) than the 15 used at map creation. That's why I have added that last row..

嗯,有趣.. 我使用 PHP 循环遍历所有(将是)标记坐标并计算 SouthWest 和 NorthEast 的值;原点坐标介于两者之间。如果所有标记坐标彼此非常接近,则 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);
  });

So, either Google has reprogrammed the function since you posted the question or.. I need more information about your code.

因此,自您发布问题以来,谷歌已经重新编程了该功能,或者……我需要有关您的代码的更多信息。

回答by Tom G

What helped me was using 0 padding as the second parameter to fitBounds(bounds, padding), here is the full code sample:

帮助我的是使用 0 padding 作为 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);
    }
}

回答by charltoons

It turns out that when you call map.getBounds()it returns the viewport with a little margin around the edges. Since this new bounds is larger than the current bounds, the map will always zoom out. I was able to solve it by avoiding using the current map's bounds altogether and maintaining a separate LatLngBounds variable. Every time I added a point I called:

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

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

To remove points (I was always adding them), you could make a new LatLngBounds object with the first point, then extend each remaining point to get your new bounds:

要删除点(我总是添加它们),您可以使用第一个点创建一个新的 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);

回答by Ryan Charmley

I also had an issue with the map zooming way out when calling fitBounds a second time on the same map with new markers. This is the frankensolution that works for me:

在使用新标记在同一地图上第二次调用 fitBounds 时,我也遇到了地图缩小的问题。这是对我有用的弗兰肯解决方案:

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

回答by Neek

I encountered this general problem today, thought I'd share a solution. I realise this is slightly different to your 'store locator' problem, but it does apply in many ways. In my case I have a collection of markers on the map and am adding one, and want to ensure all markers are now in view. This code checks each existing marker to see if its in the view, and along the way, builds a new bounding box that would contain them all, if required. At the end, if any have been found to not be in view, the view is reset so they all are.

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

(this uses Dojo's array module, simply a convenience wrapper around basic array iteration)

(这使用了 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);
}

One could easily modify this to only ensure the new marker is in view, by not looping and just doing a contains() check on the new marker.

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

回答by localtime

fitBounds: function(bounds, mapId)
    {
        //bounds: bounds, id: map id
        if (bounds==null) return false;
        maps[mapId].fitBounds(bounds);
    },  

This should help, i use this method and works fine, on map v2 a little bit different way.

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

回答by Greg W

map.setZoom(10);

I believe the acceptable range is 1-20. Whole numbers only, decimals broke the map in my experience.

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