Check successful loading of pixel image in svg - javascript

Using javascript, I am adding many pixel images, by moving <image id="myimage" xlink:href="mysource.png" ... /> elements from an XMLdoc to the DOM of an SVG image in a loop, like so
var elems = this.XMLdoc.getElementsByTagName('image');
var elem = elems.item(0);
svg.appendChild(elem);
Sometimes not all of the images are completely loaded, due to network problems, or server limitations.
After loading all images, I would like to check whether that has been successful and, if not, reload the pixel image mysource.png.
I could remove and add back all <image> tags and rely on that the cached images are loaded successfully, but then I would still not know if all images were loaded in the second round.
If it was included with <img> in html, I would do this by checking image.complete, but that does not seem to work for the SVG images.
I am also using Snap.svg to manipulate the SVG. A solution based on this library would be convenient if it can help.

In SVG you listen to the load event through the load event, you can do it like this:
var elems = this.XMLdoc.getElementsByTagName('image');
var elem = elems.item(0);
elem.addEventListener("error", replaceImage);
svg.appendChild(elem);
function replaceImage(e){
var parent = this.parentNode;
var newImage = this.cloneNode();
newImage.addEventListener("error", replaceImage);
parent.removeChild(this);
parent.appendChild(newImage);
}

Related

Changing src attribute of image element and getting size properties

I encounter a problem while performing changes on an img element via javascript:
I build a framework to cycle through different images via the arrow keys of the keyboard. I do this by loading all image urls into an array and then changing the src attribute of the img element accordingly.
So far everything works fine. But now I want to display the naturalHeight and naturalWidth of the current image. Unfortunately when I cycle through the images the sizes of the image preceeding the current image is displayed, although the element shows the correct image.
has this something to do with load order and rendering?
I would be very thankful if someone could help me on that issue.
best regards
Max
On the comments:
I simply load the images by:
imageLeft.setAttribute("src", imagesOld[rowCounter]);
imageRight.setAttribute("src", imagesNew[rowCounter]);
I have a function for updating the size information:
function updateSizeInformation() {
var imageLeftX = $find("<%= txtXImageLeft.ClientID %>");
var imageLeftY = $find("<%= txtYImageLeft.ClientID %>");
var imageRightX = $find("<%= txtXImageRight.ClientID %>");
var imageRightY = $find("<%= txtYImageRight.ClientID %>");
var imageLeft = document.getElementById("imageLeft");
var imageRight = document.getElementById("imageRight");
imageLeftX.set_value(imageLeft.naturalWidth);
imageLeftY.set_value(imageLeft.naturalHeight);
imageRightX.set_value(imageRight.naturalWidth);
imageRightY.set_value(imageRight.naturalHeight);
}
And a function to fit the image to the parent div:
function fitImagesToContainers() {
var divLeft = document.getElementById("imageContainerLeft");
var divRight = document.getElementById("imageContainerRight");
var imageLeft = document.getElementById("imageLeft");
var imageRight = document.getElementById("imageRight");
if (imageLeft.naturalWidth > imageLeft.naturalHeight) {
imageLeft.setAttribute("width", divLeft.clientWidth);
imageLeft.setAttribute("height", divLeft.clientWidth * (imageLeft.naturalHeight / imageLeft.naturalWidth));
} else if (imageLeft.naturalWidth < imageLeft.naturalHeight) {
imageLeft.setAttribute("height", divLeft.clientHeight);
imageLeft.setAttribute("width", divLeft.clientHeight * (imageLeft.naturalWidth / imageLeft.naturalHeight));
}
}
When you set the "src" attribute of an image element the page has not loaded, it normally instigates an asynchronous retrieval of the image file resource. After the image onload event fires the image element properties should represent that of the retrieved image, but be unpredictable before then.
If the code you provided executes synchronously it will run into the problem you report.
In Mozilla Firefox (at least) the image attributes can be that of the previous image if inspected immediately in the same script execution, because the new/next image has yet to be retrieved. Exactly what happens if the page has previously loaded the same image may be unpredictable - I found it giving correct dimension values immediately.
I tested this with standard javascript and do not wish to suggest how to program onload event handlers in jQuery . I did come across this other StackOerflow question on javascript, image onload() doesnt fire in webkit if loading same image which may be of interest.

