1

Once again, completely out of my depth but I need to preload some images and then add them to the page when 'all elements (including xml files etc.)' are loaded. The images and references are stored in an array for later access. Trying to draw and image from that array throws an error yet I know it is available as I can just appendTo the page:

preloadImages: function (loadList, callback) { var img; var loadedFiles = []; var remaining = loadList.length; $(loadList).each(function(index, address ) { img = new Image(); img.onload = function() { --remaining; if (remaining <= 0) { callback(loadedFiles); } }; img.src = loadList[index]; loadedFiles.push({file: 'name of image to be loaded', image: img }); //Store the image name for later refernce and the image }); } //WHEN CERTAIN OTHER CONDITIONS EXIST I CALL THE FUNCTION BELOW buildScreen: function ( imageLocs, image){ //THIS FUNCTION LOOPS THROUGH imageLocs (XML) AND CREATES CANVAS ELEMENTS, ADDING CLASSES ETC AND DRAWS PART OF A SPRITE (image) //INTO THE CANVASES CREATED var ctx = $('ID of CANVAS').get(0).getContext("2d"); var x = 'position x in imageLocs' var y = 'position y in imageLocs' var w = 'width in imageLocs' var h = 'position x in imageLocs' ctx.drawImage(image, x,y, w, h, 0, 0, w, h); //THIS THROWS AN ERROR 'TypeError: Value could not be converted to any of: HTMLImageElement, HTMLCanvasElement, HTMLVideoElement' //$(image).appendTo("#innerWrapper") //YET I KNOW THAT IT IS AVAILABE AS THIS LINE ADDS THE IMAGE TO THE PAGE } 
3
  • Are you sure that image (the argument passed into buildScreen) is not a jQuery wrapper object, instead of a pure js image object? Obviously preloadImages deals in pure images, but without seeing the code that calls buildScreen it's not certain what you are passing. Commented Feb 18, 2013 at 10:59
  • This is what calls the buildscreen function, I can append #innerWrapper with the image startSequence : function(){ $('#innerWrapper').empty(); var screenImageRef = $.grep(ST.imageFilesLoaded, function(e){ return e.file == 'AtlasSheet' }); var screenImage = $(screenImageRef[0].image); var imageLocsRef = $.grep(ST.xmlFilesLoaded, function(e){ return e.file == 'IMAGELOCS' }); var imageLocs = $(imageLocsRef[0].xml); //$(screenImage).appendTo("#innerWrapper") //appends screenImage Utilis.buildScreen('1', imageLocs, screenImage, ST.didYouSeeIt, 'ST') } Commented Feb 18, 2013 at 11:10
  • Thanks for the extra info, I've added an answer that should help. In future, if you wish to add more bulky information or code, just edit your question and add an "update" section. If you search around at other questions you'll see what people usually do :) Commented Feb 18, 2013 at 11:48

2 Answers 2

3

Problem

The issue is caused because you are passing a jQuery object to a native function, in this case ctx.drawImage, drawImage will only support native objects.

startSequence : function(){ $('#innerWrapper').empty(); var screenImageRef = $.grep(ST.imageFilesLoaded, function(e){ return e.file == 'AtlasSheet' }); var screenImage = $(screenImageRef[0].image); var imageLocsRef = $.grep(ST.xmlFilesLoaded, function(e){ return e.file == 'IMAGELOCS' }); var imageLocs = $(imageLocsRef[0].xml); //$(screenImage).appendTo("#innerWrapper") //appends screenImage Utilis.buildScreen('1', imageLocs, screenImage, ST.didYouSeeIt, 'ST') } 

Your screenImage var is created by $(screenImageRef[0].image), this will return a jQuery object that wrappers the native image object. To get back to the original native image object use the following:

screenImage.get(0) 

or

screenImage[0] 

The former is the jQuery supported way.

Solution

So the fix to your code should be either, changing the following line:

Utilis.buildScreen('1', imageLocs, screenImage.get(0), ST.didYouSeeIt, 'ST'); 

Or changing the line in the buildScreen method:

ctx.drawImage(image.get(0), x,y, w, h, 0, 0, w, h); 

... Whichever you prefer.

Confusion when debugging

The reason why everything appears to work when you append the image, is because you are using jQuery to append the image, and jQuery supports being passed jQuery wrapped elements. If you had tried to append your screenImage using native functions i.e. Element.appendChild() you would have got similar errors.

Just to help in future, it's always best to use console.log to find out what type/structure a variable actually has. Using console.log on your previous image var would have given a strange object dump of the jQuery wrapper (which might have rang alarm bells), rather than the expected [object HTMLImageElement] or some other image/console related output (depending on the browser).

Sign up to request clarification or add additional context in comments.

2 Comments

Ah superb, thanks ever so much pebbl - probably trying to walk before I can crawl! Spot on!
No problem, glad it helped... heh and nothing wrong with jumping ahead, best way to keep a sharp learning curve :)
1

I think your image preloader isn't quite correct as it uses the same img variable for all images.

Here is one that I know works well: https://gist.github.com/eikes/3925183

2 Comments

+1 It's a good thing to keep an eye out for, but it wont be causing the issue here. The img var isn't referenced outside of the preloadImages function (at least that we can see). Instead, for each $().each call, the img reference is stored as part of an object pushed to loadedFiles. So even though img is reused, each image reference will be stored safely as part of the loadedFiles array.
Thanks for your reply eikes, I need to load several different images including a sprite and need them all at once - so I need a reference in that images array so I can pass the right image to the right function, I've added a comment to what CharledB said above - sorry bit new to this and there's no code formatting

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.