I'm making a site that has an area that it's content disappear and re-appears. So when the user clicks certain button, the <div>'s content fades out and fades in the content relative to the clicked icon.
First time the function getabout is clicked it works OK, but whenever I click on clear() and then again on getabout it starts blinking. I've discovered that it does the clean to the div but it happens that the content re-appears again from nothing and becomes intermittent.
Here is my JavaScript code, it's commented so you could give me a hand here:
var check = null; //this will be checking the instance of div's content
const wait_time = 50; //the time it will take to fade
function getabout(id) {
/* prevent second call to the same function to bug */
if (check == id) return;
var titleOpacity = 0,
textOpacity = 0;
/* this changes the title first */
document.getElementById("title").style.opacity = 0;
document.getElementById("title").innerHTML = "this is the title";
// recursive call to the opacity changer, it
// increases opacity by 0.1 each time until it's 1
setInterval(function () {
titleOpacity = fadeIn(titleOpacity, 'title');
}, wait_time);
/* changes the content next to the title */
window.setTimeout(function () {
document.getElementById("dialog").style.opacity = 0;
document.getElementById("dialog").innerHTML = "this is the content";
setInterval(function () {
textOpacity = fadeIn(textOpacity, 'dialog');
}, wait_time);
}, 500);
check = id; // defines the instance "about" at the moment
}
function fadeIn(opacity, id) {
opacity += 0.1;
document.getElementById(id).style.opacity = opacity;
document.getElementById(id).style.MozOpacity = opacity;
if (opacity >= 1.0) clearInterval(listener);
return opacity;
}
function clear() {
var opacity = document.getElementById("title").style.opacity;
// supposed to decrease the opacity by 0.1 but it's not doing that
setInterval(function () {
opacity = fadeout(opacity);
}, wait_time);
//cleans the title and dialog to fill with the next button user clicked
document.getElementById("title").innerHTML = "";
document.getElementById("dialog").innerHTML = "";
}
function fadeout(opacity) {
opacity -= 0.1;
document.getElementById("title").style.opacity = opacity;
document.getElementById("dialog").style.MozOpacity = opacity;
if (opacity <= 0.0) clearInterval(listener);
return opacity;
}
function getregister(id) {
if (check == id) return;
clear(); // proceed to fade out the content and clean it
check = id;
}
I don't understand what is the error of the code. with the clear() function it should smoothly fade out the content and then clean it. But it just cleans the div. And next time I use getabout() function, instead of smoothly fade in again as it does the first time, it starts to blink.
I'm relatively new to web programming and I refuse JQuery for now. I want to understand deeply javascript before go to JQuery and this is why I would just like to know pure JavaScript solutions and considerations about this.
Ive managed to cock up my comment so trying again!
I think your problem is that you're not clearing the setInterval correctly - ensure you use listener = setInterval(...)
As it stands your clearInterval(listener); is doing nothing as 'listener' is not defined. So your fade out function continues to run.
Related
Now I want my text to flicker jus like a tube light. This means there should be some noise in its blinking. it should not be a set definite interval in which opacity changes.
Here is what I came up with:
//find the text i want to flicker
text = document.getElementById("flicker");
console.log(text);
//initialise with 0
text.style.opacity=0;
//logic of wait function
function wait(ms){
var start = new Date().getTime();
var end = start;
while(end < start + ms) {
end = new Date().getTime();
}
}
while(true){
//logic to invert the opacity
if(text.style.opacity=1)
text.style.opacity=0;
else if (text.style.opacity=0)
text.style.opacity=1;
//find a random time interval b/w 0 to 0.5 sec
randVal = Math.random()*500+1;
//wait of that time and repeat the process for ever
wait(randVal);
}
Now the problem comes when I load the web page.
IT DOES NOT LOAD
MY GUESS: the infinite while loop is the problem and is running even before the DOM loads
but I have added the script at the end of my HTML file
Use a setTimeout and toggle a class instead.
//find the text i want to flicker
const text = document.getElementById("flicker");
console.log(text);
const getDuration = () => {
//find a random time interval b/w 0 to 0.5 sec
const randVal = Math.random()*500+1;
console.log(randVal);
return randVal;
};
const doFlicker = () => {
//logic to invert the opacity
text.classList.toggle('clear');
setTimeout(doFlicker, getDuration());
};
setTimeout(doFlicker, getDuration());
.clear {
color: #00000000;
}
<div id="flicker" class="clear">Flicker</div>
I'm trying to implement an effect identical to jQuery's fadeIn() function, where an element is displayed, and then it's opacity is animated from 0 to 1. I need to do it programmatically (WITHOUT jQuery), and I need the element to be able to fade out (display:none) and then fade back in.
The ideal solution will use a CSS transition to leverage hardware acceleration - I can get the element to fadeOut with great success by listening to the transitionend event. Fading back in, however is proving to be a challenge as the following bit of code is not working as intended:
fader.style.transition = 'opacity 1s';
const fadeIn = () => {
fader.style.display = 'block';
fader.style.opacity = 1;
};
When fadeIn() is called the element simply snaps back in, instead of smoothly animating. I have a codePen that I've been tinkering with to illustrate the problem.
My theory is that the transition is unable to execute on an element that's not in the DOM, as I can get the animation to work by setting height:0 instead of display:none. Perhaps there is a delay between when I set fader.style.display = 'block'; and when the DOM is actually being updated, during which I cannot transition?
On that idea: I also seem to be able to get the animation to work by delaying the opacity change with setTimeout(() => {fader.style.opacity = 1}, 20}. This seems to create a sort of race condition however because as the timeout duration gets closer to 0 the animation works less and less dependably.
Please note that I do not want to toggle the visibility attribute like the solutions to this question, as that does not effectively remove the element from the DOM.
Changing the height/width to 0 is a more viable option, but because the height and width of the element are not known, it will require the extra step of capturing those values before fading out so they can be re-applied when fading in. This seems flimsy if, say, a different part of the application tries to change those values (for example a media query, and the user rotates their device while the element is hidden)
The following code should effectively replace jQuery's fadeOut() and fadeIn() functions (Much thanks to #Kyle for the clue!).
const fadeIn = (el, ms, callback) => {
ms = ms || 400;
const finishFadeIn = () => {
el.removeEventListener('transitionend', finishFadeIn);
callback && callback();
};
el.style.transition = 'opacity 0s';
el.style.display = '';
el.style.opacity = 0;
requestAnimationFrame(() => {
requestAnimationFrame(() => {
el.addEventListener('transitionend', finishFadeIn);
el.style.transition = `opacity ${ms/1000}s`;
el.style.opacity = 1
});
});
};
const fadeOut = (el, ms, callback) => {
ms = ms || 400;
const finishFadeOut = () => {
el.style.display = 'none';
el.removeEventListener('transitionend', finishFadeOut);
callback && callback();
};
el.style.transition = 'opacity 0s';
el.style.opacity = 1;
requestAnimationFrame(() => {
requestAnimationFrame(() => {
el.style.transition = `opacity ${ms/1000}s`;
el.addEventListener('transitionend', finishFadeOut);
el.style.opacity = 0;
});
});
};
This became super clear after digging into rAF (requestAnimationFrame) and watching this video on the event loop. Right around 21:00 is where I had the aha moment about why rAF needs to be nested inside another rAF.
Here is the working example on Codepen.
Please comment if you discover any edge cases that aren't solved for :)
So I have a function that I'm trying to create the loops through an array to update a div's innerHTML with JavaScript. I was hoping to set the opacity to 0 and then 1 between setting the new data each time, without using jQuery's fadeIn() and fadeOut().
Here is what I have so far. I think I'm very close, but not sure what I'm doing that's slightly off.
Thanks!
slide(index, tweets, element) {
let self = this;
element.innerHTML = data[index].text;
element.style.opacity = 1;
setTimeout(() => {
index++;
element.style.opacity = 0;
setTimeout(self.slide(index, data, element), 2000);
}, 5000);
}
EDIT
I forgot to mention I'm banking on CSS3 for animation by adding a class to my div that changes with this:
transition: opacity 2s ease-in-out;
I don't know how the code you provided relates to the problem at hand, but here's a simple demo on how to fade out, change the text and then fade back in.
You should be able to expand on this for your needs.
var d = document.querySelector("div");
window.addEventListener("load", function() {
d.classList.add("hidden");
});
var i = 0;
d.addEventListener("transitionend", function() {
if (this.classList.contains("hidden")) {
i++;
this.innerHTML = "SUCCESS! ---> " + i;
}
this.classList.toggle("hidden");
});
div {
opacity: 1;
transition: opacity 2s;
}
div.hidden {
opacity: 0;
}
<div>LOADING...</div>
It just adds the hidden class to trigger the fade out and it binds a transitionend handler to change the text and remove the class for the fade in.
i made a function that change the opacity of an element, but you know it is not working, Following is my code:
function _opacity(ele, opacity,addOpac , delay ){
ele = document.getElementById(ele);
var CurrentOpacity = ele.style.opacity,
ChangeInOpacity = setInterval(function(){
if (CurrentOpacity > opacity ) { decrease();};
if (CurrentOpacity < opacity) { increase();};
if (CurrentOpacity == opacity) { stopInc();};
}, delay),
increase = function(){
ele.style.opacity = CurrentOpacity;
CurrentOpacity = CurrentOpacity+addOpac;
},
decrease =function(){
ele.style.opacity = CurrentOpacity;
CurrentOpacity = CurrentOpacity-addOpac;
},
stopInc = function(){
clearInterval(ChangeInOpacity);
};
}
one of the foremost feature of this function is that is doesn't uses any loop.
this ideology of using setInterval works perfectly in changing the width and height of element. But here this function is not functioning.
What i know is that it is not adding any style attribute to the element which is passed to the above function
what is the mistake here because of which this is not working?
thanks in advance.
There are a few problems there:
To get the current opacity of the element, you need to use the getComputedStyle function (or currentStyle property on oldIE), not .style.opacity. The latter only has a value if it's been assigned explicitly, rather than implicitly through style sheets.
The value will be a string, so you need to convert it to a number.
It's unlikely that you'll exactly match the target opaccity, so you need to just stop when you cross the target.
You don't put ; at the end of if statements, so remove those.
You assign the opacity, but then increment it, and then later the incremented value is what you check to see if you're done, so even if it weren't for #3, you'd stop early.
In JavaScript, the overwhelming convention is to start local variable names with a lower-case letter. I changed the name of your timer handle to timer.
Your best bet is to figure out what direction you're going, then stop when you pass the target:
// Polyfill getComputedStyle for old IE
if (!window.getComputedStyle) {
window.getComputedStyle = function(element) {
return element.currentStyle;
}
}
// Your _opacity function
function _opacity(ele, opacity, addOpac, delay) {
var direction;
ele = document.getElementById(ele);
// Determine direction
direction = +getComputedStyle(ele).opacity < opacity ? 1 : -1;
var timer = setInterval(function() {
// Get the *computed* opacity
var current = +getComputedStyle(ele).opacity;
if (direction > 0) {
if (current < opacity) {
increase(current);
} else {
stopInc();
}
}
else {
if (current > opacity) {
decrease(current);
} else {
stopInc();
}
}
}, delay),
increase = function(current) {
// Increase, but don't go past target
ele.style.opacity = Math.min(current + addOpac, opacity);
},
decrease = function(current) {
// Decrease, but don't go past target
ele.style.opacity = Math.max(current - addOpac, opacity);
},
stopInc = function() {
clearInterval(timer);
};
};
// Run
_opacity("target", 0.3, 0.05, 50);
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
<div id="target">this is the element</div>
you can do this:
ele.style.opacity = "0.2";// some desired value but string if for all browsers.
for more info see this post:Setting opacity of html elements in different browsers
I am trying to put a play button in my image gallery. I have a small pice of code that needs work,but my problem is getting the images to display one at a time. The code below brings up all the pictures at once. What I am wondering is if I can work this by classname or will I need to build an array and work from that.
This is the code that partialy works showing all at once. I think I am just missing something simple.
<script>
function slide_show() {
var slides = document.getElementsByClassName("s"),
i = slides.length;
for(i=0; i<15; i++) {
slides[i].style.visibility = "visible";
slides[i].style.transition="visibility 5s ease 5s"
}
}
</script>
Try using a setTimeout to delay the movement and add some opacity to make them fade in:
var count = 0;
function slide_show() {
var slides = document.getElementsByClassName("s"),
i = slides.length;
if (count < i) {
slides[count].style.visibility = "visible";
slides[count].style.opacity = "1";
slides[count].style.transition="opacity 5s ease 5s"
count++;
setTimeout(slide_show, 500);
}
}
slide_show();
By changing the opacity numbers or the setTimout numbers - you can get different fade effects. Check out this codepen to see it in action.
You can change your function a little bit so it waits for the animation to finish:
<script>
var index = 0;
function slide_show() {
var slides = document.getElementsByClassName("s");
if(index >= slides.length)
return;
slides[index].style.visibility = "visible";
slides[index].style.transition = "visibility 5s ease 5s";
setTimeout(slide_show, 10000); // Since it takes 10 seconds to finish your animation I put in 10000
index++;
}
}
</script>