Once an image has failed loading, how can I make the browser retry?

I'm making a Chrome extension which in order to reduce bandwidth usage it stops all outcoming requests which are images.
I want to provide functionality where if the user clicks on the image (or technically a layer on top of that image) it would try to reload the image, this time not being blocked by the extension.
How can I tell the browser to retry loading the image? And if there isn't a straightforward way to do it, what would be a work around? Deleting the old image from the DOM and adding it again?
Any help is appreciated. :)
EDIT 1:
To answer #CBroe's question:
Using the chrome.webRequest.onBeforeRequest API in a background script.
To answer #jfriend00's question:
The usual placeholder "couldn't load image" icon, I guess also known as "broken file" icon:
See all those broken images?
That screenshot also illustrates the point of a layer on top of another image. Should those images not be broken, the loaded image would be there but that layer (the one in a dark grey which shows the image's dimensions) still remains there.
The desired href still exists there in the img tag:
If simply assigning the same src value to the img element is not enough¹, then create a new Image object in JavaScript, and assign the value to its src property.
¹ It might not be, if the browser just goes, “oh hey, that is the same value for the src attribute that the img already had, so I don’t have to do anything” – creating a new JS Image object however should make the browser request that resource again if he realizes he does not have it cached already.
What I would do instead is replace the URLs of the images with an image from your extension. A 1x1 pixel transparent GIF or PNG.
When you do this, add an attribute to all of the elements you replaced... something like data-yourextension-originalurl, with the URL of the original image. If the user then wants to load images, it's easy enough to go back and fix those image elements.
While I'm not too familiar with the Chrome API, a quick glance seems to suggest that there's no way to get the specific img element from each onBeforeRequest, which you'd need to know in order to figure out where to attach custom code.
This may be better accomplished with native JavaScript of some sort. For example, if Chrome lets you inject code on load, you could apply a function like the one below to all img elements after document load but before image load.
// Given an img element, replaces its src with a placeholder URL,
// and sets its click action to load its original src
function makePlaceholder(elem){
elem["data-oldtitle"] = elem.title;
elem["data-oldhref"] = elem.href;
elem["data-oldsrc"] = elem.src;
elem["data-oldonclick"] = elem.onClick;
elem.title = "Click to load the blocked image.";
elem.href = '';
elem.src = "http://example.com/placeholder.png";
elem.onClick = function(){
this.src = this["data-oldsrc"];
this.title = this["data-oldtitle"];
this.href = this["data-oldhref"];
this.onClick = this["data-oldonclick"];
};
}
The simple way to force reloading an image in JavaScript is:
var img = document.getElementById("myImage");
img.src = img.src.replace(/\?.+/,"") + "?" + new Date().getTime();
This adds a unique QueryString to the image which basically forces the browser to not use a cached version of the image.

Image width traces zero with onload when cached

I'm building a Javascript lightbox and I'm trying to adjust the size once the image has loaded. I'm using the code below, which works fine - it outputs the correct width once loaded.
My problem:
When I refresh, it will load the image instantly from the cache, and it seems to bypass the load. I get an instant zero for the width. Why does this happen?
My code:
var oImage = new Image();
oImage.src = 'http://mydomain.com/image.png';
container.html(oImage);
oImage.onload = function(){
alert(this.width);
}
** Update **
#Alex: This is the code I've tried with your plugin, I assume I'm probably doing something wrong. I'd be eager to get this working because your plugin looks quite good.
container.waitForImages(function() {
var cWidth = $(this).width();
alert("width: "+cWidth); // returns 0 - works first time but not cached
});
// Adding the image to the container for preload
container.html('<img src="mygraphic.png" />');
You need to do a few things...
Check the complete property of the img element.
Attach the load event before setting the src property.
Also, I found creating a new Image and assigning the src there is the best way to determine if the image has loaded or not.
You may want to switch the .html() and the .onload() calls.
If the image is loading from cache, I'm imagining that the .html() call completes before the script has had a chance to attach a function handler to the image's onload event. Therefore, effectively bypassing the load event itself (as the image has already loaded).
If it's still downloading the image (i.e. not cached), there will be more than enough time to call the .onload attach before the image completely finishes rendering.
While you're at it, you may want to do this the jQuery way, just so you're attaching events more similarly to DOM2 than DOM0.
var image = $('<img/>', {
src : 'http://mydomain.com/image.png'
}).load(function () {
alert(this.width);
})
// maybe clear container before if you want
.appendTo(container);
If we're going to have to set the src after the onload, we might as well do this instead:
var image = $('<img/>')
.load(function () {
alert(this.width);
})
.attr('src','http://mydomain.com/image.png')
.appendTo(container)
;
Hopefully that works cleanly.
This answer JavaScript: Know when an image is fully loaded suggests that you should set onload before setting src

Animation with image preloading

I have a list of objects MyObject and that looks like this:
var Obj1 = {'ImgTop':'500px','ImgLeft':'200px','ImgSrc':'/image1.jpg'}
var Obj2 = {'ImgTop':'300px','ImgLeft':'100px','ImgSrc':'/image2.jpg'}
I load these objects into an array like this:
var AnimCycle = new Array(2);
AnimCycle[0] = Obj1;
AnimCycle[1] = Obj2;
In my code, there are actually 15 objects loaded in the array. I have function that gets called recursively and inside the function, I have this line:
$('#HomeImg').attr('src', AnimCycle[PanelID].ImgSrc);
The problem is that the loading of the image happens when the line is triggered. How can I make the images preload?
Thanks for your suggestions.
Here is a simple script which helps to load images before hand using javascript.
$.each(data, function(index, item) {
var tempImage = new Image();
tempImage.src = item.url;
preloadedImages.push(tempImage);
}
where data as an array of image data
data=
{
name:'NameofImage',
url:'http://www.website.com/image1.jpg',
}
To display the images you can simply add the images to the DOM
$("img").attr({
src: item.src
}).appendTo("#target");
I have a simple jsfiddle which demonstartes the script. It takes data from an ajax request and pre-loads the images. When the user does a mouseover the target it attaches the image to the DOM.
Below is the screenshot showing the images are being loaded at the time the page gets loaded:
this reference link argues that images loaded in div which are hidden might not be pre-loaded in some of the browsers like Opera. I thought haven't verified it.
There might be other ways to load images using css if you do not want to use javascript
Hope this helps
Put all of your images in a hidden div in the html:
<div style="display:none">
<img src="/image1.jpg" />
<img src="/image2.jpg" />
</div>
They will be downloaded when the page loads, but they won't be displayed. Your JavaScript can remain as is.
If you want to do it with script, put this in your ready handler:
var imgPreloader = $("<div>").hide().appendTo("body");
$.each(AnimCycle, function() {
$("<img>").src(this.ImgSrc).appendTo(imgPreloader);
});

Can I load JS before images?

I want to load the js first and the images second. Reason: I want the blue rollover affect to be applied immediately. There will eventually be double the images currently on this page so it will eventually be a bigger user experience problem as it grows.
Any ideas?
http://www.rollinleonard.com/elements/
If both your JS and images are linked directly from the HTML (meaning you're using the typical <script type="javascript" src=...> and <image src=...> tags) then the load order is entirely up to the user's web browser (as far as I know).
Your best chance to control the load ordering is to load the JavaScript per usual and then have custom JS to manipulate the DOM to load the images later, e.g.:
var myDiv = document.getElementById("myImageHoldingDiv")
, img = new Image();
img.onload = function() {
myDiv.appendChild(img);
}
img.src = myImageUrl;

Categories

Resources