Pregunta Google Maps v3: ¿cómo saber cuándo terminaron de cargarse los mosaicos de una superposición ImageMapType?


Estoy trabajando con la API de Google Maps v3, y tengo una capa de superposición personalizada basada en la clase ImageMapType. Me gustaría mostrar un indicador de carga de algún tipo mientras se cargan los mosaicos de la superposición, pero no veo ninguna forma de saber cuándo terminaron.

El código para crear la superposición tiene un aspecto similar al siguiente:

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

myMap.overlayMapTypes.push(myOverlay);

Lo anterior funciona bien y la superposición se carga correctamente; simplemente parece que el mapa no emite ningún evento que indique algo sobre el estado de la superposición de ImageMapType.

Esperaría que el mapa al menos emita un evento "inactivo" cuando las baldosas terminen de cargarse, pero hasta donde sé, no.

¿Cómo puedo saber cuándo se terminó de cargar la superposición ImageMapType?

EDITAR

Escribí un caso de prueba en jsFiddle: http://jsfiddle.net/6yvcB/ - Observe la salida de la consola para la palabra "inactivo" para ver cuándo se activa el evento inactivo. Tenga en cuenta que nunca se dispara al hacer clic en el botón para agregar una superposición.

Además, gatitos.


7
2017-09-07 23:59


origen


Respuestas:


Parece que no existe una forma "lista para usar" para saber cuándo se ha terminado de cargar una superposición ImageMapType, pero gracias a un sugerencia de Martin más en el Foros de Google Maps API v3 Pude agregar mi propio evento personalizado que se emite cuando la capa termina de cargarse.

El enfoque básico es:

  • Cada vez que se solicita una URL, agregue la URL a una lista de URL pendientes
  • Anule ImageMapType.getTile () para que podamos agregar detectores de eventos "onload" a cada elemento <img>.
  • Cuando se desencadena el evento de "carga" de cada imagen, elimine esa imagen de la lista de URL pendientes.
  • Cuando la lista de URL pendientes está vacía, entonces emite nuestro evento personalizado "superposición inactiva".

Copié el código a continuación para la posteridad, pero puedes verlo en acción en 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);
});

10
2017-09-08 22:01



En base a la respuesta de @David, he creado una alternativa de Javascript puro (especialmente teniendo en cuenta que el Op no especificó 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;
    };
}

Y estas funciones se pueden invocar fácilmente desde cualquier función 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);

Funciones adicionales: soporte para múltiples capas y tiempos de espera (en caso de que el servidor sea lento o descuidado).


0
2018-04-12 05:17



Preguntas populares