2011-09-07 15 views
7

Sto lavorando con l'API di Google Maps v3 e ho uno strato di sovrapposizione personalizzato basato sulla classe ImageMapType. Vorrei mostrare un indicatore di caricamento di qualche tipo mentre le piastrelle dell'overlay si stanno caricando, ma non vedo alcun modo per sapere quando sono finite.Google Maps v3: Come sapere quando i pannelli di una sovrapposizione ImageMapType sono stati caricati?

Il codice per creare la sovrapposizione è simile al seguente:

var myOverlay = new google.maps.ImageMapType({ 
    getTileUrl: myGetTileUrl, 
    tileSize: new google.maps.Size(256, 256), 
    isPng: true 
}); 

myMap.overlayMapTypes.push(myOverlay); 

I lavori di cui sopra bene, e la sovrapposizione carica con successo; sembra solo che nessun evento sia emesso dalla mappa per indicare qualcosa sullo stato dell'overlay ImageMapType.

Mi aspetto che la mappa emetta almeno un evento "inattivo" al termine del caricamento delle tessere, ma per quanto posso dire non è così.

Come posso sapere quando l'overlay ImageMapType è terminato?

EDIT

ho scritto un banco di prova sul jsFiddle: http://jsfiddle.net/6yvcB/ - Guarda il tuo output su console per la parola "idled" per vedere quando l'evento di inattività. Si noti che non si attiva mai quando si fa clic sul pulsante per aggiungere una sovrapposizione.

Inoltre, gattini.

risposta

10

Sembrerebbe non c'è "out of the box" modo di sapere quando un overlay ImageMapType termine del caricamento, ma grazie ad un suggestion from Martin sopra sul Google Maps API v3 Forums sono stato in grado di aggiungere nel mio proprio evento personalizzato che viene emesso quando il lo strato finisce il caricamento.

L'approccio di base è:

  • Ogni volta che viene richiesto un URL, aggiungere l'URL di un elenco di URL in attesa
  • Override ImageMapType.getTile() in modo che possiamo aggiungere listener di eventi "onload" a ciascun elemento <img>.
  • Quando viene attivato l'evento "carico" di ciascuna immagine, rimuovere tale immagine dall'elenco degli URL in sospeso.
  • Quando l'elenco degli URL in sospeso è vuoto, quindi emettere il nostro evento personalizzato "overlay inattivo".

Ho copiato il codice qui sotto per i posteri, ma si può vedere in azione il jsFiddle: http://jsfiddle.net/6yvcB/22/

// Create a base map 
var options = { 
    zoom: 3, 
    center: new google.maps.LatLng(37.59, -99.13), 
    mapTypeId: "terrain" 
}; 
var map = new google.maps.Map($("#map")[0], options); 

// Listen for the map to emit "idle" events 
google.maps.event.addListener(map, "idle", function(){ 
    console.log("map is idle"); 
}); 

// Keep track of pending tile requests 
var pendingUrls = []; 

$("#btn").click(function() { 
    var index = 0; 
    var urls = [ "http://placekitten.com/256/256", 
       "http://placekitten.com/g/256/256", 
       "http://placekitten.com/255/255", 
       "http://placekitten.com/g/255/255", 
       "http://placekitten.com/257/257", 
       "http://placekitten.com/g/257/257" ]; 

    var overlay = new google.maps.ImageMapType({ 
     getTileUrl: function() { 
      var url = urls[index % urls.length]; 
      index++; 

      // Add this url to our list of pending urls 
      pendingUrls.push(url); 

      // if this is our first pending tile, signal that we just became busy 
      if (pendingUrls.length === 1) { 
       $(overlay).trigger("overlay-busy"); 
      } 

      return url; 
     }, 
     tileSize: new google.maps.Size(256, 256), 
     isPng: true, 
     opacity: 0.60 
    }); 

    // Listen for our custom events 
    $(overlay).bind("overlay-idle", function() { 
     console.log("overlay is idle"); 
    }); 

    $(overlay).bind("overlay-busy", function() { 
     console.log("overlay is busy"); 
    }); 


    // Copy the original getTile function so we can override it, 
    // but still make use of the original function 
    overlay.baseGetTile = overlay.getTile; 

    // Override getTile so we may add event listeners to know when the images load 
    overlay.getTile = function(tileCoord, zoom, ownerDocument) { 

     // Get the DOM node generated by the out-of-the-box ImageMapType 
     var node = overlay.baseGetTile(tileCoord, zoom, ownerDocument); 

     // Listen for any images within the node to finish loading 
     $("img", node).one("load", function() { 

      // Remove the image from our list of pending urls 
      var index = $.inArray(this.__src__, pendingUrls); 
      pendingUrls.splice(index, 1); 

      // If the pending url list is empty, emit an event to 
      // indicate that the tiles are finished loading 
      if (pendingUrls.length === 0) { 
       $(overlay).trigger("overlay-idle"); 
      } 
     }); 

     return node; 
    }; 

    map.overlayMapTypes.push(overlay); 
}); 
+1

