Fade image with javascript

I am trying to code a simple slider with a fade effect using .js but I am stuck;
I just cant figure out where the error in my logic is:

I have an array ( the list of images) and another array which I am using to cache image objects.
the slider() function checks for and skips missing images, adds a new image to the container and calls the fade() function.
fade() gets an image node list of the target container. the count of which should be 2: the previous image and the one that slider() added.
fade() then decreases the opacity of the first image until it reaches 0, then it removes that image completely, waits for a set interval and calls fader() for the next image in the cache array, so the loop continues.

any insight would be appreciated

code here: http://raym31.home.comcast.net/fader/

I don’t know if I follow the logic in your code but I have a working script for such a simple slider that I have written some time ago and I use it on a few sites. Maybe you’ll get some inspiration from it so I’ll present it here in a most simple way:


<!DOCTYPE html>
<html>
<head>
	<script type="text/javascript" src="slider.js"></script>
</head>

<body>
	<div id="slider">
		<img src="slider1.jpg" alt="" onload="slider.init();" />
	</div>
</body>
</html>

The idea is that the first image is defined in html while the remaining ones in js. During fade-in there will be two images in the div and as the process is finished the first (old) image will be removed from DOM - and so on. Of course, you’ll have to take care of proper css so multiple images in the div appear in the same spot (posidion: relative on div, absolute on img).

I find it best to initialize the script with the inline onload handler since it is most reliable - there’s no way, AFAIK, to replicate the same behaviour in the “proper” modern way of attaching event after DOM has loaded. If your eyes hurt because of that you can always run slider.init() at the end of the page or with some DOM onload handler.

Now javascript, I’ve added comments so all explanation is in the code:

var slider = {
	freq: 18,  // time between each frame in milliseconds
	fadeStep: 2,  // amount of opacity to increase at each frame (until it reaches 100)
	bewtweenFades: 3000,  // time to wait between slider changes
	
	// here go slider files except the first one, which is defined in html
	imgFiles: [
		'slider2.jpg',
		'slider3.jpg'
	],
	current: 0,  // index number of currently visible slider
	imgs: [],  // here we will load image elements of all sliders
	
	init: function() {
		slider.imgArea = document.getElementById('slider');
		
		// load the first slider <img> into imgs (from html DOM)
		// the 'loaded' property is used later on to prevent from displaying an
		// image that has not been fully downloaded 
		var img = slider.imgArea.getElementsByTagName('img')[0];
		img.loaded = true;
		slider.imgs.push(img);
		
		// create remaining <img> elements and load into imgs
		for (var i=0; i<slider.imgFiles.length; i++) {
			img = document.createElement('img');
			img.src = slider.imgFiles[i];
			img.onload = function() {
				this.loaded = true;
			}
			slider.imgs.push(img);
		}
		
		setTimeout(slider.fadeNext, slider.bewtweenFades);
	},
	
	/* initialize fade transition into the next image */
	fadeNext: function() {
		slider.current++;
		
		if (slider.current >= slider.imgs.length) {
			// reached the end of sequence - start from beginning
			slider.current = 0;
		}
		
		if (!slider.imgs[slider.current].loaded) {
			// give up if image is not loaded and try again in a second
			slider.current--;
			setTimeout(slider.fadeNext, 1000);
			return;
		}
		
		// add the next image to DOM just after currently visible <img>
		// initially at opacity 0
		var img = slider.imgs[slider.current];
		slider.setOpacity(img, 0);
		
		slider.imgArea.appendChild(img);

		slider.opacity = 0;  // internal opacity counter (doesn't affect display)
		slider.currentImg = img;
		setTimeout(slider.fadeIn, slider.freq);
	},
	
	/* fade in <img> */
	fadeIn: function() {
		slider.opacity += slider.fadeStep;
		if (slider.opacity > 100) {
			slider.opacity = 100;
		}
		
		slider.setOpacity(slider.currentImg, slider.opacity);
		
		if (slider.opacity < 100) {
			// continue fading
			setTimeout(slider.fadeIn, slider.freq);
		} else {
			// fading finished - new <img> is fully visible
			// so let's remove old <img> from DOM
			var firstImg = slider.imgArea.getElementsByTagName('img')[0];
			slider.imgArea.removeChild(firstImg);
			setTimeout(slider.fadeNext, slider.bewtweenFades);
		}
	},
	
	/* cross-browser set opacity to element */
	setOpacity: function(elem, op) {
		op = Math.round(op);
		elem.style.opacity = op/100;
		elem.style.filter = "alpha(opacity=" + op + ")";
	}
}

Hi dresden_phoenix,

The problem in your code is in the following block:

if (IMGcahe[s] !='skip'){
  if(IMGcahe[s].complete){
    fstep=25;
    document.getElementById(targ).appendChild(IMGcahe[s]);
    fade(fstep,fstep,to,s,targ);
  }
}  else {
  slider(targ,s+1,to)
}

IMGcahe[s] is never set to “skip”, so only the inner if statement executes, the else block never gets called.

If you move the else block up one level, the images start cycling, although the blank images aren’t skipped and the captions appear to be quite random, so maybe this isn’t how things are meant to be.

if (IMGcahe[s] !='skip'){
  if(IMGcahe[s].complete){
    fstep=25;
    document.getElementById(targ).appendChild(IMGcahe[s]);
    fade(fstep,fstep,to,s,targ);
  } else {
    slider(targ,s+1,to)
  }
}

Nonetheless, I hope this helps you somewhat.

Edit: Oops, beaten to it by Lemon Juice :slight_smile:

thank guys.

LJ has given me something else to study.

It turns out that my onError event was not firing (syntax error, how ironic), so Pullo was kinda-right; moving up the else{} actually would have made the slide switch prematurely. Once I fixed the syntax on my OnErr everything started to work. Thanks again.