delay function execution JS - javascript

I want to toggle between showing and hiding two divs on a mouseenter and click event. However, if the click event happens in the same position as the mouseenter area the functions go into a loop, illustrated in the gif below.
How can I delay the showOverlay function for a few seconds but maintain the mouseenter event working normally like in the gif below (i.e no delay):
Any help would be greatly appreciated?
var hover = document.querySelector('#hover');
var overlay = document.querySelector('#overlay');
var primary = document.querySelector('#primary');
var overlayShowing = false;
var clicked = false
function showOverlay() {
overlayShowing = true
overlay.classList.add('display');
setTimeout(function(){
overlay.classList.add('active');
}, 100);
primary.classList.add('nactive');
}
function hideOverlay() {
overlayShowing = false
overlay.classList.remove('active');
primary.classList.remove('hidden');
setTimeout(function(){
primary.classList.remove('nactive');
}, 100);
}
primary.addEventListener('transitionend', function() {
if(overlayShowing) {
primary.classList.add('hidden');
}
})
overlay.addEventListener('transitionend', function() {
if(!overlayShowing) {
overlay.classList.remove('display');
}
});
hover.addEventListener('mouseenter', function(event) {
showOverlay();
});
overlay.addEventListener("click", function() {
hideOverlay();
});
#primary {
opacity: 1;
display: block;
transition: 0.5s ease
}
#primary.hidden {
display: none !important;
}
#primary.nactive {
opacity: 0;
}
#hover {
font-size: 150px;
}
#overlay {
position: fixed;
height: 100vh;
width: 100vw;
top: 0;
left: 0;
background-color: black;
opacity: 0;
display: none;
transition: 0.5s ease
}
#overlay.active {
opacity: 0.8;
}
#overlay.display {
display: block;
}
<div id="primary">
<div id="hover">HOVER</div>
</div>
<div id="overlay"></div>

Just use a timeout to delay the showing:
var showTimeout;
function showOverlay() {
if(showTimeout) return;
showTimeout = setTimeout(() => {
overlayShowing = true;
overlay.classList.add('display');
setTimeout(function(){
overlay.classList.add('active');
}, 100);
primary.classList.add('nactive');
}, 500);
}
function hideOverlay() {
if(showTimeout) {
clearTimeout(showTimeout);
showTimeout = null;
}
overlayShowing = false
overlay.classList.remove('active');
primary.classList.remove('hidden');
setTimeout(function(){
primary.classList.remove('nactive');
}, 100);
}

Related

How to make custom cursor stay with cursor on scroll

