how to know opacity value using javascript? - javascript

I am using transition: opacity 5s; property. I want to show different alert or console message when my opacity value is 0.4 or 0.6 or .2 . on button click I am doing transition but I want to know opacity progress so that i will show those message ?
is there any way to do this
var btn = document.querySelector("button");
var par = document.querySelector("#parId");
btn.addEventListener("click", (e) => {
par.classList.add("removed");
});
par.addEventListener("transitionend", () => {
par.remove();
});
#parId {
transition: opacity 5s;
}
.removed {
opacity: 0;
}
we are getting transitionend callback if there any progress callback where I will check opacity value ?

There is no event that can be listened to to give what you want - unless you are going to use a linear transition. In that case you can carve your changes of opacity up into 0.2s slots, changing opacity on transitionend to the next value down - 0.8, 0.6 etc.
Your code however takes the default for the transition-timing-function property which is ease - not linear - so transitionend is of no use to you.
This snippet polls the opacity changes every tenth of a second and writes the current opacity to the console so you can see what is happening.
A couple of points: you will have to check for when the opacity goes just less than one of your break points, you are unlikely every to hit it just at exactly 0.6s or whatever; also notice that the console carries on being written to after the element has totally disappeared. The timing will not be exact, things are happening asynchronously.
<style>
#parId {
transition: opacity 5s;
width: 50vw;
height: 50vh;
background: blue;
opacity: 1;
display: inline-block;
}
.removed {
opacity: 0;
}
</style>
<div id="parId"></div>
<button>Click me</div>
<script>
var btn = document.querySelector("button");
var par = document.querySelector("#parId");
btn.addEventListener("click", (e) => {
let interval = setInterval(function () {
const opacity = window.getComputedStyle(par).opacity
console.log(opacity);
if (opacity == 0) {clearInterval(interval);}
}, 100);
par.style.opacity = 0;
});
</script>

You could potentially check periodically like this, although your interval will need to be at least the speed of the opacity animation or be quicker than it to catch the values.
var par = document.querySelector("#parId");
setInterval(function() {
console.log(window.getComputedStyle(par).opacity);
}, 100)
#parId{
opacity: 0.2;
transition: opacity 3s ease-in-out;
}
#parId:hover {
opacity: 1;
}
<div id="parId">
test
</div>

Take a look in this example
https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/animationend_event
You could define your animation stages as diferent ranimations on css then call them in chain via javascript. Before, you must set an event listener for the animationend event, and every time the event is fired you check the #parId opacity.
You could do it.with jQuery to, totaly in javascript

Related

Fade In and Fade Out using pure Javascript in a simple way

