简体   繁体   English

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

[英]Google Maps API v3: Can I setZoom after fitBounds?

I have a set of points I want to plot on an embedded Google Map (API v3). 我想在嵌入式Google Map(API v3)上绘制一组点。 I'd like the bounds to accommodate all points unless the zoom level is too low (ie, zoomed out too much). 除非缩放级别太低(即缩小太多),否则我希望能够容纳所有点。 My approach has been like this: 我的方法是这样的:

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

// extend bounds with each point

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

This doesn't work. 这不起作用。 The last line "gmap.setZoom()" doesn't change the zoom level of the map if called directly after fitBounds. 如果在fitBounds之后直接调用,则最后一行“gmap.setZoom()”不会更改地图的缩放级别。

Is there a way to get the zoom level of a bounds without applying it to the map? 有没有办法获得边界的缩放级别而不将其应用于地图? Other ideas to solve this? 解决这个问题的其他想法?

Edit : See Matt Diamond's comment below. 编辑 :见Matt Diamond的评论如下。

Got it! 得到它了! Try this: 试试这个:

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

Modify to your needs. 修改您的需求。

I solved a similar problem in one of my apps. 我在我的一个应用程序中解决了类似的问题。 I was a little confused by your description of the problem, but I think you have the same goal I had... 你对这个问题的描述让我感到有点困惑,但我认为你有同样的目标......

In my app I wanted to plot a one or more markers and ensure the map was showing them all. 在我的应用程序中,我想绘制一个或多个标记,并确保地图显示所有标记。 The problem was, if I relied solely on the fitBounds method, then the zoom-level would be maxed out when there was a single point - that was no good. 问题是,如果我完全依赖于fitBounds方法,那么当存在单个点时,缩放级别将被最大化 - 这是不好的。

The solution was to use fitBounds when there was many points, and setCenter+setZoom when there was only one point. 解决方案是在有多个点时使用fitBounds,在只有一个点时使用setCenter + setZoom。

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

I have come to this page multiple times to get the answer, and while all the existing answers were super helpful, they did not solve my problem exactly. 我多次来到这个页面得到答案,虽然所有现有的答案都非常有用,但他们并没有完全解决我的问题。

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

Basically I found that the 'zoom_changed' event prevented the UI of the map from "skipping" which happened when i waited for the 'idle' event. 基本上我发现'zoom_changed'事件阻止了地图的UI“跳过”,这是在我等待“空闲”事件时发生的。

Hope this helps somebody! 希望这有助于某人!

I've just fixed this by setting maxZoom in advance, then removing it afterwards. 我刚刚通过提前设置maxZoom来修复此问题,然后将其删除。 For example: 例如:

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

If I'm not mistaken, I'm assuming you want all your points to be visible on the map with the highest possible zoom level. 如果我没弄错的话,我假设您希望所有的点在地图上以最高可能的缩放级别显示。 I accomplished this by initializing the zoom level of the map to 16 (not sure if it's the highest possible zoom level on V3). 我通过将地图的缩放级别初始化为16来完成此操作(不确定它是否是V3上可能的最高缩放级别)。

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

Then after that I did the bounds stuff: 之后我做了界限:

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

Result: Success! 结果:成功!

I use: 我用:

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

This will use the smaller of 24 and the necessary zoom level according to your code, however it probably changes the zoom anyway and doesn't care about how much you zoomed out. 这将根据您的代码使用较小的24和必要的缩放级别,但它可能会改变缩放,并不关心您缩小了多少。

I had the same issue and I was able to solve it using the following code. 我有同样的问题,我能够使用以下代码解决它。 This listener ( google.maps.addListenerOnce() ) event will only get fired once, right after map.fitBounds() is executed. 只有在执行map.fitBounds()之后map.fitBounds()触发此侦听器( google.maps.addListenerOnce() )事件。 So, there is no need to 所以,没有必要

  1. Keep track of and manually remove the listener, or 跟踪并手动删除监听器,或
  2. Wait until the map is idle . 等到地图idle

It sets the appropriate zoom level initially and allows the user to zoom in and out past the initial zoom level because the event listener has expired. 它最初设置适当的缩放级别,并允许用户放大和缩小超过初始缩放级别,因为事件侦听器已过期。 For example, if only google.maps.addListener() was called, then the user would never be able to zoom-in past the stated zoom level (in the case, 4). 例如,如果仅调用google.maps.addListener() ,则用户将永远无法放大超过规定的缩放级别(在这种情况下为4)。 Since we implemented google.maps.addListenerOnce() , the user will be able to zoom to any level he/she chooses. 由于我们实施了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) 
   }
});

Had the same problem, needed to fit many markers on the map. 有同样的问题,需要在地图上放置许多标记。 This solved my case: 这解决了我的情况:

  1. Declare bounds 声明边界
  2. Use scheme provided by koderoid (for each marker set bounds.extend(objLatLng) ) 使用koderoid提供的方案(对于每个标记集bounds.extend(objLatLng)
  3. Execute fitbounds AFTER map is completed: 地图完成后执行适合的地方:

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

I've found a solution that does the check before calling fitBounds so you don't zoom in and suddenly zoom out 我找到了一个在调用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);
}

You'll have to play around with the minLatSpan variable a bit to get it where you want. 您必须稍微使用minLatSpan变量来获取它想要的位置。 It will vary based on both zoom-level and the dimensions of the map canvas. 它将根据缩放级别和地图画布的尺寸而变化。

You could also use longitude instead of latitude 您也可以使用经度而不是纬度

Please try this: 请试试这个:

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

I saw many incorrect or too complicated solutions, so decided to post a working, elegant solution . 我看到许多不正确或太复杂的解决方案,所以决定发布一个有效的,优雅的解决方案

