Setinterval Animation sometime paused - javascript

I make an animation using sequence images. i run the images using setinterval function animation going fine but i dont know why it paused some time. i posted fiddle here look this fiddle you can able to notice this pause
Unwanted Pause Happen Here
myAnim = setInterval(function(){
$("#myImageHolder8").attr('src', nextImage5[u]);
u++;
if(u==nextImage5.length)
{
u=0;
}
}, 50);
Pls friends Help me.

You need to preload the image. Setting the image source inside the loop will definately cause a hick-up at one point as loading and decoding the image(s) may very well exceed 50 ms (cached or not). This will also cause the problem to appear randomly (and faster computers may not notice while slower one or slower connections may cause this more frequent).
Preload the images and the simply insert the loaded image into the container (a parent element) instead.
You can preload the images either by hiding them in DOM and use window.onload to start, or do it in JavaScript using an array and load counter.
An example of an loader:
Live demo
var images = [],
count = nextImage5.length,
len = count,
i = 0;
for(; i < len; i++) {
var img = new Image;
images.push(img);
img.onload = loader;
img.src = nextImage5[i];
}
function loader() {
count--;
if (count === 0) {
... start animation here...
}
}
and then in the animation loop do something like (sorry, my jQuery escapes me but you see the point):
$('#myImageHolder8').html('');
$('#myImageHolder8').append(images[u]);

Before setting the animation, make sure you preload your images first. So that the images are ready and loaded to display smoothly. You can use this preloader. And I would like to suggest that instead of changing the src of an <img> it is better to draw the image to a <canvas> then create a <canvas> for your next image.

Related

How to load all images before showing the page in React?

I am trying to find a more modern solution that doesn't use jQuery as I am using React (Gatsbyjs specifically).
I have a website with multiple image carousels that contain high res images.
The issue is the each image carousel only show one image at a time, so only when the user navigates to the next image does the image get fetched, this results in a choppy loading appearance.
I have tried researching online with onLoad and load event listeners but none seem to have worked so far because they only load the image that is currently being shown by the carousel, instead of all of the images in the carousel.
If there is a way to first load all the images, then set the state to true, and only after the state is true, then the rest of the DOM appears onto the screen, that would be perfect.
Any suggestions? Thanks.
Website in question: https://dev--yachtgamechanger.netlify.com/
As Lonnie Best said, I ended up using Promise.all() to capture the loads of the images.
Just in case anyone else want to check it out:
https://codesandbox.io/s/react-image-preload-ptosn
I guess that your lib is using lazy load approach. And it's really good when dueling with high res images.
You still can change the approach to load all the images before rendering the UI, by going into the carousel component, change the rendering behavior by checking whether all images be loaded or not before render.
Updated: Because you are using gatsby-image, so just use this property:
loading: "eager". For EX:
<Img
fixed={data.file.childImageSharp.fixed}
alt="Gatsby Docs are awesome"
loading="eager"
/>
https://www.gatsbyjs.org/packages/gatsby-image/
You can ensure that an image is pre-downloaded 100% well before it gets displayed to the screen.
Simply create an Image element and set its src property to the URL where the image is located. Then use the image's onload event to detect when it is ready for instant display.
// Image to Pre-Download:
var image = new Image();
console.time("Image Fully Downloaded in");
image.src = "https://www.nasa.gov/sites/default/files/thumbnails/image/pia24870.jpeg";
image.onload = function()
{
console.timeEnd("Image Fully Downloaded in");
console.log("Image is ready for viewing.");
clearInterval(interval);
progress.parentNode.replaceChild(btn, progress);
}
// Fake Progress Indicator:
let progress = document.createElement("progress");
progress.value = 3;
progress.max = 100;
progress.textContent = "Fake Progress";
document.body.appendChild(progress);
let interval = setInterval(()=>
{
if (progress.value === 99)
{
progress.value = 0;
}
else
{
progress.value = progress.value + 1;
}
},50)
// Button to Replace Progress Indicator:
let btn = document.createElement("button");
btn.textContent = "View Entire Image Instantly";
btn.addEventListener('click',function()
{
this.parentNode.replaceChild(image, this);
});
img { max-width: 100%; }
<p>Only after the image is completely downloaded, will you see the button to view it:</p>
Based on this concept, you could pre-load/queue as many images as you like into image objects, so that they are ready to be displayed instantly (well before the user decides to view the next image). Here's an example where I'm switching between preloaded images automatically (so fast that it looks like an animated gif -- but it is actually 27 separate images from 27 different URL locations): See statue example and view source.

