JavaScript image fade out and in (using only JavaScript, no jQuery) - javascript

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.

Related

setInterval to fade in then fade out pure javascript no jquery or css

I am trying to implement a fade in/fade out feature that runs on a button click depending if some data was changed. I am using angular but the ngAnimate I could not get to work so I want to do it with pure js. What I currently have will flash the text for a second, then do nothing. This is inside my controller.
var warningText = document.getElementById('warningText');
warningText.style.display = 'inline'
$scope.warningText = "Warning: No Data was updated.";
var op = 0.0;
var fadeIn = setInterval(function() {
if (op >= 1) {
clearInterval(fadeIn);
fadeOut(op);
}
warningText.style.opacity = op;
op += op * 0.1;
}, 50);
var fadeOut = function(op) {
setInterval(function() {
if (op <= 0.1) {
clearInterval(fadeOut);
warningText.style.display = 'none';
}
warningText.style.opacity = op;
op -= op * 0.1;
}, 50);
}
Your calculation of op is wrong as that will always be zero. Secondly the second function does not return the value from setInterval, so you'll never be able to clear that interval.
Here is how you could do it with just one interval, where the sign of the increments to the opacity is reversed every time the boundary value is reached:
var warningText = document.getElementById('warningText');
function flickerMessage(msg) {
var op = 0.1;
var increment = +0.1;
warningText.textContent = msg;
warningText.style.opacity = 0;
warningText.style.display = 'inline';
var timer = setInterval(function() {
op += increment;
warningText.style.opacity = op;
if (op >= 1) increment = -increment;
if (op <= 0) {
warningText.style.display = 'none';
clearInterval(timer); // end
}
}, 50);
}
flickerMessage('Warning you');
<div id="warningText" style="display:none; opacity: 0">warning text</div>
<hr>

Javascript div fade in not working using setInterval

I'm trying to make a div containing a number of pictures to fade in but its not working and I don't know why. I believe that the inverval is not even being called. The div's opacity is set to 0.0 This is the code:
var movies = getElementById("movies");
var apparence = function(){
if(movies.style.opacity < 1.0){
movies.style.opacity = movies.style.opacity + 0.1;
} else { clearInterval(timer);
}
}
var timer = window.setInterval(apparence, 1000);
Thank you very much.
To set your movies var, you need to call:
document.getElementById('movies');
The way you are attempting to increment opacity didn't work, so I've updated your example.
New Code:
var movies = document.getElementById("movies");
var opacity = 0.1;
var apparence = function(){
if(opacity <= 1.0) {
movies.style.opacity = opacity;
} else {
clearInterval(timer);
}
opacity += 0.1;
}
var timer = window.setInterval(apparence, 1000);
JS Fiddle:
http://jsfiddle.net/onov6cq4/1/
Here is your problem
Problem1:
If you have defined your css using
#movies {
opacity: 0.0;
}
then document.getElementById().style.opacity is empty since it takes from inline style i.e. <div id="movies" style="opacity: 0.0">
Problem 2:
movies.style.opacity = movies.style.opacity + 0.1;
movies.style.opacity returns a string so you are basically appending string which results in 0.10.1 and so on. You need to do parseFloat! The attached fiddle will solve your problem
Code:
var moviesOp = document.getElementById('movies').style.opacity;
function apparence(){
console.log('interval called with op = ' + moviesOp);
if(moviesOp < 1.0){
moviesOp = parseFloat(moviesOp, 10) + 0.1;
} else {
clearInterval(timer);
}
}
var timer = setInterval(apparence, 1000);
<div id="movies" style="opacity: 0.0">
JSBin With Inline Style
If you want to use in css and not inline then use getComputedStyle. This i tried and works as u wanted
var movies = document.getElementById('movies');
function apparence(){
var moviesOp = getComputedStyle(movies).getPropertyValue('opacity');
console.log('interval called with op = ' + moviesOp);
if(moviesOp < 1.0){
movies.style.opacity = parseFloat(moviesOp, 10) + 0.1;
} else {
clearInterval(timer);
}
}
var timer = setInterval(apparence, 1000);
Non Inline jsBin

How to change the speed of setInterval in real time

