刷新 GoogleMaps tile 服务器在 JavaScript 中有效,但在 GWT 中无效
Refreshing GoogleMaps tile server works in JavaScript but not in GWT
我正在 GWT 应用程序中显示天气图。我正在使用 GWT 2.7 和可用的 GoogleMaps JavaScript API 的 GWT 包装器 here (gwt-maps-3.8.0-pre1.zip).
我使用 tile 服务器获取天气,每 5 分钟更新一次。在 5 分钟标记处,我通过将缩放比例设置为 1 然后恢复到原始状态、触发调整大小以及删除然后再次添加天气图层来刷新地图。
这很好用。但是,最近我注意到这不再有效:刷新甚至不会进入图块服务器,因此不会显示新的天气。如果您将我的地图放置 12 小时,您将看到 12 小时前的天气。以前,地图会自动保持更新。我没有更改任何代码。 所以我的猜测是底层 GoogleMaps 发生了一些变化 JavaScript API。
但是,我随后创建了这个简单的纯 JavaScript 示例:
<!DOCTYPE html>
<html>
<head>
<title>Map Test</title>
<style type="text/css">
html, body { height: 100%; margin: 0; padding: 0; }
#map {
width:90%;
height: 90%;
display:inline-block;
}
</style>
</head>
<body>
<div id="map"></div>
<button type="button" onClick="refreshMap()">Refresh</button>
<script type="text/javascript">
var map;
var tileNEX;
function initMap() {
var mapOptions = {
zoom: 8,
center: new google.maps.LatLng(42.5, -95.5),
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById('map'), mapOptions);
tileNEX = new google.maps.ImageMapType({
getTileUrl: function(tile, zoom) {
return "http://mesonet.agron.iastate.edu/cache/tile.py/1.0.0/nexrad-n0q-900913/" + zoom + "/" + tile.x + "/" + tile.y +".png?"+ (new Date()).getTime();
},
tileSize: new google.maps.Size(256, 256),
opacity:0.60,
name : 'NEXRAD',
isPng: true
});
map.overlayMapTypes.setAt("0",tileNEX);
}
function refreshMap(){
var zoom = map.getZoom();
map.setZoom(1);
map.setZoom(zoom);
//google.maps.event.trigger(map, 'resize');
//var layer = map.overlayMapTypes.getAt(0);
//map.overlayMapTypes.setAt(0, null);
//map.overlayMapTypes.setAt(0, layer);
}
</script>
<script async defer src="https://maps.googleapis.com/maps/api/js?callback=initMap">
</script>
</body>
</html>
令我惊讶的是,这仍然可以正常工作。每当您单击“刷新”按钮时,地图都会转到切片服务器并获取新切片。
所以我尝试在 GWT 中做完全相同的事情:
package com.example.client;
import com.google.gwt.ajaxloader.client.AjaxLoader;
import com.google.gwt.ajaxloader.client.AjaxLoader.AjaxLoaderOptions;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.dom.client.Document;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.maps.gwt.client.GoogleMap;
import com.google.maps.gwt.client.LatLng;
import com.google.maps.gwt.client.MapOptions;
import com.google.maps.gwt.client.MapType;
import com.google.maps.gwt.client.MapTypeId;
public class GwtMapTest implements EntryPoint {
@Override
public void onModuleLoad() {
AjaxLoaderOptions options = AjaxLoaderOptions.newInstance();
options.setOtherParms("sensor=false");
Runnable callback = new Runnable() {
public void run() {
createMap();
}
};
AjaxLoader.loadApi("maps", "3", callback, options);
}
public void createMap() {
MapOptions mapOpts = MapOptions.create();
mapOpts.setZoom(4);
mapOpts.setCenter(LatLng.create(37.09024, -95.712891));
mapOpts.setMapTypeId(MapTypeId.TERRAIN);
mapOpts.setStreetViewControl(false);
final GoogleMap map = GoogleMap.create(Document.get().getElementById("map_canvas"), mapOpts);
addWeatherLayer(map);
Button button = new Button("Gwt Refresh");
button.addClickHandler(new ClickHandler(){
@Override
public void onClick(ClickEvent event) {
refreshWeatherLayer(map);
}
});
Button nativeButton = new Button("Native Refresh");
nativeButton.addClickHandler(new ClickHandler(){
@Override
public void onClick(ClickEvent event) {
nativeRefreshWeatherLayer(map);
}
});
RootPanel.get().add(button);
RootPanel.get().add(nativeButton);
}
public native void addWeatherLayer(GoogleMap map) /*-{
var imageMapType = new $wnd.google.maps.ImageMapType({
getTileUrl: function(coord, zoom) {
return "http://mesonet.agron.iastate.edu/cache/tile.py/1.0.0/nexrad-n0q-900913/"+ zoom + "/" + coord.x + "/" + coord.y + ".png";
},
tileSize: new $wnd.google.maps.Size(256, 256),
opacity:.50,
isPng: true
});
map.overlayMapTypes.setAt("0", imageMapType);
}-*/;
private void refreshWeatherLayer(GoogleMap map){
double zoom = map.getZoom();
map.setZoom(1);
map.setZoom(zoom);
MapType layer = map.getOverlayMapTypes().getAt(0);
map.getOverlayMapTypes().setAt(0, null);
map.getOverlayMapTypes().setAt(0, layer);
}
private native void nativeRefreshWeatherLayer(GoogleMap map) /*-{
var zoom = map.getZoom();
map.setZoom(1);
map.setZoom(zoom);
$wnd.google.maps.event.trigger(map, 'resize');
var layer = map.overlayMapTypes.getAt(0);
map.overlayMapTypes.setAt(0, null);
map.overlayMapTypes.setAt(0, layer);
}-*/;
}
这应该与 pure-JavaScript 示例做同样的事情。相反,当我单击该按钮时,地图会刷新(我看到天气图层闪烁),但它实际上并没有转到切片服务器以获取新切片。
更奇怪的是,这个 "sorta" 在 Internet Explorer 中有效:我单击按钮的 3 次中可能有 1 次,地图实际上进入了切片服务器。但在 Chrome 中,当我单击按钮时它永远不会进入磁贴服务器。
为了确定这一点,我正在查看浏览器工具的网络选项卡。 我希望每次单击按钮时地图都能访问切片服务器。这就是它在纯 JavaScript 中所做的,这也是它过去在 GWT 中所做的,但是在过去几个月的某个时候,GWT 行为发生了变化。
我认为这不是浏览器缓存问题。问题是不是地图尝试获取新图块,但是得到旧的,就是它从不尝试获取新的瓷砖。我单击该按钮,但在开发人员工具的网络选项卡中没有看到任何变化。
- 为什么我在 JavaScript 和 GWT 中看到不同的行为?
- 为什么我在不同的浏览器中看到不同的行为?
- GWT GoogleMaps 库是否在进行某种内部缓存?有没有办法禁用它?
- 为什么这种行为明显改变了?
- 如何通过去图块服务器获取新图块来刷新 GWT 地图?
这不是最终答案。但包含重要信息。
为了管理 http 调用,GWT 有一组 类 可以像浏览器一样工作,这就是我认为的问题所在。
如果之前使用的相同代码可能是磁贴服务器包含缓存 header (Cache-Control:max-age=300)最近。由于某些原因,GWT 代码没有正确管理这个 header。
如果我是对的,解决问题的一种方法是在 GWT 调用中附加一个带有当前时间的参数(就像您的代码的浏览器版本)。
public native void addWeatherLayer(GoogleMap map) /*-{
var imageMapType = new $wnd.google.maps.ImageMapType({
getTileUrl: function(coord, zoom) {
return "http://mesonet.agron.iastate.edu/cache/tile.py/1.0.0/nexrad-n0q-900913/"+ zoom + "/" + coord.x + "/" + coord.y + ".png?" + new Date().getTime();
},
tileSize: new $wnd.google.maps.Size(256, 256),
opacity:.50,
isPng: true
});
map.overlayMapTypes.setAt("0", imageMapType);
}-*/;
我正在 GWT 应用程序中显示天气图。我正在使用 GWT 2.7 和可用的 GoogleMaps JavaScript API 的 GWT 包装器 here (gwt-maps-3.8.0-pre1.zip).
我使用 tile 服务器获取天气,每 5 分钟更新一次。在 5 分钟标记处,我通过将缩放比例设置为 1 然后恢复到原始状态、触发调整大小以及删除然后再次添加天气图层来刷新地图。
这很好用。但是,最近我注意到这不再有效:刷新甚至不会进入图块服务器,因此不会显示新的天气。如果您将我的地图放置 12 小时,您将看到 12 小时前的天气。以前,地图会自动保持更新。我没有更改任何代码。 所以我的猜测是底层 GoogleMaps 发生了一些变化 JavaScript API。
但是,我随后创建了这个简单的纯 JavaScript 示例:
<!DOCTYPE html>
<html>
<head>
<title>Map Test</title>
<style type="text/css">
html, body { height: 100%; margin: 0; padding: 0; }
#map {
width:90%;
height: 90%;
display:inline-block;
}
</style>
</head>
<body>
<div id="map"></div>
<button type="button" onClick="refreshMap()">Refresh</button>
<script type="text/javascript">
var map;
var tileNEX;
function initMap() {
var mapOptions = {
zoom: 8,
center: new google.maps.LatLng(42.5, -95.5),
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById('map'), mapOptions);
tileNEX = new google.maps.ImageMapType({
getTileUrl: function(tile, zoom) {
return "http://mesonet.agron.iastate.edu/cache/tile.py/1.0.0/nexrad-n0q-900913/" + zoom + "/" + tile.x + "/" + tile.y +".png?"+ (new Date()).getTime();
},
tileSize: new google.maps.Size(256, 256),
opacity:0.60,
name : 'NEXRAD',
isPng: true
});
map.overlayMapTypes.setAt("0",tileNEX);
}
function refreshMap(){
var zoom = map.getZoom();
map.setZoom(1);
map.setZoom(zoom);
//google.maps.event.trigger(map, 'resize');
//var layer = map.overlayMapTypes.getAt(0);
//map.overlayMapTypes.setAt(0, null);
//map.overlayMapTypes.setAt(0, layer);
}
</script>
<script async defer src="https://maps.googleapis.com/maps/api/js?callback=initMap">
</script>
</body>
</html>
令我惊讶的是,这仍然可以正常工作。每当您单击“刷新”按钮时,地图都会转到切片服务器并获取新切片。
所以我尝试在 GWT 中做完全相同的事情:
package com.example.client;
import com.google.gwt.ajaxloader.client.AjaxLoader;
import com.google.gwt.ajaxloader.client.AjaxLoader.AjaxLoaderOptions;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.dom.client.Document;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.maps.gwt.client.GoogleMap;
import com.google.maps.gwt.client.LatLng;
import com.google.maps.gwt.client.MapOptions;
import com.google.maps.gwt.client.MapType;
import com.google.maps.gwt.client.MapTypeId;
public class GwtMapTest implements EntryPoint {
@Override
public void onModuleLoad() {
AjaxLoaderOptions options = AjaxLoaderOptions.newInstance();
options.setOtherParms("sensor=false");
Runnable callback = new Runnable() {
public void run() {
createMap();
}
};
AjaxLoader.loadApi("maps", "3", callback, options);
}
public void createMap() {
MapOptions mapOpts = MapOptions.create();
mapOpts.setZoom(4);
mapOpts.setCenter(LatLng.create(37.09024, -95.712891));
mapOpts.setMapTypeId(MapTypeId.TERRAIN);
mapOpts.setStreetViewControl(false);
final GoogleMap map = GoogleMap.create(Document.get().getElementById("map_canvas"), mapOpts);
addWeatherLayer(map);
Button button = new Button("Gwt Refresh");
button.addClickHandler(new ClickHandler(){
@Override
public void onClick(ClickEvent event) {
refreshWeatherLayer(map);
}
});
Button nativeButton = new Button("Native Refresh");
nativeButton.addClickHandler(new ClickHandler(){
@Override
public void onClick(ClickEvent event) {
nativeRefreshWeatherLayer(map);
}
});
RootPanel.get().add(button);
RootPanel.get().add(nativeButton);
}
public native void addWeatherLayer(GoogleMap map) /*-{
var imageMapType = new $wnd.google.maps.ImageMapType({
getTileUrl: function(coord, zoom) {
return "http://mesonet.agron.iastate.edu/cache/tile.py/1.0.0/nexrad-n0q-900913/"+ zoom + "/" + coord.x + "/" + coord.y + ".png";
},
tileSize: new $wnd.google.maps.Size(256, 256),
opacity:.50,
isPng: true
});
map.overlayMapTypes.setAt("0", imageMapType);
}-*/;
private void refreshWeatherLayer(GoogleMap map){
double zoom = map.getZoom();
map.setZoom(1);
map.setZoom(zoom);
MapType layer = map.getOverlayMapTypes().getAt(0);
map.getOverlayMapTypes().setAt(0, null);
map.getOverlayMapTypes().setAt(0, layer);
}
private native void nativeRefreshWeatherLayer(GoogleMap map) /*-{
var zoom = map.getZoom();
map.setZoom(1);
map.setZoom(zoom);
$wnd.google.maps.event.trigger(map, 'resize');
var layer = map.overlayMapTypes.getAt(0);
map.overlayMapTypes.setAt(0, null);
map.overlayMapTypes.setAt(0, layer);
}-*/;
}
这应该与 pure-JavaScript 示例做同样的事情。相反,当我单击该按钮时,地图会刷新(我看到天气图层闪烁),但它实际上并没有转到切片服务器以获取新切片。
更奇怪的是,这个 "sorta" 在 Internet Explorer 中有效:我单击按钮的 3 次中可能有 1 次,地图实际上进入了切片服务器。但在 Chrome 中,当我单击按钮时它永远不会进入磁贴服务器。
为了确定这一点,我正在查看浏览器工具的网络选项卡。 我希望每次单击按钮时地图都能访问切片服务器。这就是它在纯 JavaScript 中所做的,这也是它过去在 GWT 中所做的,但是在过去几个月的某个时候,GWT 行为发生了变化。
我认为这不是浏览器缓存问题。问题是不是地图尝试获取新图块,但是得到旧的,就是它从不尝试获取新的瓷砖。我单击该按钮,但在开发人员工具的网络选项卡中没有看到任何变化。
- 为什么我在 JavaScript 和 GWT 中看到不同的行为?
- 为什么我在不同的浏览器中看到不同的行为?
- GWT GoogleMaps 库是否在进行某种内部缓存?有没有办法禁用它?
- 为什么这种行为明显改变了?
- 如何通过去图块服务器获取新图块来刷新 GWT 地图?
这不是最终答案。但包含重要信息。
为了管理 http 调用,GWT 有一组 类 可以像浏览器一样工作,这就是我认为的问题所在。
如果之前使用的相同代码可能是磁贴服务器包含缓存 header (Cache-Control:max-age=300)最近。由于某些原因,GWT 代码没有正确管理这个 header。
如果我是对的,解决问题的一种方法是在 GWT 调用中附加一个带有当前时间的参数(就像您的代码的浏览器版本)。
public native void addWeatherLayer(GoogleMap map) /*-{
var imageMapType = new $wnd.google.maps.ImageMapType({
getTileUrl: function(coord, zoom) {
return "http://mesonet.agron.iastate.edu/cache/tile.py/1.0.0/nexrad-n0q-900913/"+ zoom + "/" + coord.x + "/" + coord.y + ".png?" + new Date().getTime();
},
tileSize: new $wnd.google.maps.Size(256, 256),
opacity:.50,
isPng: true
});
map.overlayMapTypes.setAt("0", imageMapType);
}-*/;