swapping src to lazy

Not happy with existing lazy loading plugins (they are so complex that I can't even understand the codes in them), I thought I can create a simple, easy to understand script that lazy loads images.
My idea was simple. Start out with a following (deformed) img tag.
<img lazy="http://lorempixel.com/400/200"/>
Using javascript, swap out the word "lazy" with "src" when the page is being scrolled up or down.
function hackyaFunction_lazy() {
[].forEach.call(document.querySelectorAll('img[lazy]'), function(img) {
img.setAttribute('src', img.getAttribute('lazy'));
img.onload = function() {
var imgs = document.querySelectorAll('[lazy]');
for (i = 0; i < imgs.length; i++) {
var o = imgs[i],
lazy = o.getAttribute('lazy');
if (o.y <= (window.screen.height + window.scrollY + 50) && o.y >= (window.scrollY - 50)) {
o.setAttribute('src', lazy);
o.removeAttribute('lazy');
}
}
}
window.onload = window.onscroll = hackyaFunction_lazy;
});
}
I know enough of javascript to hack together bits & pieces to make something that works. And the above code kinda works.
On my console, I see that the word "lazy" has been successfully replaced with "src" for images that are in viewport.
However, images that are outside of the viewport, this is what I see.
<img lazy="http://lorempixel.com/400/200/sports/Dummy-Text" src="http://lorempixel.com/400/200/sports/Dummy-Text">
So I have half working code & this is the best that I can do.
I should have just used any one of the plugins that are available out there; just wanted to see if I can create something simple & easy.
Now that I am so close to making this thing work, I am reluctant to give it up.
Any help will be greatly appreciated.
I wanted to put together the whole thing (html & js) on jsfiddle but images fail to show on jsfiddle. Don't know why.
The code works (as described) on local environment.
The first line within the .forEach() changes the src of the current image without removing lazy and without testing whether it is in view or not, so after the .forEach() has run that line for every image they will all have been updated. That's why when you inspect the elements with the dev tools many of the images have both a src and lazy attribute.
If the idea is to only set the src once the image scrolls into view, and for any images that are already in view on page load, you can do it by keeping just the inner for loop of your function:
function hackyaFunction_lazy() {
var imgs = document.querySelectorAll('[lazy]');
for (i = 0; i < imgs.length; i++) {
var o = imgs[i];
if (o.y <= (window.screen.height + window.scrollY + 50) && o.y >= (window.scrollY - 50)) {
o.src = o.getAttribute('lazy');
o.removeAttribute('lazy');
}
}
}
window.onload = window.onscroll = hackyaFunction_lazy;
This works because on each scroll it first selects whatever elements still have the lazy attribute, then for those elements it tests whether they're in view and if so it sets their src and removes the lazy. Elements that have not yet been scrolled into view are not updated.
See it working here: https://jsfiddle.net/vb779g7v/2/
Edit/P. S. Note that your if test checking if the element is in view isn't right, because screen.height gives, as the name suggests, the height of the whole screen, not the height of the client area within the browser. But that's not really central to your question, so I'll leave fixing that as an exercise for the reader...

Improve image load time

I have a few img tags whose src is changed onmouseover. This takes an inordinate amount of time to load. How can I improve the load time? The images are basically just different icons.
You can do a few things.
1) CSS Sprites is probably the preferred method.
2) You can load the images in a div and set that div to display none, making it so the images are already loaded so on mouseover they'll be there instantly.
Also here's a link on how to PreLoad images with CSS
There are a few ways to do it, the ideal solution in your case would be to use CSS sprites considering they're icons. However, depending on the situation sometimes sprites aren't ideal.
Here's one solution using JavaScript to preload images:
var images = new Array();
function preload() {
for (i = 0; i < preload.arguments.length; i++) {
images[i] = new Image();
images[i].src = preload.arguments[i];
}
}
preload(
'http://image-1.jpg',
'http://image-2.jpg',
'http://image-3.jpg'
);
What you're trying to do is achieve a rollover. It is strange that you'd experience a very long delay in this process. Usually, if the images aren't stored in some remote location, they're pretty fast.
Look at this article for some guidance
Other things you could try:
- sprites in css
- you could use two overlapping divs and hide one and unhide the other and vice versa

Run image transition and animation simultaneously with some precision?

