Show / hide elements on mouse move - javascript

I'm building a site where I want the certain sections to be hidden until the mouse is moved. They then remain visible whilst the mouse is moving, however, if it remains still for a couple of seconds they hide again.
I'm using jQuery on the site, in my ready state I have:
var hide = setTimeout(function() {
hideNav();
}, 2000);
$('body').mousemove(function() {
clearTimeout(hide);
var hide = setTimeout(function() {
hideNav();
}, 2000);
showNav();
});
And the functions that show/hide content
function hideNav() {
$('#primary').fadeOut(1000);
var lightbox = $('#lightbox');
if (lightbox.length) {
lightbox.fadeOut(1000);
}
}
function showNav() {
$('#primary').fadeIn(1000);
var lightbox = $('#lightbox');
if (lightbox.length) {
lightbox.fadeIn(1000);
}
}
This sort of works, except the timeout for hiding the elements ends up fighting with the function to show it when the mouse moves resulting in a lot of flickering.
EDIT: The mouse movement needs to be for anywhere on the page, not just when hovering over the element that is to be shown/hidden.
Any help would be appreciated.
Thanks

Try using $.stop http://api.jquery.com/stop/
If its in the 1 second of fading out when you move your mouse, it should stop the animation of fading out and fade back in.
function hideNav() {
$('#primary').stop().fadeOut(1000);
var lightbox = $('#lightbox');
if (lightbox.length) {
lightbox.fadeOut(1000);
}
}
function showNav() {
$('#primary').stop().fadeIn(1000);
var lightbox = $('#lightbox');
if (lightbox.length) {
lightbox.fadeIn(1000);
}
}
Also, I would remove var from the var hide = ... in your mousemove function. If hide is a global variable, just reuse it inside mousemove (doesn't need to be redeclared).

Related

Bootstrap 5.2, prevent closing tooltip if cursor is back on triggering element

TLDR: moving the cursor from tooltip back to triggering element closes, shows and closes the tooltip (flickers).
I need to make the tooltips open on hover and make their content clickable. I have found a working example here on SO.
As you hover over the element it shows you a tooltip which can be interacted with, once you move the cursor away from the tooltip it closes.
There is a problem though.
If you leave the tooltip and move the cursor back on the element which triggered the tooltip, the tooltip pops back up, but dissapears after a moment ("flickering"). You need to move the cursor away from the element and back on the element for the tooltip to show again.
What I am trying to do, is check if the cursor is back on the triggering element and if that is the case not run the closing function (tooltip.hide()).
I have tried to do this by imitating the existing process from the example found on SO. That is, check if the tooltip has lost :hover, setTimout (300ms) and check if cursor is now positioned on the triggering element or back on the tooltip.
Here is a jsFiddle example.
This is the code. The problematic code is between the two looong comment lines.
Note: Moving the cursor away from the triggering element and back on the triggering element also triggers the flickering.
//https://stackoverflow.com/questions/67993080/bootstrap-5-make-tooltip-hoverable-and-link-clickable
var tooltipTriggerList = [].slice.call(document.querySelectorAll('button'))
for (let tt of tooltipTriggerList){
tt.setAttribute("data-bs-placement","top")
}
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
const tooltip = new bootstrap.Tooltip(tooltipTriggerEl, {
trigger: "manual",
'customClass': 'custom-tooltip'
})
let tooltipElTimeout;
let currentToolTip;
let currentTooltipTimeout;
tooltipTriggerEl.addEventListener("mouseenter", function () {
let toolTipID;
// Clear Set Timeout
clearTimeout(currentTooltipTimeout);
// Show Tooltip
tooltip.show();
// Assign current tooltip ID to toolTipID variable
toolTipID = tooltipTriggerEl.getAttribute("aria-describedby");
// Assign current tooltip to currentToolTip variable
currentToolTip = document.querySelector(`#${toolTipID}`);
/*******************************************************************/
// Hide tooltip on tooltip mouse leave
currentToolTip.addEventListener("mouseleave", function () {
currentTooltipTimeout = setTimeout(()=>{
console.log("!currentToolTip.matches(':hover')");
console.log(!currentToolTip.matches(":hover"));
if(!tooltipTriggerEl.matches(":hover")){
console.log("!tooltipTriggerEl.matches(':hover')");
console.log(!tooltipTriggerEl.matches(":hover"));
if (!currentToolTip.matches(":hover")) {
tooltip.hide();
}
}
}, 300)
});
/***********************************************************************/
});
tooltipTriggerEl.addEventListener("mouseleave", function () {
// SetTimeout before tooltip disappears
tooltipTimeout = setTimeout(function () {
// Hide tooltip if not hovered.
if (!currentToolTip.matches(":hover")) {
tooltip.hide();
}
}, 100);
});
return tooltip;
})
Thank you
Edit:
Amine Ramouls answer is correct. isHidden also needs to bet set to false on the 2cnd eventListener, otherwise the tooltips no longer work (problem with aria-describedby).
in your code you have an event listener wich add an event listner and that's a big mistake because it add an infinit number of eveneent listner to your element.
so you juste have to organize your code like this :
//https://stackoverflow.com/questions/67993080/bootstrap-5-make-tooltip-hoverable-and-link-clickable
var tooltipTriggerList = [].slice.call(document.querySelectorAll('button'))
for (let tt of tooltipTriggerList){
tt.setAttribute("data-bs-placement","top")
}
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
const tooltip = new bootstrap.Tooltip(tooltipTriggerEl, {
trigger: "manual",
'customClass': 'custom-tooltip'
})
let isHidden = true;
let currentTooltipTimeout;
tooltipTriggerEl.addEventListener("mouseenter", function () {
let toolTipID;
// Clear Set Timeout
clearTimeout(tooltipElTimeout);
clearTimeout(currentTooltipTimeout);
if (isHidden)
{
tooltip.show();
isHidden=false;
}
});
// Hide tooltip on tooltip mouse leave
tooltipTriggerEl.addEventListener("mouseleave", function () {
console.log("!currentToolTip.matches(':hover')");
if(!tooltipTriggerEl.matches(":hover")){
currentTooltipTimeout=setTimeout(()=>{
if (!isHidden && !tooltipTriggerEl.matches(":hover")){
tooltip.hide();
isHidden=true;
}
console.log("!tooltipTriggerEl.matches(':hover')");
console.log(!tooltipTriggerEl.matches(":hover"));
}, 3000)
}
});
return tooltip;
})
now as you can see i juste added the isHidden var to check if the popup info is hidden or not, you can do that with the element if you can get it by a query selector request. that's it. enjoy your life.
Edit: i forget to tell you that i have put 3 seconde before checking the if the popup is hidden or not.

