tags:

views:

60

answers:

3

I have a array of static images that I am using for an animation.

I have one frame image that I want to update the image of and I have seen a lot of tutorials on animating images with javascript just simply update the source of an image.

frame.src = animation[2].src; etc

When I look at the resource tracking in chrome, it doesnt look like they are getting cached even thought the web browser does download the image more than once but not once for each time it is displayed, so there is still some browser caching going on.

What is the best way to replace the frame image object with another image?

A: 

Hi,

Well, you can either position all images absolute and give them a z-index, then use jQuery/JS to shuffle their z-indexes, bringing a new one to the top in a cross fader style,

or you can take all the id's and fadeone in slightly faster than the last one fades out.

Like so:

function fader(func) {
var currID = $('#mainimg ul').data('currLI');
var currLiStr = '#mainimg ul li#' + currID;
img = $(currLiStr).find('img').attr('src');
nextID = (currID == 'six') ? 'one' : $(currLiStr).next().attr('id');
nextLiStr = $('#mainimg ul li#' + nextID);
$(currLiStr).fadeOut(3000);
$(nextLiStr).fadeIn(2000).find('div.inner').delay(3000).fadeIn('slow').delay(6000).fadeOut('slow');
$('#mainimg ul').data('currLI',nextID);
}

Note 'six' is the id of the last li, reseting it back to one, but if you do $('#mainimg ul li:last').attr('id'); and $('#mainimg ul li:first').attr('id') to get the last and first id's, you can allow it to cope with any amount of images (obviously this is with li's given id's one, two and so on, but if you are finding out the last and first id you could use any structure. Or you can set a ul width a width of all the li's multiplied, and give the li's the width of the images, and set overflow to hidden, then use JS to pull the li's left by the width of 1 li on each iteration in a slider like I have done here: http://www.reclaimedfloorboards.com/

There are loads of options

Liam Bailey
switching the images on the z axis, i didn't know that could be done. i don't need any transitioning effects but i do need to cycle the images pretty quickly. I think this is a good pointer in the right direction.
griff.steni.us
A: 

The easiest way to do it is create a separate hidden image for each frame. Something like this:

var nextImage = (function(){
  var imagePaths='basn0g01.png,basn0g02.png,basn0g04.png,basn0g08.png'.split(','),
      imageHolder=document.getElementById('custom-header'),
      i=imagePaths.length, imageIndex=i-1, img;

  for (;i--;) {
    img=document.createElement('img');
    img.src='http://www.schaik.com/pngsuite/' + imagePaths[i];
    if (i) img.style.display='none';
    imageHolder.appendChild(img);
  }

  return function(){
    imageHolder.childNodes[imageIndex].style.display='none';
    if (++imageIndex >= imageHolder.childNodes.length) imageIndex=0;
    imageHolder.childNodes[imageIndex].style.display='inline-block';
  }

}());

Try this example on this page; paste it in the console and then call nextImage() a few times. Watch the top of the page.

edit

If you already have all the images in your HTML document, you can skip most of the above and just do something like this:

var nextImage = (function(){
  var imageHolder=document.getElementById('custom-header'),
      images=imageHolder.getElementsByTagName('img'),
      i=images.length, imageIndex=0, img;

  for (;i--;) if (i) images[0].style.display='none';

  return function(){
    imageHolder.childNodes[imageIndex].style.display='none';
    if (++imageIndex >= imageHolder.childNodes.length) imageIndex=0;
    imageHolder.childNodes[imageIndex].style.display='inline-block';
  }

}());
no
img.src=imagePaths[i];no, that just changes the src of the image. this is not working and what the question was addressing
griff.steni.us
what it does is preload all the images in separate image elements and hide them all but the first one in the list. When you call nextImage, the current image is hidden and the next is shown. At least, that's the idea... I didn't test it.
no
I went ahead and tested it, it had a small error where two images would show the first time through. I fixed that up and I think it does what you want. Check out the update.
no
its still not what i needed. the question states that it needs to be done without just changing the img.src
griff.steni.us
@griff.steni.us: I updated my answer... is that closer to what you want?
no
A: 

I ended up using jquery's replaceWith command and gave all the frames a class "frame" that i could select with $('.frame') which happened to only select visible frames.

<script type="text/javascript">
        var animation = [];
        var firstFrame = 1;
        var lastFrame = 96;
        var animationFrames = 16;
        var loadedImageCount = 0;

        $(function() {

        $("button, input:submit",'#forecastForm').button();
        $("#progressbar").progressbar({
            value: 0
            });
            $('#id_Species').attr('onChange', 'loadAnimation($(\'#id_Species\').val(),$(\'#id_Layer\').val(),$(\'#id_StartTime\').val(),$(\'#id_EndTime\').val())' )
            $('#id_Layer').attr('onChange', 'loadAnimation($(\'#id_Species\').val(),$(\'#id_Layer\').val(),$(\'#id_StartTime\').val(),$(\'#id_EndTime\').val())' )
            $('#id_StartTime').attr('onChange', 'loadAnimation($(\'#id_Species\').val(),$(\'#id_Layer\').val(),$(\'#id_StartTime\').val(),$(\'#id_EndTime\').val())' )
            $('#id_EndTime').attr('onChange', 'loadAnimation($(\'#id_Species\').val(),$(\'#id_Layer\').val(),$(\'#id_StartTime\').val(),$(\'#id_EndTime\').val())' )
        });


        if (document.images) { // Preloaded images
            loadAnimation('Dry_GEM',1,1,96);
        }
        function rotate(animation, frame)
        {
            if (frame >= animation.length)
                frame = 0;
            $('.frame').replaceWith(animation[frame]);
            window.setTimeout('rotate(animation,'+eval(frame+1)+')',150);
        }
        function loadAnimation(species, layer, startTime, endTime)
        {
            layer = Number(layer);
            startTime = Number(startTime);
            endTime = Number(endTime);
            if (startTime > endTime)
            {
                swap = startTime;
                startTime = endTime;
                endTime = swap;
                delete swap;
                }
            for (i=0;i<animation.length;i++)
                delete animation[i];
            delete animation;
            animation = []
            $('#progressbar').progressbar({value: 0});
            loadedImgCount = 0;
            animationFrames = endTime - startTime + 1;
            for(i=0;i < animationFrames;i++)
            {
                animation[i] = new Image();
                animation[i].height = 585;
                animation[i].width = 780;
                $(animation[i]).attr('class','frame');
                animation[i].onload = function()
                {
                    loadedImgCount += 1;
                    $('#progressbar').progressbar({value: eval(loadedImgCount / animationFrames * 100)});
                };

                animation[i].src = 'http://[[url]]/hemi_2d/' + species + '_' + layer + '_' + eval(i+startTime) + '.png';
            }
        }
    </script>
griff.steni.us
mmm, I'm pretty sure you don't need an `eval` there. Oh wait, there's *three* unneeded evals... nice.
no
thank you for your polite and useful comments, i will take them out.
griff.steni.us
actually, i went back and tried it and removing them broke the code
griff.steni.us
try just replacing them with parentheses.
no