I have built a code which change pictures every 5 second using setinterval() and everytime when a picture is changes, it will show up with it's opacity growing from 0 to 1, using setinterval() as well.
It all works excellently, but there is a single problem which I can find the way to fix it. The problem is that after I start the page, if I move to a differend tab, if I come back in a minute, it all goes craze and the opacity is growing too fast and more then once before a picture is changed.
Here is the code:
var images = [], x = 0, t = 0, timerid, s = 0;
images[0] = "Images/" + location.pathname.substring(1, location.pathname.length - 5) + "2.jpg";
images[1] = "Images/" + location.pathname.substring(1, location.pathname.length - 5) + ".jpg";
function ChangeOpacity() {
img = document.getElementById("img");
s += 0.003;
t = s.toString();
img.style.opacity = t;
if (img.style.opacity>=1) {
s = 0;
clearInterval(timerid);
}
}
function SwitchImage() {
img = document.getElementById("img");
img.src = images[x];
img.style.opacity = 0;
timerid = setInterval('ChangeOpacity()', 1);
x++;
if (x >= images.length)
x = 0;
}
function StartFun() {
setInterval('SwitchImage()', 5000);
}
You could add a window.onblur and window.onfocus function. Each time the tab loses focus (onblur) you could clear the interval and restart it when the tab gets focused again (onfocus).
More about focus on tabs
Edit:
Restarting the interval is not necessary in all cases.
Related
In my code, I wanted to create a mouse trail with 1)random images 2)a blurring effect 3) opacity transition 4) a max amount of divs in the trail.
Similar to this: https://tympanus.net/Development/ImageTrailEffects/
Point 2 and 3 are done, however I am stuck on point 4. The trail has a crazy strobe effect right now, which I dislike. I want it to be less sensitive and more subtle. Some kind of limitation on them. I've added a counter where I can count the amounts of divs created, but I'm unsure and stuck as to what to do now. I've looked at setInterval, but when I apply it to my function it's not working
I've also had some issues with the creation of an array for the random backgrounds, but I'm sure I'll figure that out. The question is mostly about how to limit and control the creation of the trail, but if anyone has a tip/link as to how to create the random background images, I am all ears.
Here the code I have up till now
window.onload= function() {
window.addEventListener('mousemove', function(e) {
var animate= function(i) {
var image= document.createElement('div'); //create a div named bubble
image.classList.add('trail');
var size= 60;
var sizepx= size+'px';
image.style.transition='2s ease';
image.style.position= 'fixed';
image.style.top= e.pageY - size/2 + 'px';
image.style.left= e.pageX - size/2 + 'px';
image.style.width= sizepx;
image.style.height= sizepx;
image.style.background= 'hsla(' +
Math.round(Math.random()*360) + ', ' +
'100%, ' +
'50%';
// image.style.background= 'black';
image.style.border= 'white 1px solid';
image.style.pointerEvents= 'none';
image.style.zIndex= 1;
document.body.appendChild(image);
//opacity and blur animations
window.setTimeout(function() {
image.style.opacity = 0;
image.style.filter = 'blur(6px)';
}, 80);
window.setTimeout(function() {
document.body.removeChild(image);
}, 2100);
};
var numItems = document.querySelectorAll('.trail').length;
console.log(numItems);
for (var i= 1; i <= 1; i+= 1) {
animate(i);
}
});
};
A fiddle:
https://jsfiddle.net/opufnsvz/
Here you go mate ( I used Unsplash for the random image source ), loading images on the fly gives unwanted effects, so they have to be preloaded. you can change the timesPerSecondto control the frequency
const numberOfImages = 10;
const imageSources = Array.from(Array(numberOfImages).keys()).map((i) => 'https://source.unsplash.com/collection/9948714?' + i);
// how many times to fire the event per second
const timesPerSecond = .1;
function preloadImages(images) {
for (i = 0; i < images.length; i++) {
let l = document.createElement('link')
l.rel = 'preload'
l.as = 'image'
l.href = images[i]
document.head.appendChild(l);
}
}
function animate(e) {
var image= document.createElement('div'); //create a div named bubble
image.classList.add('trail');
var size= 60;
var sizepx= size+'px';
image.style.transition='2s ease';
image.style.position= 'fixed';
image.style.top= e.pageY - size/2 + 'px';
image.style.left= e.pageX - size/2 + 'px';
image.style.width= sizepx;
image.style.height= sizepx;
image.style.backgroundImage = 'url(https://source.unsplash.com/collection/9948714?'+ Math.floor(Math.random()*numberOfImages) +')';
image.style.backgroundSize = 'cover';
image.style.border= 'white 1px solid';
image.style.pointerEvents= 'none';
image.style.zIndex= 1;
document.body.appendChild(image);
//opacity and blur animations
window.setTimeout(function() {
image.style.opacity = 0;
image.style.filter = 'blur(6px)';
}, 80);
window.setTimeout(function() {
document.body.removeChild(image);
}, 2100);
};
window.onload= function() {
preloadImages(imageSources);
var wait = false;
window.addEventListener('mousemove', function(e) {
if (!wait) {
wait = true;
setTimeout(() => { wait = false }, timesPerSecond * 1000);
animate(e);
}
});
};
The result I want to achieve:keep clicking the mouse and a bunch of little “heart” images will pop up according to the coordinates of each click of the mouse. In other words, one click will pop up one image on the coordinates of your mouse.
Then after 1 second, the image begin to disappear.The earlier appeared image will also disappear early.
My problem is: the image will not disappear appropriately unless I delete the clearInterval code. Here’s the code:
// when click, an image pop up
// use addEventListener to do so
// let timer = 0;
let imgList = [];
document.addEventListener("click",function(event){
let img = document.createElement("img");
img.style.position = "absolute";
img.style.left = (event.clientX - 32) + "px";
img.style.top = (event.clientY - 32) + "px";
img.src = "https://placehold.it/64x64.png";
document.body.appendChild(img);
imgList.push({
img:img,
opacity:1,
scale:1,
frame:0
});
});
var timer = setInterval(draw, 1000);
function draw(){
if (imgList.length < 1) {
clearInterval(timer);
timer = null;
}
else {
imgList[0].img.remove();
imgList.splice(0, 1);
}
}
The problem is you're cancelling your interval timer when there aren't any images, so if the user doesn't create an image within a second (and within a second after that, etc.), the timer will get cancelled and no further images will be removed.
I wouldn't use an interval timer for this, I'd use a single timer (setTimeout) you create specifically for the added image:
document.addEventListener("click",function(event){
let img= document.createElement("img");
img.style.position="absolute";
img.style.left=(event.clientX-32)+"px";
img.style.top=(event.clientY-32)+"px";
img.src="1.png";
document.body.appendChild(img);
// Remove it after one second
setTimeout(() => {
img.remove();
}, 1000);
});
You can add a load event listener to a added image and within the handler remove it with a timeout. Generic snippet, maybe it's useful for your code:
const addImage = (i = 1) => {
let img = document.createElement("img");
img.src = "https://img.icons8.com/metro/2x/like.png";
img.addEventListener("load", () =>
setTimeout(() => document.body.removeChild(img), i*1000));
// ^add load event/timeout here
document.body.appendChild(img);
}
for (let i=0; i < 5; i += 1) {
addImage(i);
}
document.addEventListener("click", () => addImage(1));
<button>Add image</button>
If the intent is to remove the images 1 second after each other you should set the timer inside the "click" callback. This way you can add the interval if it is not yet set.
If the intent is to display each image a maximum of 1 second this is not the answer you're looking for.
let imgList = [];
let timer;
document.addEventListener("click",function(event){
let img = document.createElement("img");
img.style.position = "absolute";
img.style.left = (event.clientX - 32) + "px";
img.style.top = (event.clientY - 32) + "px";
img.src = "https://placehold.it/64x64.png";
document.body.appendChild(img);
imgList.push({
img:img,
opacity:1,
scale:1,
frame:0
});
if (!timer) {
timer = setInterval(draw, 1000);
}
});
function draw(){
if (imgList.length < 1) {
clearInterval(timer);
timer = null;
}
else {
imgList[0].img.remove();
imgList.splice(0, 1);
}
}
So I have this basic script which alternates between three images and I'd like to add a simple fadein/fadeout/fadeto or whatever looks best so it's not so clunky. How can I achieve this? Or, is there a better way?
function displayNextImage() {
x = (x === images.length - 1) ? 0 : x + 1;
document.getElementById("img").src = images[x];
}
function displayPreviousImage() {
x = (x <= 0) ? images.length - 1 : x - 1;
document.getElementById("img").src = images[x];
}
function startTimer() {
setInterval(displayNextImage, 3000);
}
var images = [], x = -1;
images[0] = "assets/img/logo1.png";
images[1] = "assets/img/logo2.png";
images[2] = "assets/img/logo3.png";
You can set the opacity of the images before you change the src:
function displayNextImage() {
x = (x === images.length - 1) ? 0 : x + 1;
var imgvar = document.getElementById("img");
imgvar.classList.add("fadeOut");
setTimeout(function() {
imgvar.src = images[x];
imgvar.classList.remove("fadeOut");
}, 500);
}
function displayPreviousImage() {
x = (x <= 0) ? images.length - 1 : x - 1;
var imgvar = document.getElementById("img");
imgvar.classList.add("fadeOut");
setTimeout(function() {
imgvar.src = images[x];
imgvar.classList.remove("fadeOut");
}, 500);
}
function startTimer() {
setInterval(displayNextImage, 3000);
}
var images = [], x = -1;
images[0] = "assets/img/logo1.png";
images[1] = "assets/img/logo2.png";
images[2] = "assets/img/logo3.png";
And in CSS:
img {
opacity: 1;
transition: opacity 500ms ease-in-out;
}
img.fadeOut {
opacity: 0;
}
Note: I added a 500ms timeOut in javascript because I suspect that otherwise the animation wouldn't be visible at all because it would instantly go from visible to invisible to visible again.
You could place two image elements in the page. One for the current image and one for the next image.
Once the time to show the image has passed, apply a CSS class on the visible image to transition its opacity to 0.
Once the transition is completed, replace the image source with the next image to show. Position the image element behind the image element that is now visible to the user and remove the transition CSS.
You can use the following. Source, W3 Schools. See here for the jQuery include
$(document).ready(function(){
$(".btn1").click(function(){
$("p").fadeOut()
});
$(".btn2").click(function(){
$("p").fadeIn();
});
});
However, this uses jQuery. Depending on your limitations, you may not be able to use this. For further information on both the fadeIn(time) and fadeOut(time) functions, checkout W3's article!
You can try animate.css to animate the html tag every time you call one of the functions.
https://github.com/daneden/animate.css
I have a javascript which uses many images, and I want to load them all before the user starts clicking around. The images are a little bit big, so it takes a while. Here's my code:
startTest();
function preloadImages() {
console.log("preload images");
for(var i = 1; i <= 132; i++) {
var img = new Image();
images[i-1] = "images/"+i+".png";
img.src = images[i-1];
if(i == 132) {
img.load = doneLoading();
}
}
}
function doneLoading() {
console.log("done loading");
document.getElementById("laading").style.display = "none";
console.log("loading gone");
showReady();
}
function startTest() {
console.log("start test");
trialCount = 0;
document.getElementById("laading").style.display = "block";
preloadImages();
var hammertime = Hammer(document.body).on("touch", function(event) {
registerTouch(event);
});
startTestTime = +new Date();
console.log("end start test");
}
As you can see, startTest() is first called, which calls preload images. Here's the issue:
When I load the page in the browser, the javascript console indicates that "done loading" has been printed, however the spinny wheel on the tab in the browser shows that the webpage is still loading...
What's going on here? How can I figure out once all my images are done loading?
You need to check on each image load that the image is the last one to load. Check using a count variable (loaded).
function preloadImages() {
var loaded = 0;
for(var i = 0; i <= 132; i++) {
var img = new Image();
images.push("images/"+(i+1)+".png");
img.src = images[i];
img.onload = function(){
loaded++;
if(!(loaded < 132)){
// all images have loaded
doneLoading();
}
}
}
}
In order to do a pre-loading, you will have to keep checking the complete status for each image that is being downloaded. Since, you can't know beforehand how much time it will take for each image to download (depending on latency or size), you will have to implement a timer which will keep polling the complete status on each image.
Here is one possible algorithm:
var timer = null,
numImages = 132,
allImages = new Array;
function preLoadImages() {
document.getElementById('loadcaption').innerHTML = 'Loading images... ';
for (var i = 0; i < numImages; i++) {
var tmp = "images/" + i + ".png";
allImages[i] = new Image();
allImages[i].onLoad = imgOnLoad(tmp);
allImages[i].src = tmp;
}
timer = window.setInterval('checkLoadComplete()', 250);
}
function imgOnLoad(imgName) { window.status = 'Loading image... ' + imgName; }
function checkLoadComplete() {
for (var i = 0; i < allImages.length; i++) {
if (!allImages[i].complete) {
imgOnLoad(allImages[i].src);
document.getElementById('loadcaption').innerHTML = 'Loading images... ' + Math.round((i/allImages.length)*100,0) + ' %';
return;
}
}
window.clearInterval(timer);
document.getElementById('loadcaption').innerHTML = 'Completed.';
window.status = '';
}
Where loadcaption is a simple HTML element to show progress. (You can also use an animated gif for loading animation).
The idea is to keep checking the complete status on each image by calling checkLoadComplete by a timer. Once all images are (load) complete, the for loop exits and the timer is cleared.
You start the pre-loading process by calling preLoadImages(); function.
I have this banner rotator which is working fine except for one problem...
This rotator here first goes through the function and when it reaches the "setTimeout" statement it triggers the "cycle" function again and again.
You guys probably know that in Firefox there is a status-bar in the bottom-left corner, which says "loading" or "waiting for domain.com..." etc etc.
The problem is this; When you enter the website in Firefox, the status bar says "Loaded" and dissappears. Then after 8 seconds (the setTimeout delay) the status bar shows again and displays something like "Getting data from domain.com...". And it doesn't go away.
This message is most likely caused by the setTimeout code, which triggers the function cycle over and over again.
Is there any way of "solving" this?
This probably happens in other browsers also, but so far I have only tested it in FF.
function ban_rot(){
//First preload images
// counter
var i = 0;
// create object
imageObj = new Image();
// set image list
images = new Array();
images[0] = "../Graphics/adv/1.gif"
images[1] = "../Graphics/adv/2.jpg"
// start preloading
for (i = 0; i <= images.length; i++) {
imageObj.src = images[i];
}
///////////////////////
var links = new Array("http://www.link1.com", "http://www.link2.se");
var alts = new Array("alt1", "alt2");
var titles = new Array("title1", "title2");
var counter = 0;
var banner_div = document.getElementById("ban_rot");
cycle();
function cycle() {
if (counter == links.length) {
counter = 0;
}
else if (counter < links.length) {
banner_div.innerHTML = '<img src=\"' + images[counter] + '\" border=\"1px\" style=\"border-color:#000;\" alt=\"' + alts[counter] + '\" title=\"' + titles[counter] + '\">';
//increase counter
counter++;
}
setTimeout(cycle, 8000);
} //end cycle function
} //end ban_rot function
The browser is showing a loading indicator because you're making it load a new image.