The reason setZoom() doesn't work as you expect is that fitBounds() is asynchronous, so it gives no guarantee that it would immediately update the zoom, but your call to setZoom() relies on that. setZoom()无法正常工作的原因是fitBounds()是异步的,所以它不能保证它会立即更新缩放,但是你对setZoom()调用依赖于它。

What you might consider is setting the minZoom map option before calling fitBounds() and then clearing it after it completes (so that users can still zoom out manually if they want to): 您可以考虑在调用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);

In addition, if you want to also limit the max zoom, you can apply the same trick with the maxZoom property. 此外,如果您还想限制最大缩放,可以使用maxZoom属性应用相同的技巧。

See the MapOptions docs . 请参阅MapOptions文档

this work's for me with API v3 but with setting fixed zoom: 这项工作对我来说是API v3,但设置固定缩放:

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

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

In this function, you need to dynamically add metadata to store the geometry type only because the function accepts any geometry. 在此函数中,您需要动态添加元数据以存储几何类型,因为该函数接受任何几何。

"fitGeometries" is a JSON function extending a map object. “fitGeometries”是一个扩展地图对象的JSON函数。

"geometries" is an generic javascript array not an MVCArray(). “geometry”是一个通用的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);
},

I use this to ensure the zoom level does not exceed a set level so that I know satellite images will be available. 我使用它来确保缩放级别不超过设定级别,以便我知道卫星图像可用。

Add a listener to the zoom_changed event. zoom_changed事件添加侦听器。 This has the added benefit of controlling the zoom control on the UI also. 这还具有控制UI上的缩放控制的额外好处。

Only execute setZoom if you need to, so an if statement is preferable to Math.max or to Math.min 如果需要,只执行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);

To prevent zooming out too far: 为防止缩小太远:

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

Like me, if you are not willing to play with listeners, this is a simple solution i came up with: Add a method on map which works strictly according to your requirements like this one : 像我一样,如果你不愿意和听众一起玩,这是我提出的一个简单的解决方案:在地图上添加一个严格按照你的要求工作的方法,如下所示:

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

then you may call map.fitLmtdBounds(bounds) instead of map.fitBounds(bounds) to set the bounds under defined zoom range... or map.fitLmtdBounds(bounds,3,5) to override the zoom range.. 然后你可以调用map.fitLmtdBounds(bounds)而不是map.fitBounds(bounds)来设置定义的缩放范围下的边界...或map.fitLmtdBounds(bounds,3,5)来覆盖缩放范围。

Please try this. 请试试这个。

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

If this will helpful to you. 如果这对你有帮助。

All the best 祝一切顺利

I don't like to suggest it, but if you must try - first call 我不想建议,但如果你必须尝试 - 先打电话

gmap.fitBounds(bounds);

Then create a new Thread/AsyncTask, have it sleep for 20-50ms or so and then call 然后创建一个新的Thread / AsyncTask,让它休眠20-50ms左右,然后调用

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

from the UI thread (use a handler or the onPostExecute method for AsyncTask). 来自UI线程(使用处理程序或AsyncTask的onPostExecute方法)。

I don't know if it works, just a suggestion. 我不知道它是否有效,只是一个建议。 Other than that you'd have to somehow calculate the zoom level from your points yourself, check if it's too low, correct it and then just call gmap.setZoom(correctedZoom) 除此之外,你必须以某种方式自己计算你的点的缩放级别,检查它是否太低,纠正它然后只需调用gmap.setZoom(correctedZoom)

After calculation of the boundries you can check the distance between upper left and down right corner; 计算边界后,您可以检查左上角和右下角之间的距离; then you can understand the zoom level by testing the distance (if distance is too far zoom level would be low) then you can select wheter using setbound method or setZoom.. 然后你可以通过测试距离来理解缩放级别(如果距离太远,缩放级别会很低),那么你可以使用setbound方法或setZoom来选择。

If 'bounds_changed' is not firing correctly (sometimes Google doesn't seem to accept coordinates perfectly), then consider using 'center_changed' instead. 如果'bounds_changed'未正确触发(有时Google似乎不完全接受坐标),那么请考虑使用'center_changed'。

The 'center_changed' event fires every time fitBounds() is called, although it runs immediately and not necessarily after the map has moved. 每次调用fitBounds()时都会触发'center_changed'事件,尽管它会立即运行,而不一定在地图移动后运行。

In normal cases, 'idle' is still the best event listener, but this may help a couple people running into weird issues with their fitBounds() calls. 在正常情况下,'idle'仍然是最好的事件监听器,但这可能会帮助一些人通过fitBounds()调用遇到奇怪的问题。

See google maps fitBounds callback 请参阅google maps fitBounds回调

To chime in with another solution - I found that the "listen for bounds_changed event and then set new zoom" approach didn't work reliably for me. 为了与另一个解决方案联系 - 我发现“监听bounds_changed事件然后设置新的缩放”方法对我来说并不可靠。 I think that I was sometimes calling fitBounds before the map had been fully initialized, and the initialization was causing a bounds_changed event that would use up the listener, before fitBounds changed the boundaries and zoom level. 我认为在地图完全初始化之前我有时会调用fitBounds ,并且在fitBounds更改边界和缩放级别之前,初始化导致了一个使用侦听器的bounds_changed事件。 I ended up with this code, which seems to work so far: 我最终得到了这个代码,到目前为止似乎工作:

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

For me the easiest solution was this: 对我来说,最简单的解决方案就是:

map.fitBounds(bounds);

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

All I did is: 我所做的就是:

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

And it works on V3 API. 它适用于V3 API。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM