带有自定义图块的动态谷歌地图可防止重复播放

时间:2012-10-10 17:31:22

标签: google-maps

我有一个动态磁贴集,我不希望允许在其边界之外进行平移。

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

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

What is happening

What I want

3 个答案:

答案 0 :(得分:9)

为了快速访问,以下是此解决方案的jsfiddle:http://jsfiddle.net/nYz6k/


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

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

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

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

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

重要!使用&#39; center_changed&#39;而不是'拖'&#39;因为&#39;拖延&#39;具有滑动行为,当您完成拖动并设置中心时,地图仍然会在平移方向上滑动。


在您实施解决方案之前,我建议您查看Maps API坐标系统和投影的工作原理,因为此解决方案很大程度上基于它,如果您想要调整它,那么了解它是有用的这个信息。

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


这是您需要做的事情。首先,您需要实现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();
     });
    

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

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

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

完成所有这些后,您现在可以安全地使用您的方法,但作为&#39; center_changed&#39;的处理程序。而不是为了拖延&#39;正如我之前提到的那样。


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

http://jsfiddle.net/nYz6k/

您可以在左下角看到限制显示的小半标记,它位于边界的SW角落。在NW角落也有一个,但自然你无法看到它,因为它显示在位置上方。

答案 1 :(得分:0)

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

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

var union = strictBounds.union(map.getBounds());
if (strictBounds.equals(union)) { //new map bounds is within strict bounds

答案 2 :(得分: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/