如何在Google地图中的标记上平滑放大?

时间:2011-01-20 20:42:19

标签: javascript google-maps

我希望能够在Google地图中的标记上平滑放大。如果只是双击设置缩放,则地图突然在该缩放级别上,没有任何平滑过渡。

缩放比当前级别更进一级,Google地图显示了一个很好的平滑过渡。因此,必须可以平滑放大多个级别,但如何?

6 个答案:

答案 0 :(得分:56)

幸运的是,我想最近达到同样的效果,并找到了一个解决方案,我做了a post。基本上,仅为每次转换设置超时是不够的,因为如果谷歌的缩放效果尚未完成,或者已经很久完成,它可能很容易导致“开始 - 停止”类型的缩放。

正如马丁所说,这有一些不利之处,我不会重申。您最终是否使用它是您的选择,并且在很大程度上取决于您的用户的CPU功率和/或浏览器。这是一个很好的效果,当明智地使用时肯定会留下深刻的印象。

我的解决方案如下:

// example marker:
var marker = new google.maps.Marker({
    map: map, 
    position: new google.maps.LatLng(-20.3,30.3)
});


// add the double-click event listener
google.maps.event.addListener(marker, 'dblclick', function(event){
    map = marker.getMap();    
    map.setCenter(overlay.getPosition()); // set map center to marker position
    smoothZoom(map, 12, map.getZoom()); // call smoothZoom, parameters map, final zoomLevel, and starting zoom level
});


// the smooth zoom function
function smoothZoom (map, max, cnt) {
    if (cnt >= max) {
        return;
    }
    else {
        z = google.maps.event.addListener(map, 'zoom_changed', function(event){
            google.maps.event.removeListener(z);
            smoothZoom(map, max, cnt + 1);
        });
        setTimeout(function(){map.setZoom(cnt)}, 80); // 80ms is what I found to work well on my system -- it might not work well on all systems
    }
}  

基本上它归结为将缩放级别调整为1,监听zoom_changed事件,等待80ms然后再将缩放级别调整为1,等等。这样做的好处是{{{ 1}}事件似乎是在Google地图提供的平滑过渡之后调用的,但之前加载了实际图像,因此不会浪费太多带宽。

超时中的80毫秒也是我想出的一个神奇数字 - 建议您进行更彻底的测试,看看哪些在不同的系统和浏览器上有效,并且可能会根据您的发现略微改变算法或者用于不同的系统。

每次都可能没有必要添加和删除监听器,但是如果你愿意,你可以自己做一些小的改进。

答案 1 :(得分:8)

这个很适合我:

function animateMapZoomTo(map, targetZoom) {
    var currentZoom = arguments[2] || map.getZoom();
    if (currentZoom != targetZoom) {
        google.maps.event.addListenerOnce(map, 'zoom_changed', function (event) {
            animateMapZoomTo(map, targetZoom, currentZoom + (targetZoom > currentZoom ? 1 : -1));
        });
        setTimeout(function(){ map.setZoom(currentZoom) }, 80);
    }
}

答案 2 :(得分:3)

您可以尝试使用setInterval一次放大一个级别,并在达到所需级别时将其清除。

这个问题是使其工作的间隔完全取决于用户机器的CPU和带宽(它加载和渲染新的图像块集的速度有多快)。

Tbh,我不确定它是否可以在任何情况下都能正常工作,但缩放级别之间的小间隔可能会有所帮助。

要记住的一些事情:

  1. 这会对用户cpu和带宽造成更大的压力,而不是直接转到所选的zoomlevel
  2. 用户必须等到完成此操作才能开始与地图进行交互,这很容易成为非常糟糕的用户体验。
  3. 这两个以及可能是其他原因是谷歌为什么不首先在地图中构建你想要的那种变焦 - 因为这是一个坏主意......

答案 3 :(得分:2)

@Herman Schaaf 你的解决方案很棒但是当你双击它时会跳过几个缩放 :d 所以我做了一个解决方案+ smoothZoom了 我无法从jsfiddle.net上编辑JesseDobbelaere的代码 这是你和杰西的代码的混合。

function smoothZoom(map, level, cnt, mode)
{
    if(mode == true)
    {
        if (cnt >= level) {
            return;
        }
        else
        {
            if((maxZoomOut + 2) <= cnt)
            {
                var z = google.maps.event.addListener(map, 'zoom_changed', function(event)
                {
                    google.maps.event.removeListener(z);
                    map.setCenter(marker.getPosition());
                    smoothZoom(map, level, cnt + 1, true);
                });
                setTimeout(function(){map.setZoom(cnt);}, timeOut);
            }
            else
            {
                map.setZoom(cnt);
                smoothZoom(map, level, cnt + 1, true);
            }
        }
    }
    else 
    {
        if (cnt < level) {
            return;
        }
        else
        {
            var z = google.maps.event.addListener(map, 'zoom_changed', function(event)
            {
                google.maps.event.removeListener(z);
                map.setCenter(marker.getPosition());
                smoothZoom(map, level, cnt - 1, false);
            });
            if(maxZoomIn - 2 <= cnt)
            {
                map.setZoom(cnt);
            }
            else
            {
                setTimeout(function(){map.setZoom(cnt);}, timeOut);
            }
        }
    }
}    

我做了更多的变量,比如timeOut和maxZoomIn Out ...... 你可以在jsfiddle上找到完整的代码 http://jsfiddle.net/dexy86/9afy9/

答案 4 :(得分:0)

我已尝试过上面提供的替代方案,但是,每当我在桌面浏览器或移动应用中查看转换时,这一切都会立即或至少在一段时间内发生,而这段时间是眼睛无法察觉的到每个循环迭代之间的时间,至少在我试用过的硬件上。

我使用与其他方法相同的循环,但更改了超时,以便在缩放级别较高时更快地发生缩放,而在较低时更慢,因此结果更加明显。

我没有使用固定的超时时间,而是将第一个超时设置为0,然后将后续超时设置为以下快速和脏的等式

((1+ currentZoom) / maxZoom) * 500;

在代码中我假设最大缩放为18,但您可以使用maxZoom找出给定纬度/经度的缩放级别。我的代码是:

timeout = (1+map.getZoom() / 18) * 500;

答案 5 :(得分:-1)

这将在所需位置平滑缩放。尝试添加以下行:

LatLng latLng = new LatLng(lat,lng);
map.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, ZOOM_FACTOR));