4

我绘制了几个图像,其功能类似于:

context.drawImage(img, width / 2 * (-1), height / 2 * (-1), width, height);

我读过我需要等待图像加载后才能绘制它,如下所示:

img.onload = function() {
    context.drawImage(img, width / 2 * (-1), height / 2 * (-1), width, height);
};

然而,这会导致图像被绘制,但之后没有绘制任何内容,因为我每隔几毫秒调用一次绘制函数,因为它是简单游戏“动画”循环的一部分。

在我的 init() 函数中继续运行代码之前,有没有一种方法可以等待 onload 事件?

我想是这样的:

var image_loaded = false;
img.onload = function() {
    image_loaded = true;
};
if(image_loaded) {
    animate();
}

应该管用?除非我需要添加一个 timeOut 函数来继续调用 init() 直到 image_loaded 为真?

4

2 回答 2

4

现场演示

var imagesLoaded = [],
    images = [
        'http://www.zombiegames.net/inc/screenshots/The-Last-Stand-Union-City.png', 
    'http://www.zombiegames.net/inc/screenshots/Lab-of-the-Dead.png',
    'http://www.zombiegames.net/inc/screenshots/Zombotron.png',
    'http://www.zombiegames.net/inc/screenshots/Road-of-the-Dead.png'],
    canvas = document.getElementById("canvas"),
    ctx = canvas.getContext("2d");

canvas.width = 640;
canvas.height = 480;

function init(){
    // just loops through the images.
    if(imagesLoaded.length > 0){
        ctx.drawImage(imagesLoaded[0], 0, 0, 640, 480);
        imagesLoaded.push(imagesLoaded.shift());   
    }
    setTimeout(init,500);
}

function preload(){
    for(var i = 0; i < images.length; i++){
        (function(value){
            return function(){
                var loadedImage = new Image();
                loadedImage.src = images[value];
                loadedImage.onload = function(){
                    imagesLoaded.push(loadedImage);  
                } 
            }();
        })(i);

    }
    checkLoaded();
}

function checkLoaded(){
    if(imagesLoaded.length === images.length){
        console.log(imagesLoaded.length);
        init(); 
    } else{
        setTimeout(checkLoaded,30);
    }
}

preload();

以上是如何预加载图像并等待执行其他操作的示例。基本上,您所做的是将所有图像放在一个数组中,并将onload事件添加到每个图像中。当他们通过它们将我加载到另一个包含所有加载图像的数组中时。一旦两个数组的长度匹配,所有图像都可以使用了。

另一种方法是在加载时增加一个计数器,并根据数组的长度检查它的值。当计数器变量等于图像数组的长度时,这意味着它们都已加载并可以使用。

于 2013-05-15T13:32:07.773 回答
3

我创建了一个简单的小型库来简化图像的加载。

检查演示

请参阅下面的库代码:

// Simple Image Loader Library
window.Loader = (function () {
var imageCount = 0;
var loading = false;
var total = 0;

// this object will hold all image references
var images = {};

// user defined callback, called each time an image is loaded (if it is not defined the empty function wil be called)
function onProgressUpdate() {};
// user defined callback, called when all images are loaded (if it is not defined the empty function wil be called)
function onComplete() {};

function onLoadImage(name) {        
    ++imageCount;
    console.log(name + " loaded");

    // call the user defined callback when an image is loaded
    onProgressUpdate();

    // check if all images are loaded
    if (imageCount == total) {
        loading = false;
        console.log("Load complete.");
        onComplete();
    }

};

function onImageError(e) {
    console.log("Error on loading the image: " + e.srcElement);
}

function loadImage(name, src) {
    try {
        images[name] = new Image();
        images[name].onload = function () {
            onLoadImage(name);
        };
        images[name].onerror = onImageError;
        images[name].src = src;
    } catch (e) {
        console.log(e.message);
    }
}

function getImage(/**String*/ name){
    if(images[name]){
        return (images[name]);
   }
    else{
        return undefined; 
    }
}

// pre-load all the images and call the onComplete callback when all images are loaded
// optionaly set the onProgressUpdate callback to be called each time an image is loaded (useful for loading screens) 
function preload( /**Array*/ _images, /**Callback*/ _onComplete, /**Callback <optional>*/ _onProgressUpdate) {
    if (!loading) {

        console.log("Loading...");
        loading = true;

        try {
            total = _images.length;
            onProgressUpdate = _onProgressUpdate || (function(){});
            onComplete = _onComplete || (function(){});                

            for (var i = 0; i < _images.length; ++i) {
                loadImage(_images[i].name, _images[i].src);                    
            }
        } catch (e) {
            console.log(e.message);
        }
    } else {
        throw new Error("Acess denied: Cannot call the load function while there are remaining images to load.");
    }
}

// percentage of progress
function getProgress() {
    return (imageCount / total)*100;
};

// return only the public stuff to create our Loader object
return {
    preload: preload,
    getProgress: getProgress,
    getImage: getImage,
    images: images // have access to the array of images might be useful but is not necessary
};
})();

这个怎么运作

为了确保图像已加载并且您的应用程序可以使用它们,库具有该Loader.preload方法。

preload 方法将接收一个对象数组,每个对象都包含您要加载的图像的名称和 src 属性。或者,您可以设置onComplete回调(在加载所有图像时调用)和onProgressUpdate回调(在每次加载图像时调用)。如果您想为您的onProgressUpdate应用程序创建加载屏幕,则回调很有用。

使用Loader.getProgress()获取随时加载的图像的百分比。

要获取加载的图像的引用,请调用Loader.getImage(name)其中 name 是图像的名称属性(字符串)。

如果您出于某种原因需要遍历所有图像,请使用Loader.images. 它是在其属性中包含对图像的所有引用的对象。

像这样使用:

var images = [{name: "img1", src: "http://...a.."}, 
              {name: "img2", src: "http://...b.."},
              ...
              {name: "imgN", src: "http://...N.."}];

function onProgressUpdate(progress){
    ...
    drawProgressBar(progress); // just an example of what you can do
    ...
}

function onComplete(){
    ...        
    // get an Image from Loader object
    var texture = Loader.getImage("img2");
    // or use this:
    var texture = Loader.images.img2; // or still Loader.images["img2"]
    ...

    // iterate over the images
    for (var img in Loader.images){
        console.log(Loader.images[img].src);
    }
    ....
}

Loader.preload(images, onComplete, onProgressUpdate);

如果没有,请检查演示。

于 2013-05-15T19:19:59.597 回答