scroll based on dragenter event?

how to scroll up step by step and scroll down step by step using jquery. (jquery ui not appreciated).
i have a 2 divs
<div class="upper" style="height:35px;background-color:red;right:0;left:0;top:0;position:fixed;width:100%;z-index:2000"></div>
<div class="lower" style="height:35px;background-color:red;right:0;left:0;bottom:0;position:fixed;width:100%;z-index:2000"></div>
if i drag an image and hover on first div (upper),it should scroll up step by stell.
if i drag and hover on 2nd div it should scroll down manually.
in both cases scrolling should stop if i came out of the div.
i am trying to implement it using events
var isleftDragPosition=true;;
$('.upper').on('dragleave', function(){
console.log("hidragleave");
var isleftDragPosition=true;
});
$('.lower').on('dragleave', function(){
console.log("hi2dragleave")
var isleftDragPosition=true;
});
$('.upper').on('dragenter', function(){
var isleftDragPosition=false;
while(!isleftDragPosition){
var x=document.documentElement.scrollTop;
console.log("to upper position",x);
window.scrollTo(0, x-2);
}
});
$('.lower').on('dragenter', function(){
console.log("hi2dragenter",document.documentElement.scrollTop)
window.scrollTo(1000, 1000);
});
i am trying it with the top div to scroll up, but the code crashes my tab(hang).
how i can do that?
You are redefining your flag in each handler, so the change is not saved. Also, while loop might be to fast for your particular case. I modified code like this:
$('.upper').on('dragenter', function(){
isleftDragPosition=false;
clearInterval(interval);
var f = function() {
if(!isleftDragPosition){
var x=document.documentElement.scrollTop;
console.log("to upper position",x);
window.scrollTo(0, x-2);
} else {
clearInterval(interval);
}
}
setInterval(f, 1000);
});
Hope this helps.

Detecting the end of a overflow-x:scroll element and add a class before animation

As the title suggests I want to detect the start and end of a scrollable element built using overflow.
The following code works:
var scrollAmount = 150;
var scrollBox = $('.js-compare_scroll');
var arrowLeft = $('.js-compare_scroll_left');
var arrowRight = $('.js-compare_scroll_right');
var inactive = 'm-inactive';
$(arrowLeft).on('click', function () {
$(this).parent().find(scrollBox).stop().animate({
scrollLeft: '-='+scrollAmount
}, function() {
arrowRight.removeClass(inactive);
if(scrollBox.scrollLeft() === 0) {
arrowLeft.addClass(inactive);
}
});
});
$(arrowRight).on('click', function () {
$(this).parent().find(scrollBox).stop().animate({
scrollLeft: '+='+scrollAmount
}, function() {
arrowLeft.removeClass(inactive);
if(scrollBox.scrollLeft() + scrollBox.innerWidth() >= scrollBox[0].scrollWidth) {
arrowRight.addClass(inactive);
}
});
});
However the class to style the inactive colour of the arrows only appears once the animation completes. I need to add the class before the animation completes because it has a delay. I believe by default it is 400.
Is there anyway to detect this and apply the arrow classes where needed?
Thanks.
Came back from a break and realised I should take the checking if its at the end off the click event and onto a scroll event. This works a lot better now.

