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
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.
Sorry, maybe not correct title..
I have the next question: I want to make preloading with progress bar. And I stuck on one problem.
[CODE 1]:
//Preloader code
var img = [];
img[0] = new Image();
img[0].src = 'test0.jpg';
img[0].onload = function(){
//some code
}
//.....
img[100] = new Image();
img[100].src = 'test100.jpg';
img[100].onload = function(){
//some code
}
//.....
// all images loaded
//.....
/*
for expample in this part of code I need put my image 'test0.jpg' into html
*/
var temp_img = new Image();
temp_img.src = 'test0.jpg';
The question is : will it download 'test0.jpg' again or just take it from cache?
or better to do like this [CODE 2]:
//Preloader code
var img = [];
img['test0'] = new Image();
img['test0'].src = 'test0.jpg';
img['test0'].onload = function(){
//some code
}
//.....
img['test100'] = new Image();
img['test100'].src = 'test100.jpg';
img['test100'].onload = function(){
//some code
}
//.....
// all images loaded
//.....
/*
for expample in this part of code I need put my image 'test0.jpg' into html
*/
var temp_img = img['test0'];
// draw temp_img
I want to use CODE 1. But will it slow down my app? Or better to use CODE 2? Thanks in advance.
Both methods have benefits and drawbacks.
The first method is much lighter on image elements and as a general rule, the fewer DOM elements you generate, the better. There is a chance, though, that the browser will not serve the image from the cache depending on how much information is being loaded. Worst case, you will need to fetch from the network again if the browser has removed the image from the cache.
The second method is much safer and will keep the image held in memory, meaning even if the browser doesn't cache it, it's still available. It's heavier on image elements, though.
Which solution is better depends on your situation. If you're not loading a large amount of images, I'd say solution 1 is the better choice as it leverages the browser's cache. If you really can't afford to reload images off the network, though, solution 2 is safer.
TL;DR
Solution 1 shouldn't slow down your application, but solution 2 will ensure you don't fetch from the network again.
With code 1, your preloader would be useless right? I'd go with 2
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.
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.
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