2

I am changing image source on click (prev/next buttons), and I would like to fade out image, then change source and fade it in, but I cannot get smooth transition. I tried adding .delay() in between fading and changing the source but still the src change happens before fading ends. I tried adding .stop() but that only stops the currently running animation, and attribute change doesn't count as animation.

var images = ['http://i.imgur.com/U82gG8H.jpg', 'http://i.imgur.com/kVy4G4R.jpg', 'http://i.imgur.com/BtMikrd.jpg'];

var count = 0;

$('.next').on('click', function() {
  if (count !== images.length-1) {
    count++;
    $('.product_image img').fadeTo(300, 0).delay(600).attr('src', '').attr('src', images[count]).fadeTo(300, 1);
  }
});

$('.previous').on('click', function() {
  if (count !== 0) {
    count--;
    $('.product_image img').fadeTo(300, 0).delay(400).attr('src', '').attr('src', images[count]).fadeTo(300, 1);
  }
});
.navigation {
  display: block;
}
.navigation .previous,
.navigation .next {
  width: 30px;
  height: 30px;
  line-height: 30px;
  text-align: center;
  background: #ddd;
  color: #fff;
  display: inline-block;
  margin-right: 20px;
  cursor: pointer;
}
.navigation .next {
  margin-right: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class="product_image">
  <img src="http://i.imgur.com/U82gG8H.jpg" />
</div>
<div class="navigation">
  <div class="previous">&lt;</div>
  <div class="next">&gt;</div>
</div>

Any help is appreciated.

dingo_d
  • 11,160
  • 11
  • 73
  • 132

6 Answers6

2

You need to use a callback function of the first fadeTo, otherwise the images are faded out, changed and faded back in again all at the same time. Try this:

var images = ['http://i.imgur.com/U82gG8H.jpg', 'http://i.imgur.com/kVy4G4R.jpg', 'http://i.imgur.com/BtMikrd.jpg'];
var count = 0;

$('.next').on('click', function() {
  if (count !== images.length - 1) {
    count++;
    $('.product_image img').fadeTo(300, 0, function() {
      $(this).attr('src', images[count]).fadeTo(300, 1);
    });
  }
});
$('.previous').on('click', function() {
  if (count !== 0) {
    count--;
    $('.product_image img').fadeTo(300, 0, function() {
      $(this).attr('src', images[count]).fadeTo(300, 1);
    });
  }
});
.navigation {
  display: block;
}
.navigation .previous,
.navigation .next {
  width: 30px;
  height: 30px;
  line-height: 30px;
  text-align: center;
  background: #ddd;
  color: #fff;
  display: inline-block;
  margin-right: 20px;
  cursor: pointer;
}
.navigation .next {
  margin-right: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class="product_image">
  <img src="http://i.imgur.com/U82gG8H.jpg" />
</div>
<div class="navigation">
  <div class="previous">&lt;</div>
  <div class="next">&gt;</div>
</div>
Rory McCrossan
  • 331,213
  • 40
  • 305
  • 339
2

Use a callback function

I would suggest using the complete callback which is documented here.

The callback is defined as a function and is added after the opacity value like this:

.fadeTo( duration, opacity [, complete ] )

The callback function will then fire after the animation has completed allowing us to change the src attribute while the image is "hidden" and then fading it back in.

An Example

var images = ['http://i.imgur.com/U82gG8H.jpg', 'http://i.imgur.com/kVy4G4R.jpg', 'http://i.imgur.com/BtMikrd.jpg'];

var count = 0,
    productImage = $('.product_image').children('img');

$('.next').on('click', function() {
  
  if (count !== images.length - 1) {
    
    count++;
    
    productImage.fadeTo(300, 0, function() {

      productImage.attr('src', images[count]).fadeTo(300, 1);

    });
  }
});

$('.previous').on('click', function() {
  
  if (count !== 0) {
    
    count--;
    
    productImage.fadeTo(300, 0, function() {

      productImage.attr('src', images[count]).fadeTo(300, 1);

    });
  }
});
.navigation {
  display: block;
}
.navigation .previous,
.navigation .next {
  width: 30px;
  height: 30px;
  line-height: 30px;
  text-align: center;
  background: #ddd;
  color: #fff;
  display: inline-block;
  margin-right: 20px;
  cursor: pointer;
}
.navigation .next {
  margin-right: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class="product_image">
  <img src="http://i.imgur.com/U82gG8H.jpg" />
</div>
<div class="navigation">
  <div class="previous">&lt;</div>
  <div class="next">&gt;</div>
</div>
Chris Spittles
  • 15,023
  • 10
  • 61
  • 85
2

The .attr() function is not a queue based method, so the delay will not have any effect on it. You can use .delay() to add a method to the animation queue.

Also preloading the images can improve the transition.

var images = ['http://i.imgur.com/U82gG8H.jpg', 'http://i.imgur.com/kVy4G4R.jpg', 'http://i.imgur.com/BtMikrd.jpg'];

//image preloading
images.forEach(function(src) {
  var img = new Image();
  img.src = src;
})

var count = 0;

$('.next').on('click', function() {
  count++;
  count = count >= images.length ? 0 : count;
  $('.product_image img').fadeTo(300, 0).delay(600).queue(function(next) {
    $(this).attr('src', images[count]);
    next();
  }).fadeTo(300, 1);
});

$('.previous').on('click', function() {
  count--;
  count = count < 0 ? images.length - 1 : count;

  $('.product_image img').fadeTo(300, 0).delay(400).queue(function(next) {
    $(this).attr('src', images[count]);
    next();
  }).fadeTo(300, 1);
});
.navigation {
  display: block;
}
.navigation .previous,
.navigation .next {
  width: 30px;
  height: 30px;
  line-height: 30px;
  text-align: center;
  background: #ddd;
  color: #fff;
  display: inline-block;
  margin-right: 20px;
  cursor: pointer;
}
.navigation .next {
  margin-right: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class="product_image">
  <img src="http://i.imgur.com/U82gG8H.jpg" />
</div>
<div class="navigation">
  <div class="previous">&lt;</div>
  <div class="next">&gt;</div>
</div>
Arun P Johny
  • 384,651
  • 66
  • 527
  • 531
1

Try this approach

$(img).fadeTo(200,0.70, function() {
        $(img).attr("src", new_img_src);
   }).fadeTo(300,1); 
Kyobul
  • 759
  • 1
  • 7
  • 17
1

According to this answer: currently ongoing animation is finished immediately, and the current is started.

var images = ['http://i.imgur.com/U82gG8H.jpg', 'http://i.imgur.com/kVy4G4R.jpg', 'http://i.imgur.com/BtMikrd.jpg'];

var count = 0;

$('.next').on('click', function() {
  if (count !== images.length-1) {
    count++;
    $('.product_image img').fadeTo(300, 0).delay(600).attr('src', '').attr('src', images[count]).finish().fadeTo(300, 1);
  }
});

$('.previous').on('click', function() {
  if (count !== 0) {
    count--;
    $('.product_image img').fadeTo(300, 0).delay(400).attr('src', '').attr('src', images[count]).finish().fadeTo(300, 1);
  }
});
.navigation {
  display: block;
}
.navigation .previous,
.navigation .next {
  width: 30px;
  height: 30px;
  line-height: 30px;
  text-align: center;
  background: #ddd;
  color: #fff;
  display: inline-block;
  margin-right: 20px;
  cursor: pointer;
}
.navigation .next {
  margin-right: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class="product_image">
  <img src="http://i.imgur.com/U82gG8H.jpg" />
</div>
<div class="navigation">
  <div class="previous">&lt;</div>
  <div class="next">&gt;</div>
</div>
Community
  • 1
  • 1
silviagreen
  • 1,679
  • 1
  • 18
  • 39
1

You can use .fadeOut() with callback function when complete like:

var images = ['http://i.imgur.com/U82gG8H.jpg', 'http://i.imgur.com/kVy4G4R.jpg', 'http://i.imgur.com/BtMikrd.jpg'];

var count = 0;

$('.next').on('click', function() {
  if (count !== images.length - 1) {
    count++;
    $('.product_image img').fadeOut(300, function() {
      $(this).attr('src', '').attr('src', images[count]).fadeTo(300, 1);
    });
  }
});

$('.previous').on('click', function() {
  if (count !== 0) {
    count--;
    $('.product_image img').fadeOut(300, function() {
      $(this).attr('src', '').attr('src', images[count]).fadeTo(300, 1);
    });
  }
});
.navigation {
  display: block;
}
.navigation .previous,
.navigation .next {
  width: 30px;
  height: 30px;
  line-height: 30px;
  text-align: center;
  background: #ddd;
  color: #fff;
  display: inline-block;
  margin-right: 20px;
  cursor: pointer;
}
.navigation .next {
  margin-right: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class="product_image">
  <img src="http://i.imgur.com/U82gG8H.jpg" />
</div>
<div class="navigation">
  <div class="previous">&lt;</div>
  <div class="next">&gt;</div>
</div>
Alex Char
  • 32,879
  • 9
  • 49
  • 70