6

我有一个动态图块集,我不想让平移超出其范围。

下面的代码让我很接近,但用户仍然可以在严格范围之外水平滚动,因为它使用地图中心进行比较

var strictBounds = new google.maps.LatLngBounds(
 new google.maps.LatLng(sw_lat, sw_lon), 
 new google.maps.LatLng(ne_lat, ne_lon)
);

google.maps.event.addListener(map, 'drag', function() 
{
  if (strictBounds.contains(map.getCenter())) return;

 // We're out of bounds - Move the map back within the bounds

 var c = map.getCenter(),
     x = c.lng(),
     y = c.lat(),
     maxX = strictBounds.getNorthEast().lng(),
     maxY = strictBounds.getNorthEast().lat(),
     minX = strictBounds.getSouthWest().lng(),
     minY = strictBounds.getSouthWest().lat();

 if (x < minX) x = minX;
 if (x > maxX) x = maxX;
 if (y < minY) y = minY;
 if (y > maxY) y = maxY;

 map.setCenter(new google.maps.LatLng(y, x));
});

怎么了

我想要的是

4

3 回答 3

9

为了快速访问,这里是这个解决方案的 jsfiddle:http: //jsfiddle.net/nYz6k/


假设您对当前检测中心边界的解决方案感到满意,您所要做的就是根据当前地图画布大小限制边界。

您现在得到的结果是,当完全限制时(即纬度和经度都超过边界角),限制边界的每个角落都会出现在地图的中心。

解决方案是实际从边界中删除 x 和 y 偏移,并且仍然能够检查中心(与其他基于边界的检查解决方案相比,这是最有效的解决方案)。

此外,只有在初始化地图和调整窗口大小时,您才必须限制边界,这意味着当您平移时,除了您已经提供的检查方法之外没有额外的处理开销。

不要忘记为地图设置maxZoom属性(根据需要对其进行调整),因为在确定的缩放级别之上,限制边界本身将适合视口,并且没有解决方案。

重要的!使用 'center_changed' 而不是 'drag' 因为 'drag' 具有滑动行为,当您完成拖动并设置中心时,地图仍会沿平移方向滑动。


在您实施该解决方案之前,我建议您查看 Maps API 坐标系和投影的工作原理,因为该解决方案在很大程度上基于它,如果您想对其进行调整,了解这些信息很有用。

https://developers.google.com/maps/documentation/javascript/maptypes并查看自定义地图类型 -> 地图坐标部分。


这是你需要做的。首先,您需要实现 2 个在地理坐标 (LatLng) 和像素坐标之间转换的简短方法。

var fromLatLngToPixel = function (latLng) {
  var point = map.getProjection().fromLatLngToPoint(latLng);
  var zoom = map.getZoom();
  return new google.maps.Point(
    Math.floor(point.x * Math.pow(2, zoom)),
    Math.floor(point.y * Math.pow(2, zoom))
  );
}

var fromPixelToLatLng = function (pixel) {
  var zoom = map.getZoom();
  var point = new google.maps.Point(
    pixel.x / Math.pow(2, zoom),
    pixel.y / Math.pow(2, zoom)
  );
  return map.getProjection().fromPointToLatLng(point);
}

接下来,实现有效限制边界的方法。请注意,您始终必须保留一个存储原始边界的变量,因为每次调整地图画布的大小时,生成的边界都会改变。

为此,假设originalBounds保留您使用 sw_lat、sw_long 等提供的边界,并且此方法修改了shrinkedBounds 。您可以将其重命名为 strictBounds 以仍然在您的方法中工作,但这取决于您。这使用 jQuery 获取画布对象的宽度和高度。

var shrinkBounds = function () {
  zoom = map.getZoom();

  // The x and y offset will always be half the current map canvas
  // width and height respectively
  xoffset = $('#map_canvas').width() / 2;
  yoffset = $('#map_canvas').height() / 2;

  // Convert the bounds extremities to global pixel coordinates
  var pixswOriginal = fromLatLngToPixel(originalBounds.getSouthWest());
  var pixneOriginal = fromLatLngToPixel(originalBounds.getNorthEast());

  // Shrink the original bounds with the x and y offset
  var pixswShrinked = new google.maps.Point(pixswOriginal.x + xoffset, pixswOriginal.y - yoffset);
  var pixneShrinked = new google.maps.Point(pixneOriginal.x - xoffset, pixneOriginal.y + yoffset);

  // Rebuild the shrinkedBounds object with the modified 
  shrinkedBounds = new google.maps.LatLngBounds(
    fromPixelToLatLng(pixswShrinked),
    fromPixelToLatLng(pixneShrinked));
}

接下来,您所要做的就是调用此方法:

  • 地图初始化时一次。请注意,根据您调用该方法的时间,您可能会遇到一些奇怪的错误,因为地图可能尚未初始化它的所有属性。最好的方法是使用 projection_changed 事件。

    google.maps.event.addListener(map, 'projection_changed', function (e) {
      shrinkBounds();
    });
    
  • 每次调整地图画布大小时

     google.maps.event.addListener(map, 'resize', function (e) {
       shrinkBounds();
     });
    

但其中最重要的部分是“resize”事件永远不会因地图容器的编程调整大小而触发,因此每次以编程方式调整画布大小时都必须手动触发它(如果你这样做,但我怀疑你这样做) .

最常见的方法是在调整窗口大小时触发它:

$(window).resize(function () {
  google.maps.event.trigger(map, 'resize');
});

在所有这些之后,您现在可以安全地使用您的方法,但作为 'center_changed' 的处理程序,而不是我之前提到的 'drag' 的处理程序。


我用完整的工作代码设置了一个 jsfiddle。

http://jsfiddle.net/nYz6k/

您可以在左下角看到限制,并显示那个小半标记,它位于边界的 SW 角。西北角也有一个,但自然看不到,因为它显示在位置上方。

于 2012-10-15T14:58:47.577 回答
0

不要使用 map.getCenter() 作为检查,而是使用 map.getBounds()

未经测试,但完成此操作的一种简单方法是检查两个边界的并集是否相同(如果不是,则您的地图边界超出您的严格边界):

var union = strictBounds.union(map.getBounds());
if (strictBounds.equals(union)) { //new map bounds is within strict bounds
于 2012-10-12T20:42:54.453 回答
0

上面的 Tiborg 版本是迄今为止保持边界的最佳版本......我注意到当缩放级别和宽度/高度大于原始边界时会出现一个错误

我修改了他的代码并添加了一个矩形来查看它的实际效果。

var buildBounds = function(sw, ne) {
    var swY = sw.lat();
    var swX = sw.lng();
    var neY = ne.lat();
    var neX = ne.lng();
    if (swY > neY) {
      var cY = (swY + neY) / 2;
      swY = cY;
      neY = cY;
    }
    if (swX > neX) {
      var cX = (swX + neX) / 2;
      swX = cX;
      neX = cX;
    }
    return new google.maps.LatLngBounds(
      new google.maps.LatLng(swY, swX),
      new google.maps.LatLng(neY, neX));
  }

http://jsfiddle.net/p4wgjs6s/

于 2016-08-23T18:36:51.023 回答