Binding onload event on image object in jQuery - javascript

I have following code on my site:
backgroundImages[bg_img_path_b]=new Image();
backgroundImages[bg_img_path_b].src = bg_img_path_b;
backgroundImages[bg_img_path_b].loaded="loading";
//jQuery(backgroundImages[lastImage]).unbind('load.backgroundImages');
jQuery(backgroundImages[bg_img_path_b]).bind('load.backgroundImages',function(){
if(typeof callback=='function'){
callback.call(this, bg_img_path_b);
if(showLoading) hideLoadingDC();
}
}).bind('load.cache', function(){
backgroundImages[bg_img_path_b].loaded="true";
});;
There is large gallery for images used as background-images of page wrapper. I need to preload images because of speed (the images are quite large). So I have this code (actually is only a part of bigger function, which wraps caching and so on, but this few lines are fired when image is not in cache).
backgroundImages is large array of Image objects, key is the path is the path of image. Every Image object has my property "loaded" which says if image has already been loaded, or is currently in state of loading.
As you can see from my code I am calling callback function when the image is loaded (there are changes of the background etc.)
But I have a problem with I.E<9, the callback is not successfully fired up (but not every time)..When I load my page for first it loads properly, but anytime I call this function again, it goes correctly through without errors, but the load event doesn't fired..
I really don't know where could be an error, in all browsers except older IEs it works fine..
Actually I need to debug if the event is bound correctly, but I can't see it in both IE and Chrome under load item in debugger:(
Please help I am completely screwed, really don't know what to do.

So few days ago I finally found out a solution to my problem..It seems its matter if I at first bind the onload event and then set the url of Image, or at first set the url and then bind the event..
Example
var photo = new Image();
photo.url = "http://www.something.com/something.jpg";
$(photo).bind('load',doSomething());
var photo = new Image();
$(photo).bind('load',doSomething());
photo.url = "http://www.something.com/something.jpg";
First variant runs usually ok, but sometimes it fails (in older IEs)..But the second variant is sure working propely..

which jQuery API version are you using? Try using the latest version of jQuery.
Otherwise use this simple JavaScript code to load images on calling your function on body onload:
var myimages = new Array();
var path = "images/gallery/";
function preloadimages() {
for (i = 0; i < preloadimages.arguments.length; i++) {
myimages[i]=new Image();
myimages[i].src=path+preloadimages.arguments[i];
}
}
// Enter name of images to be preloaded inside parenthesis with douable quotes.
// Extend list as desired with comma.
preloadimages("gImg1.jpg","gImg2.jpg","gImg3.jpg","gImg4.jpg" /*, etc...*/);

Related

Adding img.crossOrigin = "*" interferes with img.complete

I have a function that reads map tile images. I want to keep track of whether or not a certain image has already been cached. I'm using this function from this thread:
function is_cached(src) {
var image = new Image();
image.src = src;
return image.complete;
}
This was working great. But then I needed to do some image processing. In order to copy the image data to a canvas and process it pixel by pixel, I need to use CanvasRenderingContext2D.drawImage(image, 0, 0). But it bugs me with a cross-origin error. So I can add a image.crossOrigin = "*", which solves that problem, and I can write to a canvas and do the image processing I need. That bit looks like this:
imageOutput.crossOrigin = "*"
var demCtx;
imageOutput.onload = function(){
var c = document.createElement('canvas')
c.width = c.height = 256
demCtx = c.getContext('2d')
demCtx.drawImage(imageOutput, 0, 0)
var imageData = demCtx.getImageData(0, 0, 256, 256)
}
The issue that arises is that every time I run the larger function which contains these two bits of code, the is_cached function returns false every time, except the first time. But I know that even though is_cached is returning false, the images are indeed cached, as they are loading with 0 lag (as opposed to when a novel image is called and it takes a moment to grab it from the server).
Why might .crossOrigin = "*" be interfering with the .complete status of an image?
This is happening within an ObservableHQ notebook. Might that have something to do with it? ObservaleHQ gets weird sometimes.
ObservableHQ Notebook with the problem
You can find this code in the getTileUrl cell at the bottom. This notebook is not yet finished. You can see the cached status at the Tile Previously Cached line after you click around the map of submit changes to the inputs.
Thanks for reading.
Maybe fetch api can enforce cache using the param {cache:"force-cache"}, however images should be cached as expected. You can fetch the image and pass its blob as an image source.
replace your imageOutput.src with
imageOutput.src = URL.createObjectURL(await fetch(imageUrl, {cache:"force-cache"}).then(r => r.blob()));
make your getTileURL function async as we have to await fetch and blob to be ready to be passed as image source
async function getTileURL(latArg, lngArg, zoomArg) {
Use devtools to inspect network and see tile images coming from disk cache
edit:
just try your original code and inspect network via devtools. The tiles images are cache as expected. So no need to hack into fetch blob src.

Using gifshot to create gifs from array of base64 strings doesn't work in Firefox

I'm trying to use the gifshot library to create gifs from a canvas. I'm capturing the canvas using canvas.toDataURL(), storing those results in an array, and then passing the array to the gifshot function. This works perfectly fine in Chrome and IE, but in FF the gif never gets created. I can see that Firefox creates the temporary images of each "frame" in the DOM, but for some reason the onerror part of the image load is hit instead of the actual onload. I'm not sure why.
I'm really not sure what to try either. It's such a straight-forward method: simply pass an array of images to the gifshot function.
function createGif(array) {
gifshot.createGIF({
images: array
}, function (obj) {
if (!obj.error) {
var image = obj.image,
animatedImage = document.createElement('img');
animatedImage.src = image;
document.body.appendChild(animatedImage);
}
});
}
Where array is the base64 strings. Passing something like imgur links instead (like in their example) works just fine. It's just the array of base64 strings that FF doesn't like. I've checked, in FF, and the array that's being passed is just fine.
Here's a jsfiddle as an example: http://jsfiddle.net/dxdn6s3h/2/. Works in IE/Chrome, doesn't in FF.
i am working with gifshot also and i figured out that i need to separately init Image object and add it to the array. Below code is more clear:
var images = [];
var oneImage = new Image();
oneImage.src = base64ImageString;
images.push(oneImage);
And then use your code to export the gif image.
Hope this post can help you :)

