Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

angelwatt

Moderator emeritus
Original poster
Aug 16, 2005
7,852
9
USA
On a recent little project I've come across something interesting and frustrating. Say you have the following code inside a script tag within the head tag.
Code:
var a = document.createElement('img');
a.setAttribute('src', 'image.png');
alert(a.width);
The first time the page loads it will alert 0, but if you reload the page it'll give you the correct width of that image. I've also tried the alternative technique below.
Code:
var a = new Image();
a.src = 'image3.png';
alert(a.width);
I get the same results. This gets quite frustrating when you're centering the image on the screen and getting zero widths and heights for the image as you can imagine. So far the only way I've been able to get the images to center without a reload is to do getElementById on it a "moment" later and adjust the style attributes (using the now accessible width/height) of the image at that point.

Though I have a working solution (at least I think it is), I was curious if other people had thoughts on the subject and maybe better solutions they'd like to share. PHP handles this stuff nicely, but prefer not to do an AJAX call. I want pure JavaScript with maybe a hint of CSS if need be.
 
Until the browser downloads the image, it's not going to know the image width. Is there a previous page where you can reference the image invisibly so that the browser has a chance to cache it prior to reaching your page?
 
Until the browser downloads the image, it's not going to know the image width. Is there a previous page where you can reference the image invisibly so that the browser has a chance to cache it prior to reaching your page?

Well it happens all on the same page. I'm creating my own version of lightbox essentially. I'm still going through their code to see how they get around it, though it seems they're using a similar technique as I am, but they animate the appearance of the image so it caches along the way.
 
To show one solution (that I'm not very satisfied with since it requires a delay):
Code:
var a = document.createElement('img');
a.setAttribute('src', 'image.png');  // starts to put image in cache
setTimeout('alertWidth()', 400); // 400 millisecond delay
function alertWidth() { alert(a.width); }
So setting the attribute to the file does start to put the image into cache, but apparently it needs a little time before the images attributes become available. The specific time needed depends on the connection speed between the browser and the server. I had been using 100 ms, which worked fine from home where my server is at, but from work that doesn't seem to be a long enough delay so going to increase it to probably 400 ms.

Still though, I'd like to hear other people's thoughts and if they have different solutions.
 
Please try this possible solution:

Code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Test</title>

<script language="javascript" type="text/javascript">
<!--//
function MakeVisible() {
	var imgobj=document.getElementById('mypic');
	var divobj=document.getElementById('mydiv');
	divobj.style.visibility="visible";
	alert(imgobj.width);
}
//-->
</script>

</head>

<body onload="MakeVisible()">

	<div id="mydiv" style="display: none">
		<img src="whatever.png" alt="Blah blah...." id="mypic"  />
	</div>

</body>
</html>


What I did was wrap a div around the image, assigned id's to both, set only the div hidden. The body onLoad calls a simple function that creates objects for the div and image, setting the div visible and then alerting the image size as in your example.

I included the complete HTML page to show you placement of things and what doctype I was using. If this works for you I'm sure you can streamline and tweak.

Please let me know, I tried it in FF and MSIE making sure to dump my cache before testing.

-Jim
 
Well, not quite what I was after Jim. First, a small note, I think you meant for the style of the div to be visibility: hidden rather than display: hidden since display doesn't have a hidden value. Small point though.

By having the img tag in the HTML from the beginning, the browser is already caching the image, even if the style is set to hidden (from my understanding). In my situation (which I didn't explain well in the beginning so sorry about that), the only img tags in the HTML is for the thumbnails, not the full size image, which is why it's not cached.

I have updated my JavaScript to use a longer delay before displaying the image after creating the img element. If someone wants to check it out to see if it works for you, you can find my web site through my profile and it's in the Artwork section of my site (I'd rather not post direct links). If it centers first try let me know, and also if it doesn't. The delay isn't too horrible.
 
I made a solution to this once. My page would often not know what image would be displayed until it was displayed, and I had to measure it before the display took place. I therefore created the image object in either an invisible area (using methods such as display:none, visibility:hidden, opacity/filter:alpha 0, left:-500px, etc), and then waited for the image to load.

When an image finishes loading, it triggers some events. The most important are: onabort, onerror, onload. By handling these events, you can detect when the image has finished loading.

Example: (I have not tested this specific example, but this is how it works)
Code:
var a = document.createElement('img');
//insert the handlers BEFORE the src is set
a.onabort = imageError;
a.onerror = imageError;
a.onload = imageLoaded;

a.setAttribute('src', 'image.png');

function imageError(){
    alert("Oops: A problem occurred while displaying the image");
}
function imageLoaded(){
    alert(a.width);
}

Once the image has finished loading, finding values such as dimensions work fine.
 
Thanks CoreWeb. I tested your code you posted and it did alert the correct width, and that was without placing the image (hidden or otherwise) into the document.

I had been using the onload in an earlier version, but for whatever reason had taken it out (kept running into browser issues here and there). I'll try to get it back into my code and see what happens. I'll be sure to post back my results.
 
OK, got to try out using onload for the image and does appear to do the trick, thanks CoreWeb. I've some other little things to work out still, but that at least takes care of one thing. For anyone that wants to see what this was for you can see it in action here.

I'm glad you found that helpful. I think at one time I was using onload along with a interval check for IE (there is some way, I forgot how, to detect whether an image has loaded), but for some reason I determined that it was unnecessary in my latest javascript library.

I notice that you are letting the image load while it is visible; it may look nicer if you delayed displaying it until it had completely loaded. Just a suggestion.
 
I'm glad you found that helpful. I think at one time I was using onload along with a interval check for IE (there is some way, I forgot how, to detect whether an image has loaded), but for some reason I determined that it was unnecessary in my latest javascript library.

I notice that you are letting the image load while it is visible; it may look nicer if you delayed displaying it until it had completely loaded. Just a suggestion.

Yeah that's one of the little bugs I've got going on. I tried to hide it until after it was loaded, but for some reason IE and Opera had issues with that. It would work for the first click, but if you tried to review it, the image wouldn't reappear. It's very odd. If only Firefox and Safari were the only browsers I would have had this done a while ago. I think it's because IE and Opera don't start preloading the image until after the image is thrown on the screen. Maybe I could try a peek-a-boo tactic to fool it :)
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.