Failed to execute 'drawImage' in 'CanvasRenderingContext2D'

I got the following error:

Uncaught TypeError: Failed to execute 'drawImage' in 'CanvasRenderingContext2D': the supplied value is not of type '(HTMLImageElement or HTMLVideoElement or HTMLCanvasElement or ImageBitmap)'

I saw a link to the same error, but the implementation was different from the mines. This is a game, and it displays some images, but still gives this error. Here is my code:

This is the line where chrome indicates an error:

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); } } 

This is ctx.drawImage(resources.get(rowImages[row]), col * 101, row * 83) .

This is the full render() function. Images are contained in the following array:

 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 - a separate resources.js file that creates a cache for images, the code should be in case this helps:

 (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 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 also lists two other sections with the same error:

 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); } 

Error in rendering rendering ();

and in the last line of my file, which calls main () as follows:

 // Let play this game! var then = Date.now(); reset(); main(); 
+6
source share
1 answer

You have load, onready, the callback mechanism looks like.

So, I would make the main function to start all:

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

even if resources.get() continues to load the image, which is asynchronous in nature, you will still have an error because drawimage expects the resource to be there, not loaded and then drawn.

+2
source

All Articles