从Google地图视口范围中排除叠加元素 [英] Exclude overlaid element from Google Maps viewport bounds

查看:114
本文介绍了从Google地图视口范围中排除叠加元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用Google Maps API v3在网站上创建内嵌地图。在它的容器元素中,我也有一个绝对定位的覆盖图,它显示了一些细节信息,可以在地图上视觉悬停。根据上下文确定,此元素可能会增长到整个地图元素的大小。

所有这些工作都很好,但Maps实例当然仍然认为地图的叠加部分是地图的有效可用部分。这意味着,特别是如果叠加层位于最大高度时, setCenter 不会集中在可见中心,并且使用 DirectionsRenderer 部分位于叠加层下。



查看此图片:

是否有限制 的方法视口到蓝色区域,所以 setCenter 居中在箭头尖端, setBounds 适合蓝色部分?

解决方案

我已经设法实现了一个可接受的功能解决方案。




  • 每个 Map 对象都有 Projection ,它可以在LatLng点之间转换为地图点。
  • 地图指向一个 Projection 用于计算的code>用于'世界'坐标,我它们是缩放级别为0的世界地图上的像素。

  • 每个缩放级别的精确倍数都是显示的像素数量的两倍。这意味着给定映射点中的像素数等于 2 ^ zoom



下面的示例假定右侧有一个300px宽的侧边栏 - 适应其他边框应该很容易。

居中



使用这些知识,编写一个偏离中心的自定义函数变得非常简单:

 函数setCenter(latlng )
{
var z = Math.pow(2,map.getZoom());
var pnt = map.getProjection()。fromLatLngToPoint(latlng);
map.setCenter(map.getProjection()。fromPointToLatLng(
google.maps.Point(pnt.x + 150 / z,pnt.y)));

$ / code>

这里的关键是 z 变量,以及最后一行中的 pnt.x + 150 / z 计算。由于上述假设,这将点移动到以当前缩放级别左侧150像素为中心,并因此补偿右侧侧栏上缺少的300像素。



边界



边界问题远没有那么简单。原因是为了正确抵消这些点,您需要知道缩放级别。重新调整这个不会改变,但是为了适应先前未知的边界,它几乎总是会。由于Google Maps在拟合界限时内部使用了未知边距,因此没有可靠的方法来预测所需的缩放级别。

因此,一种可能的解决方案是调用一个双精度视图,步火箭。首先,在整个地图上调用 fitBounds 。这应该使边界和缩放级别至少几乎正确。然后在此之后,再次调用

下面的示例实现使用 LatLngBounds 对象作为参数进行调用,或者没有参数默认为当前边界。

  function setBounds(bnd,cb)
{
var prj = map.getProjection();
if(!bnd)bnd = map.getBounds();
var ne = prj.fromLatLngToPoint(bnd.getNorthEast()),
sw = prj.fromLatLngToPoint(bnd.getSouthWest());
if(cb)ne.x + =(300 / Math.pow(2,map.getZoom()));
else google.maps.event.addListenerOnce(map,'bounds_changed',
function(){setBounds(bnd,1)});
map.fitBounds(new google.maps.LatLngBounds(
prj.fromPointToLatLng(sw),prj.fromPointToLatLng(ne)));
}

我们首先要做的是获得边界的实际点,因为 cb 未设置,所以我们在 bounds_changed 上安装一次只发生的事件,然后在 fitBounds 完成。这意味着在缩放后,该功能会自动再次调用。第二次调用时,使用 cb = 1 ,然后抵消该框以纠正300像素宽的侧边栏。



在某些情况下,这可能会导致轻微的非动画效果,但在实践中,我只看到这发生在真正垃圾按钮导致适合操作时。它运行得非常好,否则。



希望这可以帮助某人:)


I am using Google Maps API v3 to create an inline map on a website. In its container element, I also have an absolute positioned overlay which shows some detail information, visually hovering over the map. Determining on context this element may grow up to the size of the entire map element.

All this is working fine, however the Maps instance of course still considers the overlaid part of the map a valid usable part of the map. This means that, especially if the overlay is at maximum height, setCenter doesn't focus on the visible center, and routes drawn with DirectionsRenderer are partially underneath the overlay.

See this image:

Is there a way to limit the actual viewport to the blueish area, so that setCenter centers on the arrow tip and setBounds fits to the blue part?

解决方案

I have managed to implement an acceptably functional workaround for the time being.

Some general notes which are good to know:

  • Every Map object has a Projection, which can convert between LatLng points to map points.
  • The map points a Projection uses for calculation are in 'world' coordinates, meaning they are pixels on the world map at zoom level 0.
  • Every zoom level exactly doubles the number of pixels shown. This means that the number of pixels in a given map point equals 2 ^ zoom.

The samples below assume a 300px wide sidebar on the right - adapting to other borders should be easy.

Centering

Using this knowledge, it becomes trivial to write a custom function for off-center centering:

function setCenter(latlng)
{
    var z = Math.pow(2, map.getZoom());
    var pnt = map.getProjection().fromLatLngToPoint(latlng);
    map.setCenter(map.getProjection().fromPointToLatLng(
                    new google.maps.Point(pnt.x + 150/z, pnt.y)));
}

The crucial bits here are the z variable, and the pnt.x + 150/z calculation in the final line. Because of the above assumptions, this moves the point to center on 150 pixels to the left for the current zoom level, and as such compensates for the missing 300 pixels on the right sidebar.

Bounding

The bounds issue is far less trivial. The reason for this is that to offset the points correctly, you need to know the zoom level. For recentering this doesn't change, but for fitting to previously unknown bounds it nearly always will. Since Google Maps uses unknown margins itself internally when fitting to bounds, there is no reliable way to predict the required zoom level.

Thus a possible solution is to invoke a two-step rocket. First off, call fitBounds with the entire map. This should make the bounds and zoom level at least nearly correct. Then right after that, do a second call to fitBounds corrected for the sidebar.

The following sample implementation should be called with a LatLngBounds object as parameter, or no parameters to default to the current bounds.

function setBounds(bnd, cb)
{
    var prj = map.getProjection();
    if(!bnd) bnd = map.getBounds();
    var ne = prj.fromLatLngToPoint(bnd.getNorthEast()),
        sw = prj.fromLatLngToPoint(bnd.getSouthWest());
    if(cb) ne.x += (300 / Math.pow(2, map.getZoom()));
    else google.maps.event.addListenerOnce(map,'bounds_changed',
        function(){setBounds(bnd,1)});
    map.fitBounds(new google.maps.LatLngBounds(
        prj.fromPointToLatLng(sw), prj.fromPointToLatLng(ne)));
}

What we do here at first is get the actual points of the bounds, and since cb isn't set we install a once-only event on bounds_changed, which is then fired after the fitBounds is completed. This means that the function is automatically called a second time, after the zoom has been corrected. The second invocation, with cb=1, then offsets the box to correct for the 300 pixel wide sidebar.

In certain cases, this can lead to a slight off-animation, but in practice I've only seen this occur when really spamclicking on buttons causing a fit operation. It's running perfectly well otherwise.

Hope this helps someone :)

这篇关于从Google地图视口范围中排除叠加元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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