web-dev-qa-db-ja.com

「CanvasRenderingContext2D」で「drawImage」の実行に失敗しました

次のエラーが発生しました。

Uncaught TypeError: 'CanvasRenderingContext2D'で 'drawImage'の実行に失敗しました:指定された値はタイプ '(HTMLImageElementまたはHTMLVideoElementまたはHTMLCanvasElementまたはImageBitmap)'ではありません

ここで同じエラーへの参照を見ましたが、実装は地雷とは異なりました。これはゲームであり、いくつかの画像をレンダリングしますが、それでもこのエラーが発生します。これが私のコードです:

これは、chromeがエラーを示している行です。

_for (row = 0; row < numRows; row++) {
    for (col = 0; col < numCols; col++) {
        /* The drawImage function of the canvas' context element
         * requires 3 parameters: the image to draw, the x coordinate
         * to start drawing and the y coordinate to start drawing.
         * We're using our Resources helpers to refer to our images
         * so that we get the benefits of caching these images, since
         * we're using them over and over.
         */
         ctx.drawImage(resources.get(rowImages[row]), col * 101, row * 83);
        }
}
_

それはctx.drawImage(resources.get(rowImages[row]), col * 101, row * 83)です。

これは完全な関数render()です。画像は次の配列に含まれています。

_function render() {
        /* This array holds the relative URL to the image used
         * for that particular row of the game level.
         */
        var rowImages = [
                'images/water-block.png',   // Top row is water
                'images/stone-block.png',   // Row 1 of 3 of stone
                'images/stone-block.png',   // Row 2 of 3 of stone
                'images/stone-block.png',   // Row 3 of 3 of stone
                'images/grass-block.png',   // Row 1 of 2 of grass
                'images/grass-block.png'    // Row 2 of 2 of grass
            ],
            numRows = 6,
            numCols = 5,
            row, col;

        /* Loop through the number of rows and columns we've defined above
         * and, using the rowImages array, draw the correct image for that
         * portion of the "grid"
         */
        for (row = 0; row < numRows; row++) {
            for (col = 0; col < numCols; col++) {
                /* The drawImage function of the canvas' context element
                 * requires 3 parameters: the image to draw, the x coordinate
                 * to start drawing and the y coordinate to start drawing.
                 * We're using our Resources helpers to refer to our images
                 * so that we get the benefits of caching these images, since
                 * we're using them over and over.
                 */
                 ctx.drawImage(resources.get(rowImages[row]), col * 101, row * 83);
            }
          }


        renderEntities();
    }  //END RENDER
_

リソースは、画像のキャッシュを作成する別個のファイル_resources.js_であり、これが役立つ場合に備えてコードは次のとおりです。

_(function() {
    var resourceCache = {};
    var loading = [];
    var readyCallbacks = [];

    /* This is the publicly accessible image loading function. It accepts
     * an array of strings pointing to image files or a string for a single
     * image. It will then call our private image loading function accordingly.
     */
    function load(urlOrArr) {
        if(urlOrArr instanceof Array) {
            /* If the developer passed in an array of images
             * loop through each value and call our image
             * loader on that image file
             */
            urlOrArr.forEach(function(url) {
                _load(url);
            });
        } else {
            /* The developer did not pass an array to this function,
             * assume the value is a string and call our image loader
             * directly.
             */
            _load(urlOrArr);
        }
    }

    /* This is our private image loader function, it is
     * called by the public image loader function.
     */
    function _load(url) {
        if(resourceCache[url]) {
            /* If this URL has been previously loaded it will exist within
             * our resourceCache array. Just return that image rather than
             * re-loading the image.
             */
            return resourceCache[url];
        } else {
            /* This URL has not been previously loaded and is not present
             * within our cache; we'll need to load this image.
             */
            var img = new Image();
            img.src = url;
            img.onload = function() {
                /* Once our image has properly loaded, add it to our cache
                 * so that we can simply return this image if the developer
                 * attempts to load this file in the future.
                 */
                resourceCache[url] = img;

                /* Once the image is actually loaded and properly cached,
                 * call all of the onReady() callbacks we have defined.
                 */
                if(isReady()) {
                    readyCallbacks.forEach(function(func) { func(); });
                }
            };

            /* Set the initial cache value to false, this will change when
             * the image's onload event handler is called. Finally, point
             * the images src attribute to the passed in URL.
             */
            resourceCache[url] = false;

        }
    }

      function get(url) {
        return resourceCache[url];
    }

    /* This function determines if all of the images that have been requested
     * for loading have in fact been completly loaded.
     */
    function isReady() {
        var ready = true;
        for(var k in resourceCache) {
            if(resourceCache.hasOwnProperty(k) &&
               !resourceCache[k]) {
                ready = false;
            }
        }
        return ready;
    }

    /* This function will add a function to the callback stack that is called
     * when all requested images are properly loaded.
     */
    function onReady(func) {
        readyCallbacks.Push(func);
    }

    /* This object defines the publicly accessible functions available to
     * developers by creating a global Resources object.
     */
    window.resources = {
        load: load,
        get: get,
        onReady: onReady,
        isReady: isReady
    };
})();
_

Chromeは、同じエラーの下に他の2つのセクションもリストしました。

_var main = function () {
    var now = Date.now();
    var delta = now - then;

    update(delta / 1000);
    render();

    then = now;

    //Request to do this again ASAP
    requestAnimationFrame(main);
}
_

エラーはrender呼び出しrender()にあります。

そして、次のようにmain()を呼び出すファイルの最後の行:

_// Let's play this game!
var then = Date.now();
reset();
main();
_
7
Janice

ロード、オンレディ、コールバックメカニズムは次のようになります。

だから私はすべてを開始するためのメイン関数として行います:

_assets = ['images/water-block.png',
          'images/stone-block.png',
          'images/grass-block.png'
         ];
var then = Date.now();
reset();
resources.onReady(main);
resources.load(assets);
_

resources.get()が画像の読み込みを続行する場合でも、つまり本質的に非同期である場合でも、drawimageはリソースがそこにあることを想定しており、読み込まれてから描画されないため、エラーが発生します。

2
AndreaBogazzi