I'm displaying a weather map in a GWT application. I'm using GWT 2.7 and the GWT wrapper of the GoogleMaps JavaScript API available here (gwt-maps-3.8.0-pre1.zip).
I use a tile server to fetch the weather, which updates every 5 minutes. On the 5 minute mark, I refresh the map by setting the zoom to 1 and then back to the original, by triggering a resize, and by removing and then adding the weather layer again.
This worked fine. However, recently I noticed that this no longer works: the refresh never even goes to the tile server, so no new weather is displayed. If you leave my map up for 12 hours, you'll be looking at weather that's 12 hours old. Previously, the map would automatically stay updated. I haven't changed any of my code. So my guess is that something changed in the underlying GoogleMaps JavaScript API.
However, I then created this simple pure-JavaScript example:
<!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>
To my surprise, this still works fine. Whenever you click the Refresh button, the map goes to the tile server and fetches new tiles.
So I tried doing the exact same thing in 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);
}-*/;
}
This should do the same thing as the pure-JavaScript example. Instead, when I click the button, the map does refresh (I see the weather layer blink), but it doesn't actually go to the tile server for new tiles.
Weirder still, this "sorta" works in Internet Explorer: maybe 1 out of 3 times I click the button, the map actually goes to the tile server. But in Chrome, it never goes to the tile server when I click the button.
To determine this, I am looking at the network tab of the browser tools. I would expect the map to hit the tile server every time I click the button. That's what it does in pure JavaScript, and that's what it used to do in GWT, but sometime in the last couple months the GWT behavior has changed.
I don't think this is a browser caching issue. The problem is not that the map tries to fetch new tiles but gets old ones, it's that it never tries to fetch new tiles. I click the button, and I see nothing happening in the network tab of the developer tools.
- Why do I see a different behavior in JavaScript vs GWT?
- Why do I see a different behavior in different browsers?
- Is the GWT GoogleMaps library doing some kind of internal caching? Is there a way to disable this?
- Why has this behavior apparently changed?
- How can I make the GWT map refresh by going to the tile server for new tiles?
?timepart to avoid the browser cache, which in this case wasn't the problem, since it was never going to the server in the first place, and therefore never even checking the browser cache. So it looks like there must be some internal caching, but only in the GWT version, which doesn't make any sense to me. Can you explain why the GWT and JS versions are different or why the?timething works in GWT? If you want to add that as an answer, I'd definitely appreciate it. - Kevin Workman