So far my program is working the way I want it to. This works fine:
// Player object
var player = {
x: 10,
y: 10,
draw: function () {
ctx.drawImage(playerImg, 0, 0);
...
Should I check if playerImg is loaded first, even though it works correctly so far?
Also, what is the best way to check. I was thinking about putting all the images in an array. Then check with the onLoad function. If they are all loaded then I will start the game loop. Is this a good idea?
Thanks
How image loading works
You need to check if the image is loaded as image loading is asynchronous. You may experience that your code works sometimes without. This is mainly because your image exists in the cache and the browser is able to load it fast enough before the drawImage is called, or the image exists on local disk.
However, new users will need to download the data first and you don't want first-time users to experience errors such as images not showing because they are not finished loading.
As it works asynchronous your code will continue to execute while the image loading takes place in the background. This may cause your code to execute before the image has finished loading. So handling image loading is important
Handling multiple images
You can load all your images first (or those you need to start with) and you can define them using array:
var imageURLs = [url1, url2, url3, ...],
images = [],
count = imageURLs.length;
Then iterate and create the image elements:
for(var i = 0; i < count; i++) {
/// create a new image element
var img = new Image();
/// element is valid so we can push that to stack
images.push(img);
/// set handler and url
img.onload = onloadHandler;
img.src = imageURLs[i];
/// if image is cached IE (surprise!) may not trigger onload
if (img.complete) onloadHandler().bind(img);
}
and in the callback function do the inventory count:
function onloadHandler() {
/// optionally: "this" contains current image just loaded
count--;
if (count === 0) callbackDone();
}
Your callback is the code you want to execute next. Your images will be in the array images in the same order as the imageURLs.
For production you should also incorporate an onerror handler in case something goes wrong.
Related
i am making a game based on draw images and clear it every some part of second.
i started with:
var peng = new Image();
and then:
peng.onload = function() {
context.drawImage(peng, pengXPosition, pengYPosition, pengWidth, pengHight);
};
and in the loop:
var i=0;
function pengMoveRight(){ i++;if(i==1){peng.src = 'images/1.png';}else if(i==2)
{peng.src = 'images/2.png';} else if(i==3){peng.src = 'images/3.png';}else if(i==4){
peng.src = 'images/4.png';}else if(i==5){peng.src = 'images/5.png';}else if(i==6){
peng.src = 'images/6.png';i-=6;}}
when i run it it works well on IE but on chrome and mozilla it`s too slow and the character is about to disappear .. i used setinterval(); once and window.requestAnimationFrame(); once and both of them cause the same problem.
what should i do to make it smooth move?
here is the full script http://mark-tec.com/custom%20game/
Instead of changing the source, try to create several Image objects instead. That way, the drawImage call can always use a pre-loaded image.
You need to preload all the images or use the sprite method (all images packed into a single sprite) in order to avoid the initial delay caused by the image loading only when it's needed.
However, after that initial problem, your example should run fine once all the images are cached.
I want to upload a texture to webgl, and most tutorials do something like this:
var textureImage = new Image();
textureImage.src = "img/texture.png";
textureImage.onload = function() { ...texture loading code... };
So the texture doesn't actually get uploaded to webgl until later, after the image has loaded.
However, I have an image on the DOM that I want to use as a texture, and this image will for sure be loaded because my JavaScript doesn't run until all of the page's content has fully loaded.
How do I get that image on the DOM and upload it to webgl immediately? Instead of waiting for a callback.
It's not because your page has fully loaded that your images are loaded too. They are not necessary on your page.
Even if that is the case, you can use onload callback without problem: it will be called as soon as you start the image loading if it is already loaded.
If your try to bind a texture that is not fully loaded, your surface will use instead a complete white texture (or black, in some cases). So you should see the difference yourself.
By the way: to prevent a load before your callback set, it is preferable to set your callback function before your source:
var textureImage = new Image();
textureImage.onload = function() { ...texture loading code... }; // First the callback...
textureImage.src = "img/texture.png"; // Then the source.
Now my entire project is too big for a copy and paste, but here is a basic breakdown of what I'm doing right now:
$(document).ready(function(){
var canvas = $('#Canvas');
var data = {source: "images\pattern.png", repeat: "repeat"} ;
var pattern = canvas.createPattern(data); //Returns 'Null' at random
});
Things I've looked at so far:
Loading time (Somewhat related, it seems to break more often when the page loads faster)
Loading order (Doesn't seem related)
Preloading the image by forcing it to an on-page image beforehand (Doesn't fix it )
Preloading it using Image() and passing the image path to Image().src (doesn't fix it either)
Passing the Image() as data.source instead of a string path (might have helped just a little)
Initting JCanvas beforehand (No function seems to exists for this)
Creating the pattern as early or as late as possible (Seems to change the frequency, but not by a lot)
It seems to have a mind of it's own and I can't figure out what I'm doing wrong. Anyone have a clue as to what I'm doing wrong?
-Edit1-
Debugging through the Jcanvas source right now and I think it has something to do with the context. Is there any way for me to preload the canvas context?
-Edit2-
Forget everything I've said about the context, I think I figured it out.
//JCanvas source
[...]
else {
// Use URL if given to get the image
img = new Image();
img.crossOrigin = params.crossOrigin;
img.src = source; //<-- source is the url of my image ("images\pattern.png")
}
// Create pattern if already loaded
if (img.complete || imgCtx) {
onload(); //<-- When this runs, the image pops up perfectly fine
} else {
img.onload = onload(); //<-- This is what causes the problem,
//onload never seems to actually run
// Fix onload() bug in IE9
img.src = img.src;
}
The img.onload event should happen directly after an image loads, but it never seems to happen.
I am coding a script in which the user selects a range of data, and then I fetch a bunch of images (over 150) from the server and then I loop trough them to make something like a movie. What I want to know is the most efficient way to load prevent lag when moving trough the images.
Currently I am fetching the images from the server using Ajax and store them in a array of Image objects on the JavaScript. In the HTML I have a div tag in which I wish to put the images. After I finished creating all the Image object (and setting their proper src) in the array, I do the following:
imgElem = document.createElement('img');
document.getElementById('loopLocation').appendChild(imgElem);
imgElem.src = images[0].src;
After this I just make that last call but changing the loop index. I do that every 400ms. The loop works, but sometimes it lags and it freezes on an image for longer that it is supposed to be. I want to know if I am able to improve this anymore from the client side or I just need a server that responds faster.
you might wanna consider spriting which is putting all images into one big image. with this, you only need to load one big image, and then just reposition for every scene.
or, you might also want to pre-load those 150 images, before actually using them. you can use JS array to store Image objects and then loop through that array to get your images.
var images = [];
var expectLoaded = 150;
for(var i = 0; i<expectLoaded;i++){
(function(i){
//new image object
var img = new Image();
//onload hander
img.onload = function(){
//after load, push it into the array
images.push[img];
//and check if the all has loaded
if(images.length === expectLoaded){
//preload done
}
}
//start loading this image
img.src = //path to image[i];
},(i));
}
loops block the UI thread. JS is single-threaded, meaning code gets executed in a linear fashion, one after the other. anything that comes after that loop statement will wait until the loop finishes. if that loop takes long... grab some coffee. plus, since you are manipulating the DOM, you don't see the changes since the UI thread is blocked.
but there are ways to bypass this, and one of them is using timeouts to delay and queue the code for later execution, when JS is not busy.
function animate(frameNo){
//animate frame[frameNo];
if(frameNo < total_frames){ //make the UI breate in between frames
setTimeout(function(){ //so that changes reflect on the screen
animate(++frameNo); //then animate next frame
},200);
}
}
//start
animate(0);
I agree with Joseph on his second point. Here's a nice link to accomplish image preloading before you start the loop: http://www.javascriptkit.com/javatutors/preloadimagesplus.shtml
For a sort of slideshow I'm trying to implement a clever image pre-loader, which should work as following:
On load of slideshow first image is shown and images start loading
in background in order 2, 3, 4, ...
If user decides to switch to image n (which can be done via
search or thumbs or ...) and the triggered preload (from 1.) didn't load n yet, the order (2, 3, 4, ...) established in 1. will be re-organized with n as first element.
Other possibility for 2. could be to suspend preloading, load image n, and continue preload, but I'd prefer first idea because this will give you the freedom of more sophisticated re-ordering, e.g. (n, n+1, n+2, ..., last, 1st-not-loaded, 2nd-not-loaded, ...).
So far I just did a simple preload-loop like that:
for (var i = 0; i < issue.pages.length; i++)
{
log("preloading image from URL " + issue.pages[i].imageUrl);
var img = new Image();
img.onload = function()
{
log("reading loading image " + this.src);
};
img.src = issue.pages[i].imageUrl;
}
which works fine, but seems to block downloading of other images: If I call
imageN = new Image();
imageN.src = issue.pages[n].imageUrl;
somewhere else (onClick of thumb) while images of loop still loading, imageN will not be loaded before it's its turn from order in loop.
Any ideas?
To my knowledge there is no way to stop or suspend an image loading with javascript. However, a neat way to control the order of the images loading would be to chain together their load events. Here is an example (using jQuery).
In the example I have an array imgQueue that I am using as a queue and a function loadNextImage that grabs an image off the queue to load and calls loadNextImage when the image is done loading.
function loadNextImage() {
if (imgQueue.length > 0) {
var imgN = new Image();
imgN.src = imgQueue.shift();
$(imgN).load(function(){
$("#main").append(imgN);
loadNextImage();
});
}
}
To change the order images are loading you would literally just move them ahead in imgQueue, for example if I wanted to move image 5 to the front:
imgQueue.unshift(imgQueue.splice(4,1));
This isn't perfect, for instance, unless the images are large it probably makes more sense to load them in groups. Also because loadNextImage manipulates the queue you can't keep track of images just by their original index, you'd need to do something fancy like store them as hashes so you can find them later:
var imgHashQueue = [
{name: "name", url = "url"},
...
]
Couple resources here:
http://ditio.net/2010/02/14/jquery-preload-images-tutorial-and-example/ - http://engineeredweb.com/blog/09/12/preloading-images-jquery-and-javascript
Previous SO discussion: Preloading images with jQuery