2

I’m trying to figure out how to make an animation using the order of three images.

The default image is “image1.png” that always shows when the page loads.

  1. After every 5 seconds, the variable “back.src” must abruptly change to image2.png, so without fading. The default is image1.png

  2. And then after 0.5 seconds, the variable again changes but then to image3.png.

  3. 0.5 seconds later it changes back to image2.png

  4. and 0.5 later again back to image1.png.

This is to be repeated in a loop because I want to repeat the process again after 5 seconds.

My problem is, I don't know if structuring this code is the best way to go about it. How would my code need to look based on the requirement explained above?

Here's my code of what I've got so far:

var back = new Image();
back.src = "image1.png";
        function wait(miliseconds) {
            var currentTime = new Date().getTime();
            while (currentTime + miliseconds >= new Date().getTime()) {
            }
        }

        function image1() {
            wait(5000);
            back.src = "image2.png";
        }

        function image2() {
            wait(500);
            back.src = "image3.png";
        }

        function image3() {
            wait(500);
            back.src = "image2.png";
        }


function animate(){
    ctx.save();
    ctx.clearRect(0, 0, cW, cH);
    ctx.drawImage(back,0,0);        
    ctx.restore();
}
var animateInterval = setInterval(animate, 30);
Zhyohzhy
  • 640
  • 6
  • 19

3 Answers3

2

There is no wait() operation in Javascript and usually trying to make one like you are doing causes bad things to happen (event loops get starved, user interfaces get locked up, etc...). Instead, you schedule things to run in the future with setTimeout(). This allows the JS engine to do other things (like service other events happening in the system) while you are waiting for your next loop iteration and is generally very important in Javascript.

I'd suggest you just put the sequence you want into a data structure and then use a timer that iterates through the data structure, wrapping when it gets to the end:

var data = [
  ["image1.png", 5000],
  ["image2.png", 500],
  ["image3.png", 500],
  ["image4.png", 500]
];

function runAnimation() {
    var index = 0;

    function animate(image){
        ctx.save();
        ctx.clearRect(0, 0, cW, cH);
        ctx.drawImage(image,0,0);        
        ctx.restore();
    }

    function next() {
       var img = new Image();
       img.src = data[index][0];
       animate(img);

       // schedule next iteration 
       var t = data[index][1];

       // increment and wrap index if past end
       index = (index + 1) % data.length;

       setTimeout(next, t);
    }

    next();

}

To make this work properly, you will need your images to be precached so they get loaded immediately. If you aren't going to precache the images, then you will need to add onload handlers so you can know when the images have finished loading and are ready for drawing.

There is info on precaching images here: How do you cache an image in Javascript

Or, to make sure your images are loaded before drawing with them, you can use an onload handler like this:

var data = [
  ["image1.png", 5000],
  ["image2.png", 500],
  ["image3.png", 500],
  ["image4.png", 500]
];

function runAnimation() {
    var index = 0;

    function animate(image){
        ctx.save();
        ctx.clearRect(0, 0, cW, cH);
        ctx.drawImage(image,0,0);        
        ctx.restore();
    }

    function next() {
       var img = new Image();
       var nextSrc = data[index][0];
       img.onload = function() {
           animate(img);

           // schedule next iteration 
           var t = data[index][1];

           // increment and wrap index if past end
           index = (index + 1) % data.length;

           setTimeout(next, t);
       };
       img.src = nextSrc;
    }

    next();

}
Community
  • 1
  • 1
jfriend00
  • 580,699
  • 78
  • 809
  • 825
1

You can achieve it using setIterval()

Read about JS Timers Here

Here is what you need : https://jsfiddle.net/nfe81zou/3/

var image1 = "https://pixabay.com/static/uploads/photo/2016/06/17/13/02/duck-1463317_960_720.jpg";
var image2 = "https://pixabay.com/static/uploads/photo/2013/09/22/16/56/duck-185014_960_720.jpg";
var image3 = "https://pixabay.com/static/uploads/photo/2013/11/02/03/23/ducks-204332_960_720.jpg";

$(function() {
  $("#image").prop("src", image1);
  setInterval(function() {
$("#image").prop("src", image2);
setTimeout(function() {
  $("#image").prop("src", image1);
  setTimeout(function() {
    $("#image").prop("src", image3);
  }, 500);
  setTimeout(function() {
    $("#image").prop("src", image2);
  }, 1000);
}, 1500);
  }, 5000);
});
#image {
  border: 2px solid red;
  width: 400px;
  height: 200px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<img src="" id="image"/>
Himanshu Tyagi
  • 5,025
  • 1
  • 20
  • 42
  • The timing of this won't work properly. Every 500ms, you will be drawing image3. But on the intervals that are multiples of 1000, you will also be drawing image2 and on the ones that are multiples of 1500, you will also be drawing image1. This is just not what you want. There is no reliable guarantee of ordering between all your intervals and you're doing all sorts of extra setting or `.src` to values you don't even want drawn. I would not recommend this method. – jfriend00 Jun 22 '16 at 11:39
  • @jfriend00 How about now? Notice the timeout and interval – Himanshu Tyagi Jun 22 '16 at 11:46
  • Multiple interval timers that are supposed to stay perfectly coordinated between them is not a good design practice in Javascript. Interval timers are not guaranteed to be perfectly accurate. – jfriend00 Jun 22 '16 at 11:55
  • You almost got it! The first image only lasts for 5 seconds the one time after the page loads, then it just starts to change after 0.5 like the other pictures. How would you tweak it? – Zhyohzhy Jun 22 '16 at 12:00
  • Checkout the updates, order your images according to your need. – Himanshu Tyagi Jun 22 '16 at 12:05
  • Thanks a lot! This is a much better way to go about what I wanted to achieve. – Zhyohzhy Jun 22 '16 at 12:19
1

This would be my approach on this problem. The images are displayed in the order of

0 (5000ms) -> 1 (500ms) -> 2 (500ms) -> 1 (500ms) -> 0 (5000ms) ...

There is no setInterval() here. This code utilizes a pseudo recursive setTimeout() implementation.

var images = ["http://1.bp.blogspot.com/_ZRj5nlc3sp8/S-T7vOsypQI/AAAAAAAADBo/0kYfB8BM6zE/s320/beautiful+girl+pics+1.jpg",
              "http://1.bp.blogspot.com/-w4UtHwbrqBE/ViNbJWhnmvI/AAAAAAAADtY/hGbRtz993Tg/s1600/face%2Bwallpapers%2B%25282%2529.jpg",
              "http://2.bp.blogspot.com/-4kZ9Iu8QTws/ViNbL3S29fI/AAAAAAAADtw/QakqQE72N1w/s1600/face%2Bwallpapers%2B%25286%2529.jpg"],
      imel = document.getElementById("photo");
function displayImages(idx,fwd){
  var ms = 0;
  idx = idx || 0;    // we could also use the ES6 default value method.
  if (idx === 0) {
    fwd = !fwd;      // when index becomes 0 switch the direction of the loop
    ms = fwd ? 5000  // if backwards rearrange index and duration to 0.5 sec
             : (idx = images.length - 2, 500);
  } else ms = 500;   // when index is not 0 set the duration to 0.5 sec
  imel.src = images[idx];
  fwd ? setTimeout(function(){displayImages(++idx % images.length,fwd)},ms)
      : setTimeout(function(){displayImages(--idx,fwd)},ms);
}

displayImages();
<image id ="photo"></image>
Redu
  • 19,106
  • 4
  • 44
  • 59