I am building a website as part of some university coursework and my landing page design is fairly ambitious, designed to wow my professor.
It requires many images of different types, jpegs, pngs and animated gifs which all appear to have a negative impact on loading time and gracefulness.
So what I'm building is a little stage-themed image carousel, what I'm trying to make it do is:
Roll curtain up revealing first image
Roll curtain down & change to second image
Roll curtain up revealing second image
Roll curtain down & change to third image
Roll curtain up revealing third image
and so on.. looping through the images indefinitely
Whilst this is going on there is a simple animated spotlight gif overlaying the image carousel, running constantly.
I am aware that there are a number of ways to achieve this, I'm trying to find the most smooth and precise method. What I have managed to constuct so far is a basic image carousel that isn't very wow, and a curtain that rolls up first time only on most browsers (it only rolls up and down constantly on Dreamweaver CS5).
I am asking here because I have tried a number of different ways and have been searching the web for 3 days trying to find a relevant example to work from. Any suggestions would be greatly appreciated.
You can view a working example here
Here is my javascript:
$(document).ready(function() {
var imgs = ['images/logopic.png','images/lobby.png','images/worksofshake.jpg','images/worksofshake.jpg'];
var cnt = imgs.length;
setInterval(Slider, 6000);
function Slider() {
$('#imageSlide').fadeOut("fast", function() {
$(this).attr('src', imgs[(imgs.length++) % cnt]).fadeIn("slow");
});
$("#curtaindown").animate({height:"95%"});
/*$("#curtaindown").animate({height:"75%"});
$("#curtaindown").animate({height:"50%"});
$("#curtaindown").animate({height:"30%"});*/
$("#curtaindown").animate({height:"5%"},5000);
$("#curtaindown").animate({height:"95%"},5000);
$(".leadinfo").hide();
}
});
Thank-you for any and all help.
This solution assumes that on page load, the curtain is covering up the image and the first image is already set on #imageSlide. I haven't tested it, but the general idea should be correct. One problem with this solution is that with a bad internet connection, there's a chance the curtain will pull away before the image is actually done downloading. Accounting for that is a bit messier, so I didn't get into it.
var imgs = [...];
var nextImage = 1;
var $image = $('#imageSlide');
var $curtain = $('#curtaindown');
hideCurtain();
preloadNextImage();
// Show the next image in 6 seconds
setTimeout(showNextImage, 6000);
function showNextImage() {
showCurtain(function(){
// Set the img tag to the new image
$image.attr('src', imgs[nextImage]);
nextImage++;
if (nextImage.length >= imgs.length)
nextImage = 0;
preloadNextImage();
// After the curtain is hidden, wait 5 more seconds before
// switching to the next one.
hideCurtain(function(){
setTimeout(showNextImage, 5000);
});
});
}
function showCurtain(onComplete) {
$curtain.animate({height:'95%'},
{ duration: 500,
complete: onComplete });
}
function hideCurtain(onComplete) {
$curtain.animate({height:'5%'},
{ duration: 500,
complete: onComplete });
}
function preloadNextImage() {
// Start downloading the next image.
(new Image()).src = imgs[nextImage];
}
I eventually settled on a very simple implementation that works even though I'm fairly sure it logically shouldn't. If someone could comment to explain why it does work I'd be very grateful.
This is the code I eventually used:
<script type="text/javascript">
$(document).ready(function() {
$("#scroller_container_top").hide();
var imgs = ['images/logopic.png','images/lobbywithcaption.jpg','images/seatswithcaption.jpg','images/worksofshake.jpg'];
var cnt = imgs.length;
setInterval(Slider, 10000);
function Slider() {
$('#imageSlide').fadeOut("slow", function() {
$(this).attr('src', imgs[(imgs.length++) % cnt]).fadeIn("slow");
});
$("#curtaindown").animate({height:"5%"},5000);
$("#curtaindown").animate({height:"95%"},5000);
};
</script>

CSS opacity performance. Image fading

I'm trying to fade in-out my image for my photo gallery switching. All it's done in JavaScript which simply changes the opacity CSS value of the image element. This is really laggy (slow) on some computers - for example my laptop which isn't extremely powerful, but it's brand new (Asus Eeepc).
I was wondering if there's anyway I can fix this performance issue. I've seen demos of Canvas animation and HTML5 applied to images and they're really smooth on my laptop. I wonder if I can apply the same thing to my image fading feature.
Any ideas? How would I do this?
I quickly threw together an example of an image fading away using the canvas tag as requested: http://jsfiddle.net/6wmrd/12/ (Only tested in Chrome and Firefox)
I´m not sure if there is any performance gain though, but here is at least a very simple example of how it can be done. It should also be noted that this was done in 5 min so the code can be improved and optimized.
Otherwise, from my experience, if you have a solid background behind the image, I have found that it is sometimes smoother to fade an element over the image with the same color as the background.
Other ways you can improve performance could be to reduce FPS. If I´m not mistaken MooTools has 50 FPS as standard. However, reducing the FPS might influence the perceived performance.
Here is code that works for all browsers:
add to head :
/* ****************************
* updated for all browsers by
* Evan Neumann of Orbiting Eden on
* October 6, 2011.
* www.orbitingeden.com - evan#orbitingeden.com
* original version only worked for IE
*****************************/
<!-- Begin
/* *****************************
* * editable by user
* ***************************/
var slideShowSpeed = 5000; // Set slideShowSpeed (milliseconds) shared by IE and other borwsers
var crossFadeDuration = 5; // Duration of crossfade (1/10 second) shared by IE and other borwsers
var crossFadeIncrement = .05; //crossfade step amount (1 is opaque) for non-IE browsers
// Specify the image files
var Pic = new Array(); // do not change this line
// to add more images, just continue the pattern, adding to the array below
Pic[0] = 'images/dare2wear-427ED-e.jpg';
Pic[1] = 'images/PBW_3238EDSM-e.jpg';
Pic[2] = 'images/dare2wear-441_2ED-e.jpg';
/* ********************************
* do not change anything below this line
**********************************/
var f = 0; //index of the foreground picture
var b = 1; //index of the background picture
var p = Pic.length; //number of pictures loaded and in queue - this may increase as time goes on depending on number and size of pictures and network speed
//load the picture url's into an image object array
//used to control download of images and for IE shortcut
var preLoad = new Array();
for (i = 0; i < p; i++) {
preLoad[i] = new Image();
preLoad[i].src = Pic[i];
}
function runSlideShow() {//this is trigerred by <body onload="runSlideShow()" >
//if IE, use alternate method
if (document.all) {
document.images.SlideShow.style.filter="blendTrans(duration=2)";
document.images.SlideShow.style.filter="blendTrans(duration=crossFadeDuration)";
document.images.SlideShow.filters.blendTrans.Apply();
}
//increment the foreground image source
document.images.SlideShow.src = preLoad[f].src;
//if IE, use the shortcut
if(document.all) {
document.images.SlideShow.filters.blendTrans.Play();
}
//all other browser use opacity cycling
else {
var imageContainer = document.getElementById('imageContainer');
var image = document.images.SlideShow;
//convert an integer to a textual number for stylesheets
imageContainer.style.background = "url('"+Pic[b]+"')";
//set opacity to fully opaque (not transparent)
image.style.opacity = 1;
//run fade out function to expose background image
fadeOut();
}
//increment picture index
f++;
//if you have reached the last picture, start agin at 0
if (f > (p - 1)) f = 0;
//set the background image index (b) to one advanced from foreground image
b = f+1;
//if b is greater than the number of pictures, reset to zero
if(b >= p) {b = 0;}
//recursively call this function again ad infinitum
setTimeout('runSlideShow()', slideShowSpeed);
}
function fadeOut(){
//convert to element
var el = document.images.SlideShow;
//decrement opacity by 1/20th or 5%
el.style.opacity = el.style.opacity - crossFadeIncrement;
//if we have gone below 5%, escape out to the next picture
if(el.style.opacity <= crossFadeIncrement) {
return;
}
//wait 50 milliseconds then continue on to decrement another 5%
setTimeout('fadeOut()', crossFadeDuration*10);
}
// End -->
and add two elements to the body. The first is a container background element. I have used a div, but td, body and others should work too. The second is the foreground image. Lastly, within the <body> tag, add the onload function call
<body onLoad="runSlideShow()">
<!-- this is the main image background -->
<div id="imageContainer">
<!-- this is the main image foreground -->
<img id="SlideShow" name='SlideShow' width="324" height="486">
</div>
Luca one way to make it faster is to use hardware acceleration and webkit transforms. The problem is that different browser support this to different degrees. See
http://mir.aculo.us/2010/06/04/making-an-ipad-html5-app-making-it-really-fast/
hopefully in the not-to-distant futures support for hardware acceleration in the browser will be better.
Have a look at the front page of this site It's 5 images that fade in and out in rotation, pure css2, html4, javascript, and is cross-browser (as far as I am aware). The javascript is a bit hackneyed - written some time ago :) but it seems to be smooth enough. See how it is on your machine. If it lags, you could try with a slower update, say 150 or 200ms instead of a 100.

Categories