How to show divs when the mouse moves anywhere on screen, not just the element itself?

I managed to hide and show my classes when the user moves his mouse over the specific element. But what I would actually like is that these show when the user moves his mouse anywhere on the screen, not just the selected div's.
This is my current code:
$(window).on('mousemove', function () {
$('.barhide').addClass('show');
try {
clearTimeout(timer);
} catch (e) {}
timer = setTimeout(function () {
$('.barhide').removeClass('show');
}, 1000);
});
And my css:
.barhide {
background: #333;
color: #fff;
display: block;
opacity: 0;
transition: all 1.5s ease;
}
.barhide.show {
opacity: 1;
display: none;
}
So what I would like is that after 3 seconds, the classes with .barhide get hidden and if the user moves his mouse anywhere in screen, they show up again, instead of just when they move over the element.
Also I was wondering if it's not a lot easier to do these things with React?
I have restructured the code a bit and added some comments explaining what's happening and when. Also, lose the try since attempting to clear a timer will never throw an exception.
Keep in mind that mouseover type events are an issue on mobile devices. These two articles may help in that regard:
JQuery's Virtual Mouse Events
Simulated Mouse Events using JQuery
$(function(){
// When page loads, wait 3 seconds and hide all elements with .barhide class:
setTimeout(toggle, 3000);
});
var timer = null;
// General function for adding/removing the "hide" class.
// This is used when the page first loads and each time
// the mouse moves on the page. We're not calling toggle()
// here because a flicker effect can happen which would leave
// the elements showing instead of being hidden.
function toggle(){
$('.barhide').toggleClass('hide');
}
$(window).on('mousemove', function(){
// When anywhere on page is moused over bring back .barhide
// elements for 3 seconds. Removing "hide" simply restores
// the original CSS & layout
$('.barhide').removeClass('hide');
// Kill any previous timers
clearTimeout(timer);
// Wait 3 seconds and hide again
timer = setTimeout(toggle, 3000)
});
.barhide { background-color:blue; }
.hide { display:none; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="barhide">ONE</div>
<div class="show">TWO</div>
You just count the nr of timers running and when the last finishes you hide the bar.
var count = 0;
$(window).mousemove(function( event ) {
$('.barhide').show();
count += 1;
setTimeout(function() {
if (count == 1) {
$('.barhide').hide();
}
count -= 1;
}, 3000);
});

Simple but tricky Show/Hide Toggle On/Off Combinations driving me bonkers

Have a few divs that need to show/hide and the buttons within need to know when it's on and when it's off. Somehow they need to "communicate with another" to know when to be hidden or visible. Oh yeah, I'd like to keep the smooth fadein/fadeout effect on all elements.
Thanks!!
My fiddle is here:
http://jsfiddle.net/Pe9jn/
Here's the code I've got that mostly works, but it's a bit quirky:
//hide maximize link on page load
$('.maximize_menu').css('display','none');
//settings
var opacity = 1, toOpacity = 0, duration = 350;
//set opacity ASAP and events
$('.toggle_all, .toggle_all2').css('opacity',opacity).toggle(function() {
$('#content, .maximize_menu, #menu, .minimize_menu').fadeTo(duration,toOpacity);
}, function() {
$('#content, .maximize_menu, #menu, .minimize_menu').fadeTo(duration,opacity);
}
);
// this minimizes the menu and should make the mazimize_menu link visible when toggled off
$('.minimize_menu').css('opacity',opacity).toggle(function() {
$('#menu, .minimize_menu,.maximize_menu').fadeTo(duration,toOpacity);
}, function() {
$('.maximize_menu, #menu, .minimize_menu, .maximize_menu').fadeTo(duration,opacity);
$('.maximize_menu').show(duration,toOpacity);
$('.maximize_menu').css('display','block');
}
);
// this maximizes the menu and should disappear once the menu is visible
$('.maximize_menu').css('opacity',opacity).toggle(function() {
$('#menu, .minimize_menu,').fadeTo(duration,toOpacity);
}, function() {
$('#menu, .minimize_menu, .maximize_menu').fadeTo(duration,opacity);
}
);
I think that you should rethink all the logic, because you are not actually hiding the elements, you are just setting the opacity to 0. What you should really use is fadeOut() and fadeIn()

Categories

Resources