2016-05-12 10 views
9

Sto visualizzando una mappa meteo in un'applicazione GWT. Utilizzo GWT 2.7 e il wrapper GWT dell'API JavaScript di GoogleMaps disponibile here (gwt-maps-3.8.0-pre1.zip).Il server di riquadri GoogleMaps di aggiornamento funziona in JavaScript ma non in GWT

Uso un server di tessere per scaricare il meteo, che si aggiorna ogni 5 minuti. Al momento del contrassegno dei 5 minuti, aggiorno la mappa impostando lo zoom su 1 e poi di nuovo sull'originale, attivando un ridimensionamento e rimuovendo e aggiungendo di nuovo il layer meteo.

Questo ha funzionato bene. Tuttavia, recentemente ho notato che questo non funziona più: l'aggiornamento non arriva mai al server delle tessere, quindi non viene visualizzato nessun nuovo meteo. Se lasci la mia mappa per 12 ore, guarderai il tempo che ha 12 ore. In precedenza, la mappa veniva automaticamente aggiornata. Non ho cambiato nessuno dei miei codici. Quindi la mia ipotesi è che qualcosa sia cambiato nell'API JavaScript di GoogleMaps sottostante.

Tuttavia, Poi ho creato questo semplice esempio JavaScript-pura:

<!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> 

Con mia grande sorpresa, questo funziona ancora bene. Ogni volta che fai clic sul pulsante Aggiorna, la mappa va al server delle tessere e recupera nuove tessere.

Così ho provato a fare la stessa cosa 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); 
    }-*/; 

} 

Questo dovrebbe fare la stessa cosa come l'esempio puro JavaScript. Invece, quando faccio clic sul pulsante, la mappa si aggiorna (vedo lampeggiare il livello del tempo), ma in realtà non va al server delle tessere per le nuove tessere.

Ancora più strano, questo "sorta" funziona in Internet Explorer: forse 1 su 3 volte faccio clic sul pulsante, la mappa in realtà va al server tile. Ma in Chrome, non va mai al server di tile quando faccio clic sul pulsante.

Per determinare questo, sto guardando la scheda di rete degli strumenti del browser. Mi aspetto che la mappa colpisca il server di tile ogni volta che faccio clic sul pulsante. Questo è quello che fa in puro JavaScript, ed è quello che faceva in GWT, ma a volte negli ultimi due mesi il comportamento GWT è cambiato.

Non penso che si tratti di un problema di memorizzazione nella cache del browser. Il problema è non che la mappa tenta di recuperare nuove tessere ma ottiene quelle vecchie, è che non cerca mai di recuperare nuove tessere. Faccio clic sul pulsante e non vedo nulla che si verifichi nella scheda di rete degli strumenti di sviluppo.

  • Perché vedo un comportamento diverso in JavaScript rispetto a GWT?
  • Perché vedo un comportamento diverso nei vari browser?
  • La libreria GoogleMaps di GWT esegue una sorta di caching interno? C'è un modo per disabilitare questo?
  • Perché questo comportamento è apparentemente cambiato?
  • Come posso aggiornare la mappa GWT andando al server delle tessere per le nuove tessere?
+0

Ho testato lo script in entrambi i browser e l'ho provato su GWT. Una delle differenze che ho trovato è che nei browser hanno inserito un timestamp dopo il tassello (/ZOOM/X/Y.png?TIME). Il codice GWT apparentemente non lo fa. Nel browser se il tempo è omesso, IE lo recupera dal server e Chrome lo preleva da localcache. Forse la modifica era nel server tile (o un proxy specifico) che memorizza nella cache il riquadro. Puoi provare ad aggiornare la richiesta nel codice GWT con un parametro "? TIME"? – fhofmann

+0

@fhofmann Che ha funzionato davvero, il che è sorprendente per me. Solitamente si aggiunge una parte '? Time' per evitare la cache del browser, che in questo caso non era il problema, dal momento che non stava andando sul server in primo luogo, e quindi nemmeno controllando la cache del browser. Quindi sembra che ci debba essere del caching interno, ma solo nella versione GWT, che per me non ha alcun senso. Puoi spiegare ** perché ** le versioni GWT e JS sono diverse o perché la cosa '' time' 'funziona in GWT? Se vuoi aggiungerlo come risposta, lo apprezzerei sicuramente. –

+0

In realtà non ho mai usato GWT prima. Ma ora sono curioso e cercherò di scoprire come funziona e dove potrebbe essere il caching. – fhofmann

risposta

1

Questa non è la risposta definitiva. Ma contiene informazioni significative.

Per gestire le chiamate http GWT ha un set di classi che si comportano come un browser ed è il punto in cui credo che il problema sia.

Se lo stesso codice ha funzionato prima è possibile che il server tile includa l'intestazione Cache (Cache-Control: max-age = 300) di recente. E per qualche motivo il codice GWT non gestisce questa intestazione correttamente.

Se ho ragione, un modo per eliminare il problema è aggiungere un parametro con l'ora corrente nella chiamata GWT (come la versione del browser del tuo codice).

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); 

}-*/; 
+0

Hai la soluzione giusta, ma non credo che il problema sia in GWT. È colpa mia, dal momento che non mi ero reso conto di avere la parte '? Time' nella mia versione JavaScript. Se lo prendo, si comporta come la versione GWT. Se lo aggiungo alla versione GWT, allora funziona perfettamente. ** Quindi il problema è nella libreria JavaScript sottostante, non in GWT. ** Apparentemente Google Maps sta facendo un po 'di cache interna, il che significa anche che ** la modifica del controllo cache del server tile non farà nulla. ** I' Sono piuttosto sicuro che questo è un nuovo comportamento, ma non posso dirlo perché il codice è offuscato. –

+0

Detto questo, hai indicato la parte "? Time" nel mio JavaScript, quindi ti meriti la taglia. E 'stato un grande aiuto. Ma non penso che abbiamo identificato la causa del problema, dal momento che è interno all'API di Google Maps, che è offuscato. Mi piacerebbe un po 'di parole ufficiali sul fatto che qualcosa sia cambiato solo per la mia sanità mentale, ma per ora funziona così sono felice. –

+0

Ho fatto un altro test. Questa volta ho compilato il codice GWT e l'ho indirizzato a un server fittizio di tile (servlet locale che restituisce l'ora corrente in un'immagine). Il mio obiettivo era dimostrare che l'intestazione della cache è il problema e vedere dove GWT scarica e gestisce l'immagine. Sfortunatamente sto ricevendo un errore di script e non riesco a vedere la tua applicazione in esecuzione. – fhofmann

Problemi correlati