10

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

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

谢谢!

4

12 回答 12

11

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

map.fitBounds(bounds);
map.panToBounds(bounds);
于 2011-09-06T22:29:52.873 回答
10

问题是这样的:我们设置

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

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

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
}
于 2012-04-24T16:13:18.503 回答
7

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

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

于 2010-10-11T16:05:59.570 回答
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 已经重新编程了该功能,或者......我需要有关您的代码的更多信息。

于 2010-11-04T03:04:32.393 回答
4

帮助我的是使用 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);
    }
}
于 2018-07-10T16:55:23.377 回答
3

当使用新标记在同一张地图上第二次调用 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);
}
于 2013-10-11T22:47:31.293 回答
2

事实证明,当您调用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);
于 2013-04-12T15:24:48.883 回答
1

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

(这使用了 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() 检查。

于 2014-01-06T01:36:38.593 回答
1

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

请注意,上述方法不会删除标记。它从地图中删除标记。如果您希望删除标记,则应将其从地图中删除,然后将标记本身设置为空。

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

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

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

我的解决方案是跟踪单独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)
    }
  }
})

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

任斯

于 2020-10-22T10:57:51.630 回答
0
map.setZoom(10);

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

于 2010-07-15T04:18:12.610 回答
0
fitBounds: function(bounds, mapId)
    {
        //bounds: bounds, id: map id
        if (bounds==null) return false;
        maps[mapId].fitBounds(bounds);
    },  

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

于 2011-03-13T14:48:05.210 回答
0

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

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

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

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

.google-map.loaded {
    height: 400px;
}

于 2020-01-23T15:58:52.030 回答