I would like to know how to change the speed of setInterval in real time e.g:
if (score < 10)
repeater = setInterval(function() {
spawnEnemy();
}, 1000);
if (score => 10)
repeater = setInterval(function() {
spawnEnemy();
}, 500);
I know this method doesn't work, but is there a way that I can achieve this some other way?
jsFiddle Demo
There is no way to change the interval speed itself once running. The only way to do it is to have a variable for the speed, and then clear the interval and start a new one with the new speed.
var speed = 500;
var changeSpeed = speed;
repeater = setInterval(repeaterFn, speed);
function repeaterFn(){
spawnEnemy();
if( changeSpeed != speed ){
clearInterval(repeater);
speed = changeSpeed;
repeater = setInterval(repeaterFn, speed);
}
}
function changeRepeater(){
changeSpeed = 700;
}
Another way would be to just use setTimeout rather than setInterval. Do the check every time so you can keep your speed logic in a seperate function.
var game_over = false;
var score = 0;
function getSpeedFromScore(score)
{
if (score > 20) {
game_over = true;
}
if (score < 10) {
return 1000;
} else {
return 500;
}
}
function spawnEnemyThenWait() {
if (!game_over) {
spawnEnemy();
var speed = getSpeedFromScore(score);
setTimeout(spawnEnemyThenWait, speed);
}
}
JS Fiddle http://jsfiddle.net/bq926xz6/
You can use clearInterval:
if (score < 10) {
clearInterval(repeater);
repeater = setInterval(spawnEnemy, 1000);
}
if (score => 10) {
clearInterval(repeater);
repeater = setInterval(spawnEnemy, 500);
}
But it depends on the context. If this snippet is executed more often, than it has to be, you will need some kind of mechanism to prevent it from resetting your interval all the time.
But there is (as I wrote in the comment to the question) no way to use clearInterval and change the interval itself. At least not without replacing it by a new interval as shown above.
You can use a game loop and track the spawn state in an enemy class:
// press f12 so see console
function Enemy() {
this.spawned = false;
this.spawnOn = 20;
this.tick = function () {
this.spawnOn = this.spawnOn - 1;
if (this.spawnOn == 0) {
this.spawned = true;
}
}
this.goBackToYourCage = function () {
this.spawnOn = Math.floor(Math.random() * 50) + 1;
this.spawned = false;
}
}
var enemy = new Enemy();
window.setInterval(function () {
enemy.tick();
if (enemy.spawned) {
console.log('spawned');
enemy.goBackToYourCage();
console.log('Next spawin in :' + enemy.spawnOn);
}
}, 100);
http://jsfiddle.net/martijn/qxt2fe8y/2/

Remove div after fade out animation - javascript

I'm trying to remove a div from the body AFTER an animation is completed, but at the moment looks like the remove happens right after the first iteration of the animation.
function $(el) { return document.getElementById(el); }
var divFirst = $('first');
if(divFirst)
divFirst.addEventListener("click", addSecond);
function removeSecond()
{
fadeOut();
var child = $('second');
console.log("remove called");
child.remove();
}
function addSecond()
{
console.log("addSecond called");
var aContainer = document.createElement('div');
aContainer.setAttribute('id', 'second');
aContainer.innerHTML = "Second";
aContainer.addEventListener("click", removeSecond);
document.body.appendChild(aContainer);
fadeIn();
}
function fadeIn()
{
var secondDiv = $('second');
if(secondDiv)
{
secondDiv.style.opacity ? secondDiv.style.opacity :
secondDiv.style.opacity = "0.0";
if(parseFloat(secondDiv.style.opacity) <= 1)
{
secondDiv.style.opacity = parseFloat(secondDiv.style.opacity) + 0.05;
setTimeout(fadeIn, 50);
}
}
}
function fadeOut()
{
var secondDiv = $('second');
if(secondDiv)
{
console.log(secondDiv.style.opacity);
if(parseFloat(secondDiv.style.opacity) >0 )
{
secondDiv.style.opacity = parseFloat(secondDiv.style.opacity) - 0.05;
setTimeout(fadeOut, 50);
}
}
}
Here the jsfiddle: http://jsfiddle.net/ny85ckk2/
If I remove the child.remove() call, the animation continues till the end.
Any idea?
Thanks a lot
Your fadeOut is an asynchronous operation. When you call it, it starts the fade, but then the fade continues and completes asynchronously because you're using setTimeout. So your code after callilng fadeOut runs just after it starts.
To remove the element when done, remove that code and instead remove the element in fadeOut when done:
function fadeOut()
{
var secondDiv = $('second');
if(secondDiv)
{
console.log(secondDiv.style.opacity);
if(parseFloat(secondDiv.style.opacity) >0 )
{
secondDiv.style.opacity = parseFloat(secondDiv.style.opacity) - 0.05;
setTimeout(fadeOut, 50);
}
else // Added
{ // Added
secondDiv.remove(); // Added
} // Added
}
}
Or if you want more flexibility, have fadeOut call a callback when done and remove the element in the callback; we do that by separating out the actual work of the fade from starting it:
function fadeOut(callback)
{
var secondDiv = $('second');
if (secondDiv)
{
doFade();
}
function doFade() {
if(parseFloat(secondDiv.style.opacity) >0 )
{
secondDiv.style.opacity = parseFloat(secondDiv.style.opacity) - 0.05;
setTimeout(doFade, 50);
}
else if (callback)
{
callback(secondDiv);
}
}
}
Usage:
function removeSecond()
{
fadeOut(function(div) {
div.remove();
});
}
Fiddle

Sequentially highlighting divs using javascript

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
);

Categories