在用户点击之前,图像不会在画布上绘制

时间:2013-05-15 08:37:02

标签: javascript html5 canvas

我用一个执行类似于以下功能的函数绘制了几个图像:

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为真?

2 个答案:

答案 0 :(得分:4)

<强> Live Demo

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事件添加到每个图像中。当他们将我通过它们加载到另一个包含所有加载图像的数组中。一旦两个阵列的长度匹配,所有图像都可以使用。

另一种方法是在加载计数器时递增计数器,并根据数组的长度检查其值。当计数器变量等于图像数组的长度时,意味着它们已经全部加载并准备好使用。

答案 1 :(得分:3)

我创建了一个简单的小型库,可以轻松加载图像。

Check the demo

请参阅下面的库代码:

// 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是图像的名称属性(String)。

如果由于某种原因需要迭代所有图像,请使用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);

Check the demo如果你没有。