Looking for some help with a custom cursor. It's all working fine except for when you scroll, the custom cursor stays where it is on the page until you move the mouse again and then it catches up. So I need to make the custom cursor stick to the position of the default cursor at all times.
Thanks in advance!
const queryCursor = document.querySelector(".cursor");
var cursor = {
delay: 8,
_x: 0,
_y: 0,
endX: window.innerWidth / 2,
endY: window.innerHeight / 2,
cursorVisible: true,
cursorEnlarged: false,
$cursor: queryCursor,
init: function () {
this.outlineSize = this.$cursor.offsetWidth;
this.setupEventListeners();
this.animateDotOutline();
},
setupEventListeners: function () {
var self = this;
// On Hover Active
document.querySelectorAll("a, img, .elementor-custom-embed-image-overlay, button").forEach(function (el) {
el.addEventListener("mouseover", function () {
self.cursorEnlarged = true;
queryCursor.classList.add("active");
});
el.addEventListener("mouseout", function () {
self.cursorEnlarged = false;
queryCursor.classList.remove("active");
});
});
// On Hover Disappears
document.querySelectorAll("input, textarea, iframe, video, .footer").forEach(function (el) {
el.addEventListener("mouseover", function () {
self.cursorEnlarged = true;
queryCursor.classList.add("hidden");
});
el.addEventListener("mouseout", function () {
self.cursorEnlarged = false;
queryCursor.classList.remove("hidden");
});
});
document.addEventListener("mousemove", function (e) {
self.cursorVisible = true;
self.toggleCursorVisibility();
self.endX = e.pageX;
self.endY = e.pageY;
});
document.addEventListener("mouseenter", function (e) {
self.cursorVisible = true;
self.toggleCursorVisibility();
self.$cursor.style.opacity = 1;
});
document.addEventListener("mouseleave", function (e) {
self.cursorVisible = true;
self.toggleCursorVisibility();
self.$cursor.style.opacity = 0;
});
},
animateDotOutline: function () {
var self = this;
self._x += (self.endX - self._x) / self.delay;
self._y += (self.endY - self._y) / self.delay;
self.$cursor.style.top = self._y + "px";
self.$cursor.style.left = self._x + "px";
requestAnimationFrame(this.animateDotOutline.bind(self));
},
toggleCursorVisibility: function () {
var self = this;
if (self.cursorVisible) {
self.$cursor.style.opacity = 1;
} else {
self.$cursor.style.opacity = 0;
}
}
};
cursor.init();
.cursor {
z-index: 1000;
pointer-events: none;
position: absolute;
top: 50%;
left: 50%;
border-radius: 50%;
opacity: 0;
transform: translate(-50%, -50%);
transition: opacity 0.3s ease-in-out, transform 0.3s ease-in-out, background-color 0.3s, width 0.3s, height 0.3s;
width: 20px;
height: 20px;
background-color: #EBF602;
display: flex;
align-items: center;
justify-content: center;
}
.cursor.active {
transform: translate(-50%, -50%) scale(2);
opacity:0.7 !important;
}
.cursor.hidden {
opacity: 0 !important;
}
section{
min-height:100vh;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="cursor"></div>
<section></section>
<section></section>

The equivalent of pointer-events:none in javascript

I'm facing a problem with wiggling bottom border pseudo css element, pointer events set to none fixes it but I have decide to go with javascript and create a span on mouse enter event and remove it on mouse leave event. with set time method, I created an acceptable animation like feeling but now back to the same problem WIGGLING. So is there an equivalent code in javascript that mimics pointer events set to none?
<a class="top-link">
<span class="title"> Title </span>
</a>
.border-bottom {
border-bottom: solid 3px #ddd;
content: "";
width: 100%;
position: absolute;
top: 100%;
z-index: 1;
left: 0;
transform: translateY(4px);
transition: ease-in 0.2s;
opacity: 0;
}
document.querySelectorAll(".top-link").forEach((el) => {
el.addEventListener("mouseenter", function () {
el.insertAdjacentHTML("beforeend", '<span class="border-bottom"></span>');
el.childNodes.forEach((e) => {
if (e.className == "border-bottom") {
setTimeout(() => {
e.style.transform = "translateY(0px)";
e.style.opacity = "1";
}, 50);
}
});
});
el.addEventListener("mouseleave", function () {
el.childNodes.forEach((e) => {
if (e.className == "border-bottom") {
setTimeout(() => {
e.style.transform = "translateY(4px)";
}, 25);
setTimeout(() => {
e.style.opacity = "0.4";
}, 50);
setTimeout(() => {
e.style.opacity = "0";
e.remove();
}, 250);
}
});
});
});

Change of opacity using css transition and vanilla JavaScript works only when fading out

This codepen shows my problem: http://codepen.io/PiotrBerebecki/pen/pNvpdG
When the user clicks on the big button the css opacity is reduced to 0. Since I've applied the following rule: transition: opacity 0.5s ease-in-out; the fade out animation is smooth.
I would like to achieve the same smooth transition when the next button fades in.
However for some reason the next button appears suddenly without any transition.
Would you know what causes the issue and how to fix it?
console.clear();
(function() {
// Data for the app
const model = {
buttons: ['tomato', 'blue'],
currentButton: -1
};
// Logic for the app
const controller = {
init: function() {
view.init();
},
getButtonName: function() {
model.currentButton = (model.currentButton + 1) % model.buttons.length;
return model.buttons[model.currentButton];
}
};
// View for the app
const view = {
init: function() {
this.root = document.getElementById('root');
this.showNext();
},
animationDelay: 500,
showNext: function() {
// Get next button name
const buttonName = controller.getButtonName();
// Create button DOM element
const buttonElement = document.createElement('div');
buttonElement.className = 'button';
buttonElement.id = buttonName;
buttonElement.textContent = buttonName;
buttonElement.style.opacity = 0;
// Add event listender for the button
buttonElement.addEventListener('click', event => {
// Reduce opacity
buttonElement.style.opacity = 0;
// Remove the button from DOM
setTimeout(() => {
this.root.removeChild(buttonElement);
}, this.animationDelay + 10);
// Start the function to show next button
setTimeout(() => {
this.showNext();
}, this.animationDelay + 20);
});
// Add button to DOM
this.root.appendChild(buttonElement);
// Show button by increasing opacity
buttonElement.style.opacity = 1;
}
};
// Start the app
controller.init();
}());
#tomato {
background: tomato;
}
#blue {
background: DeepSkyBlue;
}
.button {
transition: opacity 0.5s ease-in-out;
width: 100%;
height: 50vh;
border: solid 3px black;
cursor: pointer;
}
<div id="root"></div>
This should work , Code pen link: http://codepen.io/saa93/pen/gLbvmQ
You would need to add this instead of directly setting opacity to 1
// Show button by increasing opacity
buttonElement.style.opacity = 0;
setTimeout(() => {
buttonElement.style.opacity = 1;
}, this.animationDelay + 20);
Add a class (in the Snippet is .active) add the following:
CSS
.button {
opacity: 0;
transition: opacity 0.5s ease-in-out;
width: 100%;
height: 50vh;
border: solid 3px black;
cursor: pointer;
}
.button.active {
opacity: 1;
transition: opacity 0.5s ease-in-out;
}
JavaScript
...
// Reduce opacity
buttonElement.classList.toggle('active');
buttonElement.style.opacity = 0;
...
// Show button by increasing opacity
buttonElement.classList.toggle('active');
buttonElement.style.opacity = 1;
SNIPPET
console.clear();
(function() {
// Data for the app
const model = {
buttons: ['tomato', 'blue'],
currentButton: -1
};
// Logig for the app
const controller = {
init: function() {
view.init();
},
getButtonName: function() {
model.currentButton = (model.currentButton + 1) % model.buttons.length;
return model.buttons[model.currentButton];
}
};
// View for the app
const view = {
init: function() {
this.root = document.getElementById('root');
this.showNext();
},
animationDelay: 500,
showNext: function() {
// Get next button name
const buttonName = controller.getButtonName();
// Create button DOM element
const buttonElement = document.createElement('div');
buttonElement.className = 'button';
buttonElement.id = buttonName;
buttonElement.textContent = buttonName;
buttonElement.style.opacity = 0;
// Add event listender for the button
buttonElement.addEventListener('click', event => {
// Reduce opacity
buttonElement.classList.toggle('active');
buttonElement.style.opacity = 0;
// Remove the button from DOM
setTimeout(() => {
this.root.removeChild(buttonElement);
}, this.animationDelay + 10);
// Start the function to show next button
setTimeout(() => {
this.showNext();
}, this.animationDelay + 20);
});
// Add button to DOM
this.root.appendChild(buttonElement);
// Show button by increasing opacity
buttonElement.classList.toggle('active');
buttonElement.style.opacity = 1;
}
};
// Start the app
controller.init();
}());
#tomato {
background: tomato;
}
#blue {
background: DeepSkyBlue;
}
.button {
opacity: 0;
transition: opacity 0.5s ease-in-out;
width: 100%;
height: 50vh;
border: solid 3px black;
cursor: pointer;
}
.button.active {
opacity: 1;
transition: opacity 0.5s ease-in-out;
}
<div id="root"></div>
after this.root.appendChild(buttonElement);
you should set opacity to 0 and let the browser time to render before buttonElement.style.opacity = 1;
BTW I think removing and adding the element of not a good way to do this
.button {
width: 100%;
height: 50vh;
border: solid 3px black;
cursor: pointer;
animation-name: example;
animation-duration:3.5s;
}
#keyframes example {
0% {opacity:1}
50% {opacity:0}
100% {opacity:1}
}
What U really want is to use animation like this:JSFIDDLE EXAMPLE
This way the animation does all this timing and opacity back and forth using the css only

