Google Maps v3:如何判断ImageMapType叠加层的拼贴何时完成加载?

时间:2011-09-07 23:59:38

标签: javascript events google-maps google-maps-api-3

我正在使用Google Maps v3 API,我有一个基于ImageMapType类的自定义叠加层。我想在叠加层的加载时显示某种加载指示器,但我看不出有什么方法可以知道它们何时完成。

创建叠加层的代码类似于以下内容:

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

myMap.overlayMapTypes.push(myOverlay);

以上工作正常,叠加成功加载;它似乎没有地图发出任何事件来指示ImageMapType覆盖的状态。

我希望地图在加载完瓦片时至少发出一个“空闲”事件,但据我所知,它没有。

我怎么知道ImageMapType覆盖完成加载的时间?

修改

我在jsFiddle上编写了一个测试用例:http://jsfiddle.net/6yvcB/ - 观察你的控制台输出中的“闲置”一词,以查看空闲事件何时触发。请注意,单击按钮添加叠加层时,它永远不会触发。

另外,小猫。

3 个答案:

答案 0 :(得分:10)

似乎没有“开箱即用”的方式来了解ImageMapType叠加层何时完成加载,但是由于suggestion from Martin上的Google Maps API v3 Forums结束,我能够自己添加在图层完成加载时发出的自定义事件。

基本方法是:

  • 每次请求网址时,请将网址添加到待处理网址列表
  • 覆盖ImageMapType.getTile(),以便我们可以为每个< img>添加“onload”事件侦听器。元件。
  • 当每个图像的“加载”事件触发时,从待处理的URL列表中删除该图像。
  • 当待处理的网址列表为空时,请发出我们的自定义“overlay-idle”事件。

我为下属复制了下面的代码,但是您可以在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 :(得分:1)

使用事件 tilesloaded

文档:About event tilesloaded

enter image description here

答案 2 :(得分:0)

基于@David的响应,我创建了一个纯Javascript替代方案(特别是考虑到Op没有指定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;
    };
}

可以从任何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);

奖励功能:支持多个图层和超时(如果服务器速度慢或不稳定)。