I'm trying to create kind of runway of lights and here's what it looks like now
http://jsfiddle.net/7NQvq/
var divs = document.querySelectorAll('div');
var index = 0;
setInterval(function(){
if(index > divs.length+20){
index = 0;
}
if(divs[index-1]){
divs[index-1].className = '';
}
if(divs[index]){
divs[index].className = 'active';
}
index++;
}, 50);
What I don't like about it is that it's completely inflexible and hard to adjust. Furthermore it also runs additional 20 empty cycles which is wrong. Is there a better way to achieve it (preferrably pure JS)?
It seemes that there must be some combination of setInterval and setTimeout but I just can't make it work.
I've made some adjustments to use a CSS animation rather than messing around with transitions and class toggling.
Updated Fiddle
All the JavaScript does now is define the animation delay for each dot.
You can adjust:
The animation delay - I just have i/10, but you could make it i/5, i/20... experiment!
The animation duration - it's set to 1s in my Fiddle, but try shorter and longer to see what happens
The 50% that indicates when the light has faded out
How about
function cycle(selector, cssClass, interval) {
var elems = document.querySelectorAll(selector),
prev = elems[0],
index = 0,
cssClassRe = new RegExp("\\s*\\b" + cssClass + "\\b");
if (elems.length === 0) return;
return setInterval(function () {
if (prev) prev.className = prev.className.replace(cssClassRe, "");
index %= elems.length;
elems[index].className += " " + cssClass;
prev = elems[index++];
}, interval);
}
and
var runwayIntval = cycle("div", "active", 100);
and at some point
clearInterval(runwayIntval);
See: http://jsfiddle.net/arNY8/1/
Of course you could argue that toggling a CSS class is a little limited. You could work with two callback functions instead: one to switch on a freely definable effect, one to switch it off:
function cycle(elems, enable, disable, interval) {
var prev = elems[0], index = 0;
if (elems.length === 0) return;
return setInterval(function () {
index %= elems.length;
if (prev) disable.call(prev);
enable.call(elems[index]);
prev = elems[index++];
}, interval);
}
and
var cycleIntval = cycle(
document.querySelectorAll("div"),
function () {
this.className += " active";
},
function () {
this.className = this.className.replace(/\s*\bactive\b/, "");
},
100
);
Related
I got function within JS which is supposed to show random order divs on btn click.
However once the btn is clicked user got to wait for initial 10 seconds ( which is set by: setInterval(showQuotes, 10000) ) for divs to start showing in random order which is not ideal for me.
JS:
var todo = null;
var div_number;
var used_numbers;
function showrandomdivsevery10seconds() {
div_number = 1;
used_numbers = new Array();
if (todo == null) {
todo = setInterval(showQuotes, 10000);
$('#stop-showing-divs').css("display", "block");
}
}
function showQuotes() {
used_numbers.splice(0, used_numbers.length);
$('.container').hide();
for (var inc = 0; inc < div_number; inc++) {
var random = get_random_number();
$('.container:eq(' + random + ')').show();
}
$('.container').delay(9500).fadeOut(2000);
}
function get_random_number() {
var number = randomFromTo(0, 100);
if ($.inArray(number, used_numbers) != -1) {
return get_random_number();
} else {
used_numbers.push(number);
return number;
}
}
function randomFromTo(from, to) {
return Math.floor(Math.random() * (to - from + 1) + from);
}
Question: How to alter the code so upon the btn click divs will start showing right away without initial waiting for 10 seconds? (take in mind I want to keep any further delay of 10 seconds in between of each div being shown)
Thank you.
Call it when you begin the interval
todo = setInterval((showQuotes(),showQuotes), 10000);
I am trying to make an image to fade out and then in. The problem is that when I use two functions, the image doesn't fade out but it immediately disappears. Is there anyone with amazing JavaScript skills to solve my problem?
Please do not tell me about jQuery because I already know how to do it using it, I only need to improve my JavaScript skills.
PS: I need also to understand why it doesn't work and how to make it work with as much details please.
Here is my code:
var el = document.getElementById("img1");
el.addEventListener("click", function() {
function fadeOut() {
el.style.opacity = 1;
function fade(){
var val = el.style.opacity;
if ((val -= .01) > 0){
el.style.opacity = val;
requestAnimationFrame(fade);
}
}
fade();
};
function fadeIn() {
el.style.opacity = 0;
function fade1() {
var val = el.style.opacity;
if ((val += .01) < 1){
el.style.opacity = val;
requestAnimationFrame(fade1);
}
}
fade1();
};
fadeIn();
fadeOut();
});
Thank you!
Still not the prettiest, but I have made just the minimum changes to your code to make it work: http://codepen.io/rlouie/pen/BzjZmK
First, you're assigning the opacity value back and forth repeatedly for no reason, which makes the code confusing to follow and also results in string concatenation instead of addition or subtraction, I have simplified this. Second, the functions were named the opposite of what they did, also confusing and fixed by me here. Finally, you ran both functions one after the other, so the second function set opacity to zero and then broke. Instead, I use a promise in your first function and resolve it when the animation completes.
That way the second function does not run until after the first one has completed animating.
var el = document.getElementById("img1");
el.addEventListener("click", function() {
function fadeOut() {
return new Promise(function (resolve, reject) {
let opacity = 1;
function fade(){
if ((opacity -= .01) > 0){
el.style.opacity = opacity;
requestAnimationFrame(fade);
} else {
resolve();
}
}
fade();
});
};
function fadeIn() {
let opacity = 0;
function fade1() {
if ((opacity += .01) < 1){
el.style.opacity = opacity;
requestAnimationFrame(fade1);
}
}
fade1();
};
fadeOut().then(fadeIn);
});
My proposal is:
start animation with fadein
when fadein finishes start the fadeout
var el = null;
function fadeIn(timestamp) {
var val = (+el.style.opacity == 0) ? 1 : +el.style.opacity;
if ((val -= .005) > 0) {
el.style.opacity = val;
window.requestAnimationFrame(fadeIn);
} else {
window.requestAnimationFrame(fadeOut);
}
}
function fadeOut(timestamp) {
var val = (+el.style.opacity == 0) ? 1 : +el.style.opacity;
if ((val += .005) < 1) {
el.style.opacity = val;
window.requestAnimationFrame(fadeOut);
}
};
window.onload = function () {
el = document.getElementById('img1');
el.addEventListener('click', function(e) {
window.requestAnimationFrame(fadeIn);
});
}
<img id="img1" src="http://www.loc.gov/pictures/static/data/highsm/banner.jpg">
Voor de fade in:
Function FadeIn() {
var milli = 3000; //duration
el = yourelement;
el.style.opacity = 1;
var a = 1 / (milli / 1000 * 16); //the -x
FadeIn_loop(a);
}
Function FadeIn_loop(a) {
if (el.style.opacity > 0.01) {
el.style.opacity = el.style.opacity - a;
setTimeout("FadeIn(" + el + ")", 16); //about 1/60 a second
} else {
el.style.opacity = 0;
}
}
Same thing for fade out, succes!
In your code are many things that does'nt seem to be right. First of get all those functions out of each other otherwise requestAnimationframe cant find the functions.
Maybe I'm not properly understanding setInterval but I have made a kind of slideshow script, as below:
var i = 0;
setInterval(function() {
$('.slide').fadeOut('slow').delay(200);
$('.slide:eq(' + i + ')').fadeIn('slow').delay(2000);
i++;
if(i == 5){
i = 0;
}
}, 4000);
This works, except for the first run - no slides will display for the first 4 seconds.
See Fiddle here: http://jsfiddle.net/vpa89snf/6/
Is there anyway I can trigger whats inside the setInterval function when it runs the first time round?
Use setTimeOut instead of setInterval for better performance, inspect the sample below:
Here is working jsFiddle.
var i = -1;
var totalSlide = $('.slide').length-1;
var slideTimer = 0;
function nextFrame() {
i == totalSlide ? i = -1 : i;
i++;
$('.slide').fadeOut(200);
$('.slide').eq(i).fadeIn(200);
slideTimer = setTimeout(nextFrame,4000);
}
$('#holder').addClass('isAni');
nextFrame();
// play / pause animation
$('#holder').click(function() {
if ( $(this).hasClass('isAni') ) {
$(this).removeClass('isAni');
clearTimeout(slideTimer);
}else{
$(this).addClass('isAni');
nextFrame();
}
});
You need to run the function and not wait for the 4 first seconds:
var i = 0;
function doSomething() {
$('.slide').fadeOut('slow').delay(200);
$('.slide:eq(' + i + ')').fadeIn('slow').delay(2000);
i = (i + 1) % 5;
}
$document.ready(function () {
setInterval(doSomething, 4000);
doSomething(); // run it!
});
JSFIDDLE.
This is how setInterval is executed. It runs your function after x milliseconds set as 2nd parameter.
What you have to do in order to show the first slide is to have the 1rst slide fadein like below:
var i = 0;
$('.slide:eq(' + i + ')').fadeIn('slow').delay(2000);
i++;
setInterval(function() {
...
}, 4000);
I have almost finished this slider, but I don't know how to implement the functionality for next() and prev(). How can I implement these functions?
http://jsfiddle.net/M4t4L/11/
$(function () {
var container = $("#scene"),
i = 0,
count = container.find("li").length,
j = container.find("li").length - 1,
isAnimating = false;
container.find("li:first").css({
"width": "100%"
});
$("#trigger").click(function (e) {
if (!isAnimating) {
isAnimating = true;
e.preventDefault(e);
i++; if (i >= count) { i = 0; }
j++; if (j >= count) { j = 0; }
container.find("li")
.finish()
.removeClass('active')
.last()
.width(0)
.addClass("active")
.animate({
"width": "100%"
}, 800,
function () {
container.find("li").first().appendTo(container);
isAnimating = false;
});
}
});
});
The problem is that when I implement these functions and press the next or prev. Displays the last slide on one second, and then switches to the desired
http://jsfiddle.net/M4t4L/9
If you want to get a Next or Prev function running, you want to take control of the number of the slider where you are. I'm afraid you will have to play around with your i/j and make the position go in both directions.
Right now you count up your i and j, where you might want to go is to have a position var and an array of slider objects, then the click only would have to call for the next/prev object to be loaded and the animation can begin.
Something like this maybe..
var pos = 0;
var container = $('#scene').find('li');
$('.back').click(function() {
pos = pos - 1;
moveIt(pos);
});
$('.forth').click(function() {
pos = pos +1;
moveIt(pos);
});
function moveIt(pos) {
container[pos]... // Your animation goes here
}
I have this code
var timeout = 0;
$('#container td').each(function(){
var td = this;
setTimeout(function() {
var new_text = $(td).find(text).html();
popup_text.html(new_text);
popup.fadeIn('fast').delay(1000).fadeOut('slow');
}, timeout);
timeout += 1000 + 1000;
});
I get text from table cells and is displayed in the layer with a delay.
1 question: How do I make this code to run in an endless loop?
2 question: How to do that when you hover the mouse over popop cycle temporarily stopped and then continue?
Thanks a lot!
One way is to put the code to be repeated in a function, and have the function repeat itself at the end:
var timeout = 1000;
var action = function() {
// Do stuff here
setTimeout(action, timeout);
};
action();
However, as ahren suggested, setInterval might be better:
var timeout = 1000;
var action = function() {
// Do stuff here
};
setInterval(action, timeout);
The difference is slight, but if the machine is running slowly for some reason, the setInterval version will run the code every second on average, whereas the setTimeout version will run the code once each second at most.
Neither of those methods really work well with each(), however, so you'll need to store the sequence of popups somewhere and step through them:
var timeout = 1000;
var tds = $('#container td');
var index = 0;
var action = function() {
var td = tds[index];
var new_text = $(td).html();
popup.html(new_text);
popup.fadeIn('fast').delay(1000).fadeOut('slow');
if(++index >= tds.length)
index = 0;
};
setInterval(action, timeout);
action();
Finally, to avoid moving to the next popup while the popup is hovered, you can add a check for that at the start of the function. It's also necessary to rearrange the animations so that they go "check for hover - fade out - change text - fade in".
var timeout = 1000;
var tds = $('#container td');
var index = 0;
var action = function() {
if(popup.is(':hover'))
return;
var td = tds[index];
var new_text = $(td).html();
popup.fadeOut('slow', function() {
popup.html(new_text);
}).fadeIn('fast');
if(++index >= tds.length)
index = 0;
};
setInterval(action, timeout);
action();
jsFiddle: http://jsfiddle.net/qWkYE/2/
If you like the short clean way, then use the jquery-timing plugin and write:
$.fn.waitNoHover = function(){
return this.is(':hover') ? this.wait('mouseleave') : this;
};
$('#popups div').repeat().each($).fadeIn('fast',$)
.wait(200).waitNoHover().fadeOut('slow',$).all()
See this on http://jsfiddle.net/creativecouple/fPQdU/3/