javascript number of images

I have a small html file for personal use, with no css or php or web server. I have a folder 'imgs' (in the same folder as the .html) that contains images called image0.png, image1.png, image2.png... (all in sequence, until there is none). How could I make a javascript function that returns the number of images in that folder ?
There isn't a way to immediately get the number of image files using client-side JavaScript, the best you could do is to try retrieving the images one by one until, you get a 404 error.
You can use the onerror method of an img element to detect when a requested image doesn't exist - this method will be called if you request an image that isn't there.
This question might be useful, it contains some example code which you could use.
The general strategy would be to load each file as an image, in order, until a request failed, firing an onerror callback. Each subsequent image fetch is fired as the onload handler of the previous image.
// takes a callback that expects a single argument
function getImageCount(callback) {
imageCounter(0);
// pseduo-recursive function nested in the closure of the outer function
// (nested so `callback` is always accessible without constantly passing it)
function imageCounter(i) {
var img = new Image();
// if this failed, so the final image was the previous one
img.onerror = function() { callback(i); }
// if this succeeded, try the next one
img.onload = function() { imageCounter(i + 1); }
img.src = "image"+i+".png";
}
}
// actually run it, with callback function that gets the count
getImageCount(function(count) {
alert("There are " + count + "images.");
});
Due to restrictive same-origin policy for file: URLs, this won't work on Chrome without the --allow-file-access-from-files command line flag, and it will only work in Firefox if the images are being fetched from the same directory or a subdirectory of the current page.

Onload issue for Progress bar for preloaded images

I would like to try and set up a progress bar for several images while their loading and haven't been able to get it to work. I have several images that are preloaded like:
var Image1 = new Image();
var Image2 = new Image();
var Image3 = new Image();
Image1.onload = moveProgressBar();
Image2.onload = moveProgressBar();
Image3.onload = moveProgressBar();
Image1.src = url;
Image2.src = url;
Image3.src = url;
Something weird is happening since they're immediately running the moveProgressBar() function even though the images aren't entirely loaded yet. This happens even when approaching the page with no cache and with cache. Am I missing something? Any help would be appreciated.
The js onload event on images is a big messy mess. Different browsers handle it differently, and different versions (mostly IE) handle it differently. Plus, most browsers have iffy bugs.
Here is a short checklist:
set your onload BEFORE you set your src. (Wait for it, it will get quirkier...)
Handle onerror as well.
Handle images that already was cached. Sometimes they will not fire onload, while other times they will fire and do so imediately.
Use a generic belt-and-suspenders setTimeout()-function that polls to see if the image has gotten a width or height in the DOM. This is done differently in different browsers/versions, which means you'll have to use feature detection, starting with naturalWidth, then move on to getAttribute(width) before image.width.
And then you will still probably have some bugs... but you will only know if you test all browser/versions you intend to support.
For reference, the error was that Noah was calling each function and assigning the result to the onload. It should have been:
Image1.onload = moveProgressBar; // note the lack of ()

Getting size of javascript preloaded image

I'm trying to preload a number of images generated on the server to a small website. The preloading is done using setWindowTimeout and uses an Image object, sets the onload callback and then applies the new request uri.
For some requests, the server may have to signal that the image is 'unchanged' and I'm doing it by sending done a small 1x1 pixel gif (seems like I need to send an actual image, returning empty content will cause the Image object to not fire onload). In my onload handler I would like to determine the size of the fetched image and then determine if I should update the visual image with the given image.
Below is a snippet of my current solution (the output is a div to help debug):
refresh: function() {
var newSrc = '/screenshot.ashx?tick=' + new Date().getTime();
var imgObj = new Image();
var self = this;
// this is called when load is done
imgObj.onload = function() {
//if (imgObj.complete)
// return;
if (imgObj.width > 1 && imgObj.height > 1) {
output.innerHTML += '<br/>Updating image:' + newSrc;
img.src = newSrc; //fiddler shows no reload here, read from cache
}
else {
output.innerHTML += '<br/>Empty image:' + newSrc;
}
self.setupNewRefresh();
};
output.innerHTML += '<br/>Loading image:' + newSrc;
imgObj.src = newSrc;
},
I seem to have two problems:
a) the imgObj.complete is false when the function is first called but it is only called once (hence my commenting it out) and
b) I can't seem to rely on the width or height property of the image when loaded. From my tests of fetch the 1x1 pixel, it sometimes reads out 50 which seems to be default when creating a new Image() and it sometimes reads out the correct size of 1.
My ultimate goal is to have a small chunk of javascript logic that queries the server for a new image periodically, does nothing if nothing new has happened (1 pixel image) or loads the new image. I might be going about it the wrong way here or have overlooked important properties or calls, so I'm happy to receive feedbacks.
EDIT: upon suggestion from mplungjan, I preloaded into a hidden div instead, which helped me with problem b). Still no solution to problem a) though; reports complete = false once and is not called again
I'll go ahead and answer my own question.
Preloading the image into a hidden element in the DOM instead of a code-level element was the trick for actually getting correct sizes (thanks mplungjan). The a) issue, namely the complete event, remains unsolved.
As a side note I ended up using the XMLHttpRequest instead as it allowed by to look at the size of the payload returned.

Categories

Resources