刷新Google Maps API V3图层

时间:2021-04-11 15:26:07

I've been having trouble getting Google Maps API v3 to update correctly. I've got a javascript timer running that should be refreshing the traffic layer periodically but I'm not seeing it happening.

我一直无法正确地更新Google Maps API v3。我有一个javascript计时器运行应该定期刷新流量层但我没有看到它发生。

As I understand the documentation, I should be able to say something like "layer.setMap(null);" followed by "layer.setMap(map);" to refresh the layer (source: https://developers.google.com/maps/documentation/javascript/reference#TrafficLayer).

据我了解文档,我应该可以说“layer.setMap(null);”接着是“layer.setMap(map);”刷新图层(来源:https://developers.google.com/maps/documentation/javascript/reference#TrafficLayer)。

I know the new map tiles are being downloaded (for example, I can see them in the Resources section of Chrome's dev tools), but the browser isn't rendering them. There is probably something fundamental I'm missing.

我知道正在下载新的地图图块(例如,我可以在Chrome的开发工具的参考资料部分看到它们),但是浏览器没有渲染它们。我可能缺少一些基本的东西。

I've tried several things, to include:

我尝试了几件事,包括:

Is there a way to ensure the browser will render the new images without forcing a full page reload?

有没有办法确保浏览器在不强制重页加载的情况下呈现新图像?

Below is a simplified version of the page (based off of the answer from Google Maps refresh traffic layer).

以下是该页面的简化版本(基于Google地图刷新流量图层的答案)。

<html>
    <head>
        <title>Map Testing</title>
        <script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=weather"></script>
        <script src="http://code.jquery.com/jquery-latest.min.js"></script>

        <script type="text/javascript">
            var map,
                trafficLayer,
                mapTimerHandle;

            $(function() {
                initMap();
                mapTimerHandle = setInterval(refreshMap, 15000);
            });

            function refreshMap() {
                trafficLayer.setMap(null);
                trafficLayer.setMap(map);
            }

            function initMap() {
                var mapDiv = document.getElementById('map');

                map = new google.maps.Map(mapDiv, {zoom: 15, center: new google.maps.LatLng(40.7127, -74.0059)});

                trafficLayer = new google.maps.TrafficLayer();

                trafficLayer.setMap(map);
            }
        </script>
    </head>
    <body style="margin:0px;">
        <div id="map" style="width:100%; height:100%;"></div>
    </body>
</html>

7 个解决方案

#1


22  

Ok, what i've found, and what is mentioned above is that trafficLayer.setMap(null) and trafficLayer.setMap(map) - just switches tiles with drawn traffic to tiles without traffic. Also map.setZoom(map.getZoom()) (and any other variaties of zoom) doesn't work because tiles are already in cache and google scripts don't even try to download fresh ones from server.

好吧,我发现了什么,以及上面提到的是trafficLayer.setMap(null)和trafficLayer.setMap(map) - 只需将绘制流量的切片切换到没有流量的切片。另外map.setZoom(map.getZoom())(和任何其他缩放变量)不起作用,因为磁贴已经在缓存中,而谷歌脚本甚至不尝试从服务器下载新的。

Also, seems that if you just open google maps and turn on traffic layer it's not refreshing! Such a lame, google!

此外,似乎如果你只是打开谷歌地图并打开流量层,它就不会令人耳目一新!这样的跛脚,谷歌!

So we have to find a different way to solve it.

所以我们必须找到一种不同的解决方法。

First thought is to use window.location.reload(true) wich will flush image cache - and we see it works. Not a good way to go though - reloading whole page taking too long. How about reloading images? Let's try!

首先想到的是使用window.location.reload(true)将刷新图像缓存 - 我们看到它的工作原理。不是一个好方法 - 重新加载整个页面需要太长时间。如何重新加载图像?咱们试试吧!

function reloadTiles() {
    var tiles = $("#map-canvas").find("img");
    for (var i = 0; i < tiles.length; i++) {
        var src = $(tiles[i]).attr("src");
        if (/googleapis.com\/vt\?pb=/.test(src)) {              
            var new_src = src.split("&ts")[0] + '&ts=' + (new Date()).getTime();
            $(tiles[i]).attr("src", new_src);                                                   
        }               
    }
}   

And we call this function every N seconds: setInterval(reloadTiles, 5000)

我们每N秒调用一次这个函数:setInterval(reloadTiles,5000)

some comments:

一些评论:

$("#map-canvas").find("img") - will grab all images from your map container (map-canvas in my case). Not all are tiles so we need to filter them out - i've noticed that tiles are loaded from domains like mts(digit).googleapis.com/vt?pb=(hella long param). Other map images are loaded from maps.gstatic.com.

$(“#map-canvas”)。find(“img”) - 将从地图容器中获取所有图像(在我的情况下为map-canvas)。并非所有都是瓷砖所以我们需要将它们过滤掉 - 我注意到瓷砖是从像mts(数字)这样的域加载的.googleapis.com / vt?pb =(hella long param)。其他地图图像从maps.gstatic.com加载。

So we get tile images, add bogus parameter and change their src. Profit!

所以我们得到平铺图像,添加虚假参数并更改其src。利润!

Btw, i've found that traffic really changes in real time - tiles may be different each second.

顺便说一句,我发现交通确实实时变化 - 每秒的瓷砖可能会有所不同。

Edit

编辑

Oh, sorry, here's working sample. And it's a snowy Moscow with a huge traffic :)

哦,对不起,这是工作样本。这是一个多雪的莫斯科,拥有巨大的交通:)

#2


1  

I use the traffic layer quite a bit. I have added a button to toggle the layer but found to hide it I had to set the layer itself as null.

我使用流量层相当多。我添加了一个按钮来切换图层但发现隐藏它我必须将图层本身设置为null。

My code to show the layer:

我的代码显示图层:

if (MapManager.trafficLayer == null)
{
      MapManager.trafficLayer = new google.maps.TrafficLayer();
}
MapManager.trafficLayer.setMap(MapManager.map);

Then to go and hide the layer again:

然后再次隐藏图层:

MapManager.trafficLayer.setMap(null);
MapManager.trafficLayer = null;

In an ideal way what you suggested above would be better but for me this seems to work just fine.

以理想的方式,你上面建议的会更好,但对我来说这似乎工作得很好。

#3


1  

The way you are refreshing the layer is working fine.

刷新图层的方式工作正常。

Here is your code edited to prove this:

以下是您的代码编辑,以证明这一点:

<html>
<head>
    <title>Map Testing</title>
    <script type="text/javascript" src="https://maps.googleapis.com/maps/api   /js?v=3.exp&libraries=weather"></script>
    <script src="http://code.jquery.com/jquery-latest.min.js"></script>

    <script type="text/javascript">
        var map, trafficLayer;          
        var vis = false;

        $(function ()
        {
            initMap();            
        });

        function refreshMap()
        {               
            if (vis)            
            {
                trafficLayer.setMap(null)
                vis = false;
            }
            else
            {
                trafficLayer.setMap(map);
                vis = true;
            }            
        }

        function initMap()
        {
            var mapDiv = document.getElementById('map');
            map = new google.maps.Map(mapDiv, {zoom: 15, center: new google.maps.LatLng(40.7127, -74.0059)});

            trafficLayer = new google.maps.TrafficLayer();

            trafficLayer.setMap(map);
            vis = true;
            setInterval(function ()
            {
                refreshMap();
            }, 3000);
        }
    </script>
</head>
<body style="margin:0px;">
    <div id="map" style="width:100%; height:100%;"></div>
</body>

I added a visibility property to toggle the layer every 2 seconds. You will notice how it turns on and off. Because the way you called it I think it did not have enough time to refresh.

我添加了一个visibility属性来每隔2秒切换一次图层。你会注意到它是如何打开和关闭的。因为你打电话的方式我认为它没有足够的时间来刷新。

Also I added the interval in the initMap function after the layer's map was first set.

在首次设置图层映射后,我还在initMap函数中添加了区间。

Hope that helps.

希望有所帮助。

EDIT. Just to add to this, where the traffic is real time where supported, in some cases its based on historic data and will not refresh over a short period. But the traffic data is fetched at the time of each request as specified in the docs: https://developers.google.com/maps/documentation/javascript/trafficlayer#traffic_layer

编辑。只是为了补充这一点,流量是实时支持的地方,在某些情况下,它基于历史数据,并且不会在短时间内刷新。但是,在文档中指定的每个请求时都会提取流量数据:https://developers.google.com/maps/documentation/javascript/trafficlayer#traffic_layer

#4


1  

try this code snippet, may be this help you out

试试这个代码片段,可能会帮到你

function init() {
    var map,
    trafficLayer,
    mapTimerHandle;

    var mapDiv = document.getElementById('map');

    map = new google.maps.Map(mapDiv, {
        zoom: 14,
        center: new google.maps.LatLng(40.7127, -74.0059)
    });

    trafficLayer = new google.maps.TrafficLayer();
    trafficLayer.setMap(map);
}

$(document).ready(function () {
    init();
    setInterval(function () {
        google.maps.event.trigger(map, 'resize');
        map.fitBounds();
    }, 2000);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://maps.googleapis.com/maps/api/js?libraries=places&sensor=false"></script>

<div id="map" style="width:600px; height:450px"></div>

#5


1  

I haven't work with traffic layers yet, so I'm not sure if this will work for you. I read the setZoom(getZoom()) trick but when I need to refresh the tiles (the classic one. The map itself) it didn't work either. I need to show/hide a grid in Gmaps (without reloading the page)

我还没有使用流量层,所以我不确定这是否适合你。我读了setZoom(getZoom())技巧,但是当我需要刷新瓷砖(经典的那个。地图本身)时,它也无法正常工作。我需要在Gmaps中显示/隐藏网格(无需重新加载页面)

After searching and testing I got it working with these three lines:

经过搜索和测试,我得到了以下三条线:

        google.maps.event.trigger(map, 'resize'); // Can't remember if really helps
        map.setZoom( map.getZoom() -1 );    
        map.setZoom( map.getZoom() +1 ); // It won't flicker or make the transition between zoom levels. GMap just ignore the zoom change but redraw the tiles :/

I repeat. I don't know if this works with traffic layers but test it anyways. It kept me awake 2 days.

我重复。我不知道这是否适用于交通层,但无论如何都要测试它。它让我保持清醒2天。

#6


1  

Google documentation says:

谷歌文档说:

The Google Maps API allows you to add real-time traffic information (where supported) to your maps using the TrafficLayer object. Traffic information is provided for the time at which the request is made.

Google Maps API允许您使用TrafficLayer对象向地图添加实时路况信息(支持的位置)。提供交通信息的时间是提出请求的时间。

I believe your refreshMap() function will only hide and show the traffic layer (via the .setMap() method) and will not actually fetch updated traffic data (if there is).

我相信你的refreshMap()函数只会隐藏和显示流量层(通过.setMap()方法),并且实际上不会获取更新的流量数据(如果有)。

So the only efficient way would be to renew your request by re-initiating the TrafficLayer() object.

因此,唯一有效的方法是通过重新启动TrafficLayer()对象来续订您的请求。

EDIT: I've monitored the network traffic and saw no new requests are made. The view has to be changed to force new data to be fetched (for example by re-setting the zoom)...

编辑:我监控了网络流量,没有看到新的请求。必须更改视图以强制获取新数据(例如通过重新设置缩放)...

function refreshMap() {
    trafficLayer.setMap(null);
    trafficLayer = null;
    map.setZoom(map.getZoom()); // this renews the view and forces new data to be requested
    setTimeout(function () {
        trafficLayer = new google.maps.TrafficLayer();
        trafficLayer.setMap(map);
    }, 100);
}

So with the updated method above, the JS file below is re-fetched from https://maps.googleapis.com/maps/api/js/:

因此,使用上面更新的方法,可以从https://maps.googleapis.com/maps/api/js/重新获取以下JS文件:

ViewportInfoService.GetViewportInfo?1m6&1m2&1d40.67711350268867&2d-74.09477919619036&2m2&1d40.747903965754034&2d-73.91666125686464&2u15&4sen-US&5e0&6sm%40285000000&7b0&8e0&9b0&callback=_xdc_._e0qzs3&token=110512

that contains traffic data such as:

包含流量数据,例如:

...,["traffic",[[40.74725696280421,-74.102783203125],[40.75557964275589,-73.916015625]]]...

#7


1  

Sergio's answer is still the correct one but I believe Google updated their API and URLs (a risk mentioned by a commenter).

Sergio的回答仍然是正确的,但我相信Google更新了他们的API和URL(评论者提到的风险)。

The correct test would be now:

现在正确的测试:

....
if (/googleapis.com\/maps\/vt\?pb=/.test(src)) {
...

#1


22  

Ok, what i've found, and what is mentioned above is that trafficLayer.setMap(null) and trafficLayer.setMap(map) - just switches tiles with drawn traffic to tiles without traffic. Also map.setZoom(map.getZoom()) (and any other variaties of zoom) doesn't work because tiles are already in cache and google scripts don't even try to download fresh ones from server.

好吧,我发现了什么,以及上面提到的是trafficLayer.setMap(null)和trafficLayer.setMap(map) - 只需将绘制流量的切片切换到没有流量的切片。另外map.setZoom(map.getZoom())(和任何其他缩放变量)不起作用,因为磁贴已经在缓存中,而谷歌脚本甚至不尝试从服务器下载新的。

Also, seems that if you just open google maps and turn on traffic layer it's not refreshing! Such a lame, google!

此外,似乎如果你只是打开谷歌地图并打开流量层,它就不会令人耳目一新!这样的跛脚,谷歌!

So we have to find a different way to solve it.

所以我们必须找到一种不同的解决方法。

First thought is to use window.location.reload(true) wich will flush image cache - and we see it works. Not a good way to go though - reloading whole page taking too long. How about reloading images? Let's try!

首先想到的是使用window.location.reload(true)将刷新图像缓存 - 我们看到它的工作原理。不是一个好方法 - 重新加载整个页面需要太长时间。如何重新加载图像?咱们试试吧!

function reloadTiles() {
    var tiles = $("#map-canvas").find("img");
    for (var i = 0; i < tiles.length; i++) {
        var src = $(tiles[i]).attr("src");
        if (/googleapis.com\/vt\?pb=/.test(src)) {              
            var new_src = src.split("&ts")[0] + '&ts=' + (new Date()).getTime();
            $(tiles[i]).attr("src", new_src);                                                   
        }               
    }
}   

And we call this function every N seconds: setInterval(reloadTiles, 5000)

我们每N秒调用一次这个函数:setInterval(reloadTiles,5000)

some comments:

一些评论:

$("#map-canvas").find("img") - will grab all images from your map container (map-canvas in my case). Not all are tiles so we need to filter them out - i've noticed that tiles are loaded from domains like mts(digit).googleapis.com/vt?pb=(hella long param). Other map images are loaded from maps.gstatic.com.

$(“#map-canvas”)。find(“img”) - 将从地图容器中获取所有图像(在我的情况下为map-canvas)。并非所有都是瓷砖所以我们需要将它们过滤掉 - 我注意到瓷砖是从像mts(数字)这样的域加载的.googleapis.com / vt?pb =(hella long param)。其他地图图像从maps.gstatic.com加载。

So we get tile images, add bogus parameter and change their src. Profit!

所以我们得到平铺图像,添加虚假参数并更改其src。利润!

Btw, i've found that traffic really changes in real time - tiles may be different each second.

顺便说一句,我发现交通确实实时变化 - 每秒的瓷砖可能会有所不同。

Edit

编辑

Oh, sorry, here's working sample. And it's a snowy Moscow with a huge traffic :)

哦,对不起,这是工作样本。这是一个多雪的莫斯科,拥有巨大的交通:)

#2


1  

I use the traffic layer quite a bit. I have added a button to toggle the layer but found to hide it I had to set the layer itself as null.

我使用流量层相当多。我添加了一个按钮来切换图层但发现隐藏它我必须将图层本身设置为null。

My code to show the layer:

我的代码显示图层:

if (MapManager.trafficLayer == null)
{
      MapManager.trafficLayer = new google.maps.TrafficLayer();
}
MapManager.trafficLayer.setMap(MapManager.map);

Then to go and hide the layer again:

然后再次隐藏图层:

MapManager.trafficLayer.setMap(null);
MapManager.trafficLayer = null;

In an ideal way what you suggested above would be better but for me this seems to work just fine.

以理想的方式,你上面建议的会更好,但对我来说这似乎工作得很好。

#3


1  

The way you are refreshing the layer is working fine.

刷新图层的方式工作正常。

Here is your code edited to prove this:

以下是您的代码编辑,以证明这一点:

<html>
<head>
    <title>Map Testing</title>
    <script type="text/javascript" src="https://maps.googleapis.com/maps/api   /js?v=3.exp&libraries=weather"></script>
    <script src="http://code.jquery.com/jquery-latest.min.js"></script>

    <script type="text/javascript">
        var map, trafficLayer;          
        var vis = false;

        $(function ()
        {
            initMap();            
        });

        function refreshMap()
        {               
            if (vis)            
            {
                trafficLayer.setMap(null)
                vis = false;
            }
            else
            {
                trafficLayer.setMap(map);
                vis = true;
            }            
        }

        function initMap()
        {
            var mapDiv = document.getElementById('map');
            map = new google.maps.Map(mapDiv, {zoom: 15, center: new google.maps.LatLng(40.7127, -74.0059)});

            trafficLayer = new google.maps.TrafficLayer();

            trafficLayer.setMap(map);
            vis = true;
            setInterval(function ()
            {
                refreshMap();
            }, 3000);
        }
    </script>
</head>
<body style="margin:0px;">
    <div id="map" style="width:100%; height:100%;"></div>
</body>

I added a visibility property to toggle the layer every 2 seconds. You will notice how it turns on and off. Because the way you called it I think it did not have enough time to refresh.

我添加了一个visibility属性来每隔2秒切换一次图层。你会注意到它是如何打开和关闭的。因为你打电话的方式我认为它没有足够的时间来刷新。

Also I added the interval in the initMap function after the layer's map was first set.

在首次设置图层映射后,我还在initMap函数中添加了区间。

Hope that helps.

希望有所帮助。

EDIT. Just to add to this, where the traffic is real time where supported, in some cases its based on historic data and will not refresh over a short period. But the traffic data is fetched at the time of each request as specified in the docs: https://developers.google.com/maps/documentation/javascript/trafficlayer#traffic_layer

编辑。只是为了补充这一点,流量是实时支持的地方,在某些情况下,它基于历史数据,并且不会在短时间内刷新。但是,在文档中指定的每个请求时都会提取流量数据:https://developers.google.com/maps/documentation/javascript/trafficlayer#traffic_layer

#4


1  

try this code snippet, may be this help you out

试试这个代码片段,可能会帮到你

function init() {
    var map,
    trafficLayer,
    mapTimerHandle;

    var mapDiv = document.getElementById('map');

    map = new google.maps.Map(mapDiv, {
        zoom: 14,
        center: new google.maps.LatLng(40.7127, -74.0059)
    });

    trafficLayer = new google.maps.TrafficLayer();
    trafficLayer.setMap(map);
}

$(document).ready(function () {
    init();
    setInterval(function () {
        google.maps.event.trigger(map, 'resize');
        map.fitBounds();
    }, 2000);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://maps.googleapis.com/maps/api/js?libraries=places&sensor=false"></script>

<div id="map" style="width:600px; height:450px"></div>

#5


1  

I haven't work with traffic layers yet, so I'm not sure if this will work for you. I read the setZoom(getZoom()) trick but when I need to refresh the tiles (the classic one. The map itself) it didn't work either. I need to show/hide a grid in Gmaps (without reloading the page)

我还没有使用流量层,所以我不确定这是否适合你。我读了setZoom(getZoom())技巧,但是当我需要刷新瓷砖(经典的那个。地图本身)时,它也无法正常工作。我需要在Gmaps中显示/隐藏网格(无需重新加载页面)

After searching and testing I got it working with these three lines:

经过搜索和测试,我得到了以下三条线:

        google.maps.event.trigger(map, 'resize'); // Can't remember if really helps
        map.setZoom( map.getZoom() -1 );    
        map.setZoom( map.getZoom() +1 ); // It won't flicker or make the transition between zoom levels. GMap just ignore the zoom change but redraw the tiles :/

I repeat. I don't know if this works with traffic layers but test it anyways. It kept me awake 2 days.

我重复。我不知道这是否适用于交通层,但无论如何都要测试它。它让我保持清醒2天。

#6


1  

Google documentation says:

谷歌文档说:

The Google Maps API allows you to add real-time traffic information (where supported) to your maps using the TrafficLayer object. Traffic information is provided for the time at which the request is made.

Google Maps API允许您使用TrafficLayer对象向地图添加实时路况信息(支持的位置)。提供交通信息的时间是提出请求的时间。

I believe your refreshMap() function will only hide and show the traffic layer (via the .setMap() method) and will not actually fetch updated traffic data (if there is).

我相信你的refreshMap()函数只会隐藏和显示流量层(通过.setMap()方法),并且实际上不会获取更新的流量数据(如果有)。

So the only efficient way would be to renew your request by re-initiating the TrafficLayer() object.

因此,唯一有效的方法是通过重新启动TrafficLayer()对象来续订您的请求。

EDIT: I've monitored the network traffic and saw no new requests are made. The view has to be changed to force new data to be fetched (for example by re-setting the zoom)...

编辑:我监控了网络流量,没有看到新的请求。必须更改视图以强制获取新数据(例如通过重新设置缩放)...

function refreshMap() {
    trafficLayer.setMap(null);
    trafficLayer = null;
    map.setZoom(map.getZoom()); // this renews the view and forces new data to be requested
    setTimeout(function () {
        trafficLayer = new google.maps.TrafficLayer();
        trafficLayer.setMap(map);
    }, 100);
}

So with the updated method above, the JS file below is re-fetched from https://maps.googleapis.com/maps/api/js/:

因此,使用上面更新的方法,可以从https://maps.googleapis.com/maps/api/js/重新获取以下JS文件:

ViewportInfoService.GetViewportInfo?1m6&1m2&1d40.67711350268867&2d-74.09477919619036&2m2&1d40.747903965754034&2d-73.91666125686464&2u15&4sen-US&5e0&6sm%40285000000&7b0&8e0&9b0&callback=_xdc_._e0qzs3&token=110512

that contains traffic data such as:

包含流量数据,例如:

...,["traffic",[[40.74725696280421,-74.102783203125],[40.75557964275589,-73.916015625]]]...

#7


1  

Sergio's answer is still the correct one but I believe Google updated their API and URLs (a risk mentioned by a commenter).

Sergio的回答仍然是正确的,但我相信Google更新了他们的API和URL(评论者提到的风险)。

The correct test would be now:

现在正确的测试:

....
if (/googleapis.com\/maps\/vt\?pb=/.test(src)) {
...