Fade out of background page with JQuery dropdown menu

l want to create a dropdwon menu like the one on the Edinburgh Zoo site which fades out the page in the background when it is in action.
Have this so far.. jsfiddle I can't figure out how I would get the background to fade, any ideas?
var stop = true;
var hovered;
var timeout;
$('.nav').hover(
function(){
clearTimeout(timeout);
stop = true;
hovered = this;
timeout = setTimeout(function(){
if($(hovered).hasClass('nav_menu_link_drop')){
$('.content').css('z-index',0);
$(hovered).next('.content').css('z-index',5);
$(hovered).next('.content').slideDown(350);
timeout = setTimeout(function(){
$('.content').not($(hovered).next('.content')).slideUp(350);
},200);
}
else
$('.content').slideUp(350);
},400);
},
function(e){
stop = false;
clearTimeout(timeout);
setTimeout(function(){
if(!stop)
$('.content').slideUp(350);
},500);
}
);
$('.content').hover(
function(){
stop = true;
},
function(){
}
);
$('#nav_menu').hover(
function(){
},
function(){
timeout = setTimeout(function(){
$('.content').slideUp(350);
},200);
}
);
You can achieve that by adding a new element that will act as a back-drop effect.
E.g.
Put this code inside the bottom of the body tag.
<div class="back-drop"></div>
Then assign css properties to it.
.back-drop {
background: rgba(0,0,0,.5);
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
display: none;
}
Also, add z-index: 9999; to #nav_menu in your css.
#nav_menu {
position: absolute;
display: block;
height: 80px;
width: 100%;
background: orange;
z-index: 9999;
}
Add this code to your jquery codes.
$('.nav_menu_link_drop').hover(
function() {
$('.back-drop').css('display', 'block');
},
function() {
$('.back-drop').css('display', 'none');
}
);
Also, add $('.back-drop').css('display', 'block'); and $('.back-drop').css('display', 'none'); to your $('.content').hover();.
$('.content').hover(
function() {
$('.back-drop').css('display', 'block');
stop = true;
},
function() {
$('.back-drop').css('display', 'none');
}
);
Here's the JsFiddle link.
Hope it helps.

How to change opacity with javascript

I am trying to fade an element that is being created dynamically with JavaScript.
Here's a CSS example of what I am trying to do: https://codepen.io/deejay/pen/OJJqZaL
Javascript
...
const fadeOutWithOpacity = () => {
const opacity = totalCount >= 1 && 0.5;
return opacity;
};
const handleOpacity = () => {
setInterval(() => {
fadeOutWithOpacity();
}, 3000);
};
...
style: {
background: "#FA4379",
color: "#fff",
opacity: `${handleOpacity()}`
}
I only want to change the opacity value every 3sec
You can use Javascript to add a class to your element which will cause the opacity to decrease slowly thanks to the CSS transition property.
const spawnBox = () => {
var box = document.createElement("div");
box.className = "box";
box.onclick = (event) => {
box.classList.add("hidden");
};
document.body.appendChild(box);
};
spawnBox();
setInterval(() => {
spawnBox();
}, 1000);
.box {
width: 20px;
height: 20px;
margin: 5px;
background: red;
transition: opacity .5s;
}
.box.hidden {
opacity: 0;
}

Categories