Grazie per l'ottima soluzione! – mfras3r

0

In base alla risposta da @ Davide, ho creato un puro alternativa Javascript (soprattutto tenendo conto che Op non ha specificato jQuery).

var pendingUrls = []; 

function addPendingUrl(id, url) 
{ 
    // Add this url to our list of pending urls 
    pendingUrls[id].push(url); 

    //console.log("URL " + url + " added (" + pendingUrls[id].length + ")"); 

    // if this is our first pending tile, signal that we just became busy 
    if (pendingUrls[id].length === 1) { 
     console.log("overlay is busy"); 
    } 
} 

function addTileLoadListener(id, mapType, timeout) 
{ 
    // Initialise the sub-array for this particular id 
    pendingUrls[id] = []; 

    // Copy the original getTile function so we can override it, but still make use of the original function 
    mapType.baseGetTile = mapType.getTile; 

    // Override getTile so we may add event listeners to know when the images load 
    mapType.getTile = function(tileCoord, zoom, ownerDocument) 
    { 
     // Get the DOM node generated by the out-of-the-box ImageMapType 
     var node = mapType.baseGetTile(tileCoord, zoom, ownerDocument); 

     //console.log("URL " + node.firstChild.__src__ + " confirmed (" + pendingUrls[id].length + ")"); 

     function removePendingImg(node, src, result) 
     { 
      var index = pendingUrls[id].indexOf(src); 
      if (index == -1) 
      { 
       //console.log("URL " + src + " " + "not found" + " (" + pendingUrls[id].length + ")"); 
      } 
      else 
      { 
       pendingUrls[id].splice(index, 1); 
       //console.log("URL " + src + " " + result + " (" + pendingUrls[id].length + ")"); 

       // If the pending url list is empty, emit an event to indicate that the tiles are finished loading 
       if (pendingUrls[id].length === 0) { 
        console.log("overlay is idle"); 
       }     
      } 
     } 

     // Listen for any images within the node to finish loading 
     node.getElementsByTagName("img")[0].onload = function() { 
      //console.log("URL " + node.firstChild.src + " maybe loaded (" + node.firstChild.__src__ + ")"); 

      // Check that we have loaded the final image. We detect this because the node.src ends with what is in node.__src__ 
      var str = node.firstChild.src; 
      var suffix = node.firstChild.__src__; 
      if (str.indexOf(suffix, str.length - suffix.length) !== -1) 
      { 
       removePendingImg(node, node.firstChild.__src__, "loaded"); // Remove the image from our list of pending urls 
      } 
     }; 

     // Limit the wait 
     var imgsrc = node.firstChild.__src__; 
     setTimeout(function() { 
      if (node.firstChild) // if the map has already changed and the image is not going to be loaded, the node is destroyed 
      { 
       //var index = pendingUrls[id].indexOf(node.firstChild.__src__); 
       //if (index != -1) 

       // If the image is not loaded yet (node.src changes to the same value as node.firstChild.__src__ when loaded) 
       var str = node.firstChild.src; 
       var suffix = node.firstChild.__src__; 
       if (!(str.indexOf(suffix, str.length - suffix.length) !== -1)) 
       { 
        node.getElementsByTagName("img")[0].onload = null; // Disable the event handler for this node 
        removePendingImg(node, node.firstChild.__src__, "timed out"); // Remove the image from our list of pending urls 
       } 
      } 
      else removePendingImg(node, imgsrc, "discarded"); // Remove the image from our list of pending urls 
     }, timeout); 

     return node; 
    }; 
} 

E queste funzioni possono essere facilmente richiamate da qualsiasi funzione getTileUrl.

myMapType = new google.maps.ImageMapType({ 
    getTileUrl: function(coord, zoom) 
    { 
     var url = '//a.tile.server.com/' + zoom + '/' + coord.x + '/' + coord.y + '.png'; 

     // Add this url to our list of pending urls, and enable the loading image if appropriate 
     addPendingUrl("myLayer", url); 

     return url; 
    }, 
    tileSize: new google.maps.Size(256, 256), 
    opacity: 0.5 
}); 

// Listen for all the images having been loaded 
addTileLoadListener("myLayer", myMapType, 15000); 

Funzioni bonus: supporto per più livelli e timeout (nel caso in cui il server sia lento o sciatto).

+0

L'unico problema che ho riscontrato in questa versione è che l'evento onload non viene attivato quando i tile sono già nella cache.La soluzione dovrebbe essere quella di impostare l'evento onload prima del parametro src (http://stackoverflow.com/a/12355031/1816603), ma non sono sicuro se questo è compatibile con l'approccio di sovrascrivere il metodo getTile, come l'immagine src è impostato nel codice di Maps. –

Problemi correlati