I've been trying to create a fadeIn & fadeOut animation using VanillaJS in my project but I literally don't understand what's the problem. I'm using SCSS. I made it simple for you.
I tried visibility but it didn't work too. like it appears e.g. for 200ms but then immediately disappears. In another way of explanation, it appears whenever I click on it (stable) and then goes away after 200ms (unstable).
const fade = () => {
const box = document.querySelector('#box');
box.classList.toggle('fade');
};
document.querySelector('#fadebtn').addEventListener('click', fade);
#box {
width: 70px;
height: 50px;
background: #FD7A6B;
display: none;
opacity: 0;
-webkit-transition: 200ms ease-in-out;
-moz-transition: 200ms ease-in-out;
-o-transition: 200ms ease-in-out;
transition: 200ms ease-in-out;
}
#box.fade {
display: block !important;
opacity: 1 !important;
}
// I also tried this, wondered it may work, but didn't.
// .fade {
// display: block !important;
// opacity: 1 !important;
// }
<button type="button" id="fadebtn">Fade</button>
<div id="box"></div>
I wrote this due to the title of the question: "Fade in ... pure javascript ... simple way."
tl;dr https://jsfiddle.net/nqfud4j0/
The following solution is a basic example of how you can use only Javascript to fade in/out to a desired value. You could also use this with other values/properties, but it also serves as an example for basic tweening.
It's intentionally using setInterval rather than requestAnimationFrame to demonstrate the example's use of time + controlled framerate rather than a delta or 'fast as possible.' A good solution would abstract this logic into a tweening library that combines both RAF + intervals to manage latency between frames.
function fadeTo(element, toValue = 0, duration = 200) {
// Store our element's current opacity (or default to 1 if null)
const fromValue = parseFloat(element.style.opacity) || 1;
// Mark the start time (in ms). We use this to calculate a ratio
// over time that applied to our supplied duration argument
const startTime = Date.now();
// Determines time (ms) between each frame. Sometimes you may not
// want a full 60 fps for performance reasons or aesthetic
const framerate = 1000 / 60; // 60fps
// Store reference to interval (number) so we can clear it later
let interval = setInterval(() => {
const currentTime = Date.now();
// This creates a normalized number between now vs when we
// started and how far into our desired duration it goes
const timeDiff = (currentTime - startTime) / duration;
// Interpolate our values using the ratio from above
const value = fromValue - (fromValue - toValue) * timeDiff;
// If our ratio is >= 1, then we're done.. so stop processing
if (timeDiff >= 1) {
clearInterval(interval);
interval = 0;
}
// Apply visual. Style attributes are strings.
element.style.opacity = value.toString();
}, framerate)
}
// Element reference
const element = document.querySelector('div');
// Fade in and out on click
element.addEventListener('click', e => {
// Animates our element from current opacity (1.0) to 0.25 for 1000ms
fadeTo(element, 0.25, 1000);
// Waits 1s, then animates our element's opacity to 1.0 for 500ms
setTimeout(() => {
fadeTo(element, 1.0, 500);
}, 1000);
});

Transition Opacity w/javascript not working

I want to fadein a component after ajax call completes and jquery has rebuilt DOM.
I have this setup:
index.html:
<head>
<style>
body {
opacity: 0;
transition: opacity 2s;
}
</style>
</head>
<body onload="document.body.style.opacity='1'">
<div class="content">
<!-- Markup for content -->
</div>
</body>
main.css
.content {
opacity: 0;
transition: opacity 6s;
transition: opacity 2s;
-webkit-transition: opacity 6s;
-moz-transition: opacity 6s;
}
main.js
$(document).ready(function () {
const contentEl = document.querySelector(".content");
$(".submit").on("click", async function (e) {
e.preventDefault();
console.log(contentEl.style.opacity);
if (contentEl.style.opacity == 1) {
contentEl.style.opacity = 0;
console.log("Style opacity is in if and = %s", contentEl.style.opacity);
}
// Do Ajax and update DOM via jQuery
contentEl.style.opacity = 1;
}
The first time thru .content fades in as expected as well as fade in of whole page on initial render. However subsequent times thru there is no transition effect. Logging shows that I am changing style.opacity from 1 -> 0 and back to 1 after initial iteration. Any CSS guru's versed in CSS's dark secrets input advice appreciated.
$(document).ready(function () {
const contentEl = document.querySelector(".content");
contentEl.style.opacity = 1; // Define initial opacity (starting val)
$(".submit").on("click", async function (e) {
e.preventDefault();
contentEl.style.opacity = 0; // on click set opacity to 0?
FadeIn(); // Let's Fade from 0 to 1!
});
let FadeIn = () => { // Function
if (contentEl.style.opacity < 1) { // If opacity doesn't equal 1
contentEl.style.opacity += 0.2; // Let's add 0.2!
setTimeout(FadeIn(), 300); // Hell let's repeat that more 300ms
}
}; // Once we equal 1 we should be done
});
I don't play with the JQuery like that, I much rather too use CSS entirely for the animation process of these types of things, it's cleaner (less jitter). I'm assuming this is what you're sort of after though, a simple set value and slowly loop till finished. Button will start out 1 opacity, when clicked jump to 0 and slowly climb its way back up to 1.

Opacity transition css animation works from higher to lower but not vice versa

I have what should be a very simple problem, perhaps a typo that I just can't see.I have a page blocker that grays the page out with an opacity transition and blocks any clicks when I launch a form. This works in hideForm, but does not in showForm and it immediately become 0.4 opacity. Weird because all they are doing is the opposite of each other with a timeout in hideForm to set's it to display to none when opacity transition is finished.
I think this will end being a simple solution and I'll end up being asked to delete the question, which I will gladly do, but I've been trying to solve this for too long and I need a second pair of eyes.
I tried to minimize the amount of code shown but will post more if asked.
#pageCover {
opacity: 0;
-moz-transition: opacity 1s;
-webkit-transition: opacity 1s;
transition: opacity 1s;
display:none
}
This works great
function hideForm() {
if (form.style.top > '0px') {
pageCover.style.opacity = 0.0;
setTimeout(function () { pageCover.style.display = 'none'; }, 1000);
}
}
This displays the pageCover but ignores the transition and goes right to 0.4 . How can the transition work one way, but not the opposite way? I'm stumped.
function showForm() {
if (form.style.top < '0px') {
pageCover.style.opacity = 0.4;
pageCover.style.display = 'block';
}
}
The opacity attribute animates but not the "display" attribute. When they are set at the same time, the opacity transition will not be observed. You can play with the numbers but for illustration's sake, let's add a 10ms gap between the two operations:
pageCover.style.display = 'block';
setTimeout(function(){
pageCover.style.opacity = 0.4;
},10);
You can push the number to even 0, but the browser might "optimize" it away.
Live Example:
const pageCover = document.getElementById("pageCover");
function hideForm() {
pageCover.style.opacity = 0;
setTimeout(function () {
pageCover.style.display = 'none';
}, 1000);
}
function showForm() {
pageCover.style.display = 'block';
setTimeout(function () {
pageCover.style.opacity = 0.4;
}, 10);
}
document.getElementById("btn-show").addEventListener("click", showForm);
document.getElementById("btn-hide").addEventListener("click", hideForm);
#pageCover {
opacity: 0;
-moz-transition: opacity 1s;
-webkit-transition: opacity 1s;
transition: opacity 1s;
display: none;
}
<div id="pageCover">
This is the page cover
</div>
<input type="button" id="btn-show" value="Show">
<input type="button" id="btn-hide" value="Hide">

JS changing source image with animation

I have a problem with looped fade-in/fade-out image source changing in JS and CSS and using SetTimeout() callback.
The problem is, that the sequence is working strange: sometimes the image changes before the transition starts, sometimes it works fine, and sometimes in the other way.
Here is my JS:
const animationTime = 5000;
const transitionTime = 500;
function nextImage() {
let img = document.getElementById('img1');
img.classList.remove('hidden');
setTimeout(function () {
img.classList.add('hidden');
},animationTime-transitionTime);
img.src=randomize();
setTimeout(nextImage, animationTime);
}
randomize() function just gets a random image path from array.
Here is HTML:
<div class="some-class">
<img class="some-image" id="img1" src="1.png">
</div>
And here is CSS:
.some-image {
transition: opacity 0.5s linear;
-webkit-transition: opacity 0.5s linear;
-o-transition: opacity 0.5s linear;
-moz-transition: opacity 0.5s linear;
-moz-border-radius: 15px;
}
.hidden {
opacity: 0;
}
Upd.
So I have edited CSS file:
.some-image {
width: 370px;
height: 190px;
animation: fade-out;
animation-duration: 1s;
}
.hidden {
animation: fade-out;
animation-duration: 1s;
}
#keyframes fade-in {
from {opacity: 0;}
to {opacity: 1;}
}
#keyframes fade-out {
from {opacity: 1}
to {opacity: 0}
}
And JS-file:
function nextImage() {
let img = document.getElementById('img1');
img.classList.remove('hidden');
setTimeout(function () {
img.classList.add('hidden');
},animationTime-1000);
img.src=randomize();
}
setTimeout(nextImage, animationTime);
}
And, somehow, it works perfectly on a local machine, but on a dedicated website animation sometimes fades-in before the image source changed.
I think the problem is about timing. The setTimeout function didn't guarantee to execute exactly time as argument set. So there is a possibility that you change the src of image before/after it add/remove hidden class. These delay is rarely happens that might be the reason why it works on your machine.
So this problem can solve by every time you change the image you must have to make sure the image is completely hide.
const nextImage = function () {
let img = document.querySelector('img')
img.classList.add('hidden')
setTimeout(() => {
img.style.visibility = 'hidden'
img.src = randomImage()
// skip to next frame, may be this not necessary to use setTimeout
setTimeout(() => {
img.style.visibility = ''
img.classList.remove('hidden')
}, 10)
}, animationDuration)
setTimeout(nextImage, intervalDuration + animationDuration)
}
The new cycle will be: fade image out, wait for animation then change image (with set visibility to hidden) and then fade in. And loop.
With this approach. If setTimeout is early execute before the image has completely fade out the visibility will be set hidden. If it's delayed, the image will be hide a bit longer.
Live example here. In that code I add a little bit noise with random time to test.
Unfortunately, After I spent an hour to see my answer is right I still feel it's not perfect anyway and it will be worse if you image is large. I would recommend you try two or more img tags instead.
You should try using css animations instead. You can easily implement the above with it, and it will save you the trouble of handling animations in your code.

How to stop one eventListener when start another on the same element?

I'm creating some kind of gallery in js as a practice. I found an error and I don't know how to solve it.
Full code of on JSFiddle ->
Code
Background
I add two eventListeners to my img wrapper,
wrapper looks like that:
<div class="gallery-item"> <-- wrapper
<img src=""> <-- image
<div> <-- overlay
</div>
</div>
and listeners like that (listeners I'm adding during creating wrappers in js):
imageWrapper.addEventListener('mouseenter', enableOverlay, false);
imageWrapper.addEventListener('mouseleave', disableOverlay, false);
Listeners invokes functions, which are responsible for displaying overlay over image. First of them show overlay with fade effect and the second one hide it with the same effect.
enableOverlay
function enableOverlay(e) {
var el = this.childNodes[1].style;
el.display = 'block';
(function fadeIn() {
if (el.opacity < 1) {
el.opacity = parseFloat(el.opacity) + Number(0.1);
setTimeout(fadeIn, 30);
}
}());
}
disableOverlay
function disableOverlay(e) {
var el = this.childNodes[1].style;
(function fadeOut() {
if (el.opacity > 0) {
el.opacity = parseFloat(el.opacity) - Number(0.1);
setTimeout(fadeOut, 30);
} else {
el.display = 'none';
}
}());
}
Problem
On first sight everything is ok if I'm slowly move mouse over images - one function ends (opacity = 1) and the second is starting until opacity = 0. But when I'm moving mouse fast over images, overlays start to blink - opacity increases and decreases by 0.1 (value in IIFEs) and script loop.
As I figured out, reason of this behavior is that enableOverlay dosen't finish (el.opacity dosen't reach 1) and in the same time disableOverlay starts. And I don't know how to fix this situation.
I was trying to deal with it using flags which represents the state of fading function and breaks IFFEs, but it didn't help.
Long story short, can anyone help me with this problem or show me a way of thinking to solve it?
EDIT
In my opinion, my problem is 'how to stop function in one eventListener when another eventListeners is fired'. Changing opacity is only a sample.
You can use css transition.
function enableOverlay(e) {
var el = this.childNodes[1].style;
el.opacity = '1';
}
function disableOverlay(e) {
var el = this.childNodes[1].style;
el.opacity = '0';
}
.gallery-item img+div {
cursor: pointer;
opacity: 0;
-webkit-transition: opacity .3s ease;
-moz-transition: opacity .3s ease;
-o-transition: opacity .3s ease;
-ms-transition: opacity .3s ease;
transition: opacity .3s ease;
}
https://jsfiddle.net/zjqpxzmj/
Just added an attribute to track the event.
Fiddle
function disableOverlay(e) {
var el = this.childNodes[1].style;
var that = this.childNodes[1];
that.setAttribute('op','fadeOut');
(function fadeOut() {
if (el.opacity > 0 && that.getAttribute('op')==='fadeOut') {
el.opacity = parseFloat(el.opacity) - Number(0.1);
setTimeout(fadeOut, 30);
} else {
el.display = 'none';
}
}());
}
In your case, catching the latest setTimeout and calling clearTimeout on it from the other function should help.

Categories

Resources