Javascript 如何在 Google 地图中的标记上平滑放大?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4752340/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to zoom in smoothly on a marker in Google Maps?
提问by PeanutButterJelly
I'd like to be able to zoom in smoothly on a marker in Google Maps. If one just sets the zoom on double click, the map is suddenly on that zoom level, without any smooth transition.
我希望能够在 Google 地图中的标记上平滑放大。如果只是在双击时设置缩放,地图会突然处于该缩放级别,没有任何平滑过渡。
Zooming in only one level further than the current level, Google Maps shows a nice smooth transition. So it must be possible to zoom in smoothly for more than one level, but how?
仅比当前级别再放大一级,Google 地图显示出良好的平滑过渡。所以一定可以平滑放大一个以上的级别,但是如何呢?
回答by Herman Schaaf
As luck would have it, I wanted to achieve the same effect recently, and found a solution, which I made a postabout. Basically, just setting a timeout for each transition isn't enough, because it could easily result in a 'start-stop' kind of zoom if Google's zoom effect isn't finished yet, or has long finished.
幸运的是,我最近想达到同样的效果,并找到了一个解决方案,我发表了一篇文章。基本上,仅仅为每个过渡设置一个超时是不够的,因为如果 Google 的缩放效果尚未完成或早已完成,它很容易导致“开始-停止”类型的缩放。
As Martin mentioned, there are some disadvantages to this, which I won't reiterate. Whether you use this in the end is your choice, and depends largely on your users' CPU power and/or browser. It is a nice effect though, and sure to impress some, when used wisely.
正如马丁提到的,这有一些缺点,我不会重申。您最终是否使用它是您的选择,并且在很大程度上取决于您用户的 CPU 能力和/或浏览器。不过,这是一个不错的效果,如果使用得当,肯定会给一些人留下深刻印象。
My solution was the following:
我的解决方案如下:
// 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
}
}
Basically what it comes down to is adjusting the zoom level by one, listening for the zoom_changed
event, waiting 80ms before adjusting the zoom-level by one again, etc. What's nice about this is that the zoom_changed
event seems to be called after the smooth transition provided by Google Maps, but beforethe actual images are loaded, so it doesn't waste bandwidth too much.
基本上归结为将缩放级别调整为 1,侦听zoom_changed
事件,在再次将缩放级别调整为 1 之前等待 80 毫秒,等等。这件事的好处在于zoom_changed
似乎在提供的平滑过渡之后调用了该事件由谷歌地图,但在实际图像加载之前,所以它不会浪费太多带宽。
The 80ms in the timeout is also a magic number I came up with - you would be well-advised to do a more thorough test and see what works on different systems and browsers, and perhaps change the algorithm slightly based on your findings or for different systems.
超时中的 80 毫秒也是我想出的一个神奇数字 - 建议您进行更彻底的测试,看看哪些在不同的系统和浏览器上有效,并可能根据您的发现或针对不同的情况稍微更改算法系统。
It's probably also not necessary to add and remove the listener every time, but you can make that small improvement yourself if you so wish.
可能也没有必要每次都添加和删除侦听器,但是如果您愿意,您可以自己进行微小的改进。
回答by Igor Mukhin
This one worked for me nicely:
这个对我很有效:
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);
}
}
回答by Martin Jespersen
You could try to use a setInterval to zoom in one level at a time, and clear it when you reach your desired level.
您可以尝试使用 setInterval 一次放大一个级别,并在达到所需级别时将其清除。
The problem with this is that the interval that will make it work is entirely dependent on the cpu and bandwidth of the users machine (how fast can it load and render the new set of image tiles).
这样做的问题是让它工作的时间间隔完全取决于用户机器的 CPU 和带宽(它加载和渲染新的图像块集的速度有多快)。
Tbh, i'm not sure it can be done so that it will work great in every situation, but a small interval between zoom levels might help a bit.
Tbh,我不确定它是否可以完成,以便在每种情况下都能很好地工作,但是缩放级别之间的小间隔可能会有所帮助。
A few things to keep in mind tho:
需要记住的几件事:
- this will put a lot more stress on the users cpu and bandwidth than going directly to the chosen zoomlevel
- the user will have to wait until this is done to start interacting with the map, which could easily become a very bad user experience.
- 与直接进入所选缩放级别相比,这会给用户的 CPU 和带宽带来更多压力
- 用户将不得不等到这完成后才能开始与地图交互,这很容易成为非常糟糕的用户体验。
Those two and probably other reasons are why google didn't build the kind of zoom you wish into maps in the first place - because it's a bad idea...
这两个原因可能还有其他原因,这就是为什么谷歌没有首先在地图中构建您希望的那种缩放 - 因为这是一个坏主意......
回答by Dexy86
@Herman Schaaf Your solution is great but when you double click it skips a few zooms :D So I have made a solution + smoothZoom out I can't take all the credit I have edited JesseDobbelaere's code from jsfiddle.net It's a mix of yours and Jesse's code.
@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);
}
}
}
}
I have made few more variables like timeOut and maxZoomIn Out... you can find full code on jsfiddle http://jsfiddle.net/dexy86/9afy9/
我已经制作了更多的变量,如 timeOut 和 maxZoomIn Out ... 你可以在 jsfiddle http://jsfiddle.net/dexy86/9afy9/上找到完整的代码
回答by Debs
I've tried the alternatives provided above, however, whenever I view the transition in a desktop browser or mobile app, it all occurs instantly, or at least, within a period of time which is imperceptible to the eye due to the time between each loop iteration, at least on the hardware I've trialled it on.
我已经尝试了上面提供的替代方案,但是,每当我在桌面浏览器或移动应用程序中查看过渡时,它都会立即发生,或者至少在由于每个时间之间的时间而肉眼无法察觉的时间段内发生循环迭代,至少在我试用过的硬件上是这样。
I used the same loop as the other methods, but altered the timeout so that the zoom occurred more quickly when the zoom level was higher, and more slowly when it was lower, so the results were more visible.
我使用了与其他方法相同的循环,但更改了超时时间,以便在缩放级别较高时缩放发生得更快,而在缩放级别较低时发生得更慢,因此结果更加明显。
Instead of using a fixed timeout period, I set the first timeout to 0, and then subsequent timeouts to the following quick and dirty equation
我没有使用固定的超时时间,而是将第一个超时设置为 0,然后将后续超时设置为以下快速而肮脏的等式
((1+ currentZoom) / maxZoom) * 500;
In code I assumed the max zoom as 18, but you can use maxZoomto find out what the zoom level is for a given lat/long. My code is:
在代码中,我假设最大缩放为 18,但您可以使用maxZoom找出给定纬度/经度的缩放级别。我的代码是:
timeout = (1+map.getZoom() / 18) * 500;
回答by Chaman Saini
This will zoom smoothly on desired location. Try adding these lines:
这将在所需位置平滑缩放。尝试添加这些行:
LatLng latLng = new LatLng(lat,lng);
map.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, ZOOM_FACTOR));