动态谷歌地图与自定义瓷砖,防止重复锅 [英] Dynamic google map with custom tiles prevent repeating pan

查看:79
本文介绍了动态谷歌地图与自定义瓷砖,防止重复锅的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



下面的代码让我接近,但用户仍然可以滚动。

我有一个动态图块集,我不希望允许在其范围外进行平移。横向超出严格限制,因为它使用地图中心进行比较

  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;

//我们超出界限 - 将地图移回界限内

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

if (y> maxX)x = maxX;
if(y if(y> maxY)y = maxY;

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



解决方案

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






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



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

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

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



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



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




在您实施解决方案之前,我建议您查看Maps API坐标系和投影如何工作,因为此解决方案主要基于此解决方案,并且如果你想调整它,知道这些信息是有用的。



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






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

  var fromLatLngToPixel = function latLng){
var point = map.getProjection()。fromLatLngToPoint(latLng);
var zoom = map.getZoom();
返回新的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)
);
返回map.getProjection()。fromPointToLatLng(point);
}

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



为此,让我们假设 originalBounds 可以保留您通过sw_lat,sw_long等提供的边界, shrinkedBounds 通过此方法进行修改。您可以将其重命名为strictBounds,以便在您的方法中仍能正常工作,但取决于您。这使用jQuery获取canvas对象的宽度和高度。

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

// x和y偏移总是当前地图的一半
//宽度和高度
xoffset = $('#map_canvas')。width() / 2;
yoffset = $('#map_canvas')。height()/ 2;

//将边界极限转换为全局像素坐标
var pixswOriginal = fromLatLngToPixel(originalBounds.getSouthWest());
var pixneOriginal = fromLatLngToPixel(originalBounds.getNorthEast());

//用x和y偏移缩小原始边界
var pixswShrinked = new google.maps.Point(pixswOriginal.x + xoffset,pixswOriginal.y - yoffset);
var pixneShrinked = new google.maps.Point(pixneOriginal.x - xoffset,pixneOriginal.y + yoffset);

//使用修改后的
重建shrinkedBounds对象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事件永远不会触发地图容器的程序化调整大小,因此每次以编程方式调整画布大小时都必须手动触发它(如果是这样,但我怀疑是否)。

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

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

完成所有这些之后,您现在可以安全地使用您的方法,但作为'center_changed'而不是像前面提到的那样'拖'。






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



http://jsfiddle.net/nYz6k/



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


I have a dynamic tile set where I do NOT want to allow panning outside of its bounds.

The below code gets me close, but the user can still scroll horizontally outside of strict bounds because it uses the map center for comparison

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

解决方案

For quick access, here is the jsfiddle for this solution: http://jsfiddle.net/nYz6k/


Supposed you're happy with the current solution of detecting bounds against the center, all you have to do is to restrict the bounds based on the current map canvas size.

The result that you're getting now is that every corner of the restricting bounds appears on the center of the map when it's full restricting (i.e. both latitude and longitude exceed the bounds corners).

The solution is to actually remove the x and y offset from the bounds, and still be able to check against the center (which is the most efficient solution, compared to other bounds-based checking solutions).

Also, you have to restrict the bounds only when you initialize the map and when the window is resizing, which means that when you pan there is no extra processing overhead besides the check method that you have already provided.

Don't forget to set the maxZoom property for the map (tweak it as needed) because above a determined zoom level the restricting bounds will by themselves fit in the viewport and there's no solution for that.

Important! Use 'center_changed' instead of 'drag' because 'drag' has that sliding behavior that when you finished dragging and set the center, the maps still slides in the direction of the panning.


Before you implement the solution I recommend you to check out how the Maps API coordinate system and projection works, because this solution is heavily based on it, and if you want to tweak it out, it's useful to know this information.

https://developers.google.com/maps/documentation/javascript/maptypes and check out the Custom Map Types -> Map Coordinates section.


Here's what you need to do. First, you need to implement 2 short methods of converting between geographic coordinates (LatLng) and pixel coordinates.

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

Next, implement the method that effectively restricts the bounds. Note that you always have to keep a variable that stores the original bounds, because each time the map canvas is resized, the resulting bounds will change.

For this, let's say originalBounds keeps the bounds you provided with sw_lat, sw_long etc, and shrinkedBounds is modified by this method. You can rename it to strictBounds to still work in your method, but it's up to you. This uses jQuery for getting the width and height of the canvas object.

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

Next, all you have to do is to call this method:

  • once when the map is initialized. Be aware that depending on when you call the method, you may be getting some weird errors because the map might not have yet initialized all it's properties. Best way is to use the projection_changed event.

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

  • every time the map canvas is resized

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

But the most important part of this is that the 'resize' event is never triggered for programmatic resizes of the map container, so you have to trigger it manually every time you resize the canvas programmatically (if you do, but I doubt you do).

The most common way is to trigger it when the window is resized:

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

After all of this, you can now safely use your method, but as a handler for 'center_changed' and not for 'drag' as I've mentioned earlier.


I set up a jsfiddle with the full working code.

http://jsfiddle.net/nYz6k/

You can see the restricting at the bottom left corner with that little half-marker that shows up, which is positioned in the SW corner of the bounds. There is also one at the NW corner but naturally you can't see it because it's displayed above the position.

这篇关于动态谷歌地图与自定义瓷砖,防止重复锅的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