Employing setTimeout for hover interactions in conjunction with a tooltip

I have created an SVG map consisting of hexagons grouped together. My goal is to display a tooltip when the user hovers over a group, but with a 3-second delay. If the user moves away before the delay ends, I want to clear that delay to prevent the tooltip from showing. There is also a delay for the tooltip to disappear in case the user quickly moves to another element after hovering.

My current approach involves using setTimeout for this functionality. While it works most of the time, I have noticed that if I rapidly hover over different elements, the tooltip may reappear unexpectedly.

Below is my code snippet. Feel free to ask if you need further explanation. Thank you!

// Positioning the tooltip below the tooltip wrapper
gsap.set(tip, {
    yPercent: 100
});

// Implementing Tooltip Hover Behavior with Timeouts
let hoverOutTimeout; // Timeout for mouseleave event

// Adding event listener on mouse move to group elements and using timeouts to control hover behavior
for (i = 0; i < lgas.length; i++) {
    lgas[i].onmouseover = function () {
        if (hoverOutTimeout) { 
            clearTimeout(hoverOutTimeout);
            
        } else {
           
        }

       
        hoverTimeout = setTimeout(function () {
          
            gsap.to(tip, {
                yPercent: 0,
                ease: 'bounce.out'
            });
        }, 3000);
    }

    lgas[i].onmouseleave = function () {
        if (hoverTimeout) { 
            clearTimeout(hoverTimeout);
            

            hoverOutTimeout = setTimeout(() => { 
                

                gsap.to(tip, {
                    yPercent: 100,
                    ease: 'back.in'
                });
            }, 2000);

        }
        clearTimeout(hoverTimeout);
    }
}

Answer №1

It seems like there are some missing parts in your post, so I have taken the initiative to provide an example DOM structure and basic functions for displaying/hiding tooltips. In the following code snippet, the background color of each element will change depending on whether the tooltip is visible or not. The main idea here is to maintain a certain state for each element (referred to as its timerId).

const SHOW_DELAY = 1500;
const HIDE_DELAY = 1200;

function showTooltip(element) {
  element.classList.add('hovered');
}

function hideTooltip(element) {
  element.classList.remove('hovered');
}

function setTooltips(elements) {
  function getMouseEventHandler(elementHandler, delay) {
    return ({target: element}) => {
      let timerId = timerIdMap.get(element) ?? 0;
      clearTimeout(timerId);
      timerId = setTimeout(() => elementHandler(element), delay);
      timerIdMap.set(element, timerId);
    };
  }

  const handleMouseEnter = getMouseEventHandler(showTooltip, SHOW_DELAY);
  const handleMouseLeave = getMouseEventHandler(hideTooltip, HIDE_DELAY);

  const timerIdMap = new WeakMap();

  for (const element of elements) {
    timerIdMap.set(element, 0);
    element.addEventListener('mouseenter', handleMouseEnter);
    element.addEventListener('mouseleave', handleMouseLeave);
  }
}

const elements = [...document.querySelectorAll('div.item')];
setTooltips(elements);
.container {
  display: flex;
  flex-wrap: wrap;
  width: 14rem;
}

.item {
  border: 1px solid;
  height: 3rem;
  width: 3rem;
}

.hovered {
  background-color: orangered;
}
<div class="container">
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
</div>

Answer №2

My method involved binding events to a unique ID and checking it using setTimeout. The ID is generated at the time of event binding, preventing hovers from stacking.

When hovering over an element, the event is associated with the current generated ID. On mouseleave, the events are unbinded and rebound with a new ID. I created a snippet to test this approach.

let bindCurID;

let hoverBinder = function(){
  bindCurID = new Date() * Math.random();
  
  $('div').off('mouseenter').on('mouseenter', function(){
    let sMsg = $(this).find('h2').text();
    let bindID = bindCurID;
    
    setTimeout(function(){
      if(bindID != bindCurID)
        return
      $('body').append('<span class="hov">' + sMsg + '</span>');
    }, 2000)
    
  });
  
  $('div').off('mouseleave').on('mouseleave', function(){
    $('.hov').remove();
    hoverBinder()
  });
}

hoverBinder()
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="div1" style='background-color:lightblue'>
<h2>Hello</h2>
</div><br /><br />
<div id="div2" style='background-color:lightblue'>
<h2>World</h2>
</div>

While some may have quicker ways to achieve this, my solution may not be as wizardly but gets the job done effectively.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for displaying an uploaded image using the Valums file uploader

I recently implemented the Andrew Valums File Uploader on my website and it's functioning as expected. I am now looking to modify it so that instead of displaying just the uploaded filename and size, it will show the uploaded picture directly in the b ...

Obtaining the IP address of the client's request

In an effort to prevent others from wasting time in the future, I am sharing this post even though it's not really a question anymore. Objective: Obtain the client IP address and set specific values based on certain octets in the IP address. While w ...

Modify the item in an array using values from a different item in the same array

Within my code, I am juggling two arrays. The first contains multiple objects, while the second stores serialized form data mapped to JSON. Both arrays share identical keys. My goal is to dynamically update the values of an object in the original array ba ...

Is there a risk of encountering issues when preloading (or caching) an entire website using Ajax?

I am in the process of developing a portfolio website for an architect that includes numerous images on various pages. The navigation is implemented using history.js (AJAX). To improve loading times and enhance user experience, I have devised a script that ...

What's the best way to ensure that the theme state remains persistent when navigating, refreshing, or revisiting a page in the browser?

Is there a way to ensure that my light/dark theme settings remain persistent when users reload the page, navigate to a new page, or use the browser's back button? The current behavior is unreliable and changes unexpectedly. This is the index.js file ...

Attempting to select an image with the intention of triggering a modal to appear through an ajax

Hi there, I recently started coding and I'm facing an issue that I can't seem to solve. I want to set it up so that when you click on an image, a modal opens corresponding to the img tag, and then the modal click event triggers a method. The prob ...

"The combination of Node.js, Express, and Angular is causing a continuous loop in the controller when a route is

Currently, I am utilizing node js alongside Express. Angular js files are being loaded through index.html. The code for app.js is as follows: app.use(bodyParser.json()); // for parsing application/json app.use(bodyParser.urlencoded({ extended: true })); ...

Issues with CSS file loading in Django

My program has a CSS file that I defined, but for some reason it's not working. When I checked with firebug, the status is 200 OK, but no changes are occurring. I'm unsure if there is a syntax issue with my CSS file. Can you please provide your i ...

"Are you greeted with a new tab pop-up on your initial visit

I am trying to display a helpful message in a new tab the first time someone visits my website, but I am encountering issues. Below is the code snippet I am using: <html> <?php $cookie_name = "visited"; $cookie_value = "1"; ...

Executing multiple functions with onPress in React Native

When I press onPress using TouchableOpacity, I am attempting to invoke multiple functions. Here's an example: functionOne(){ // perform an action } functionTwo(){ // execute something } <TouchableHighlight onPress{() => this.functionOne()}/& ...

What is the process for displaying a floating menu when you reach a specific point while scrolling?

I'm looking to implement a feature where four menu tabs will slide in from left to right when the user scrolls past a specified point on the page, such as 1000px. I want them to smoothly appear just like this example, but positioned on the left side o ...

What steps should I take to create a collapsible Bootstrap navbar?

I'm attempting to recreate the scrolling functionality seen here: It seems like they might be using a customized Bootstrap Navbar, so I've taken one from here: and tailored it to my needs. How can I achieve the effect where the navigation bar ...

Ways to display Div contents based on selected options in an Angular 2/4 list

"Struggling with dynamically displaying div contents" Situation:- I have a list of 3 items: *Menu1 *Menu2 *Menu3 and I have separate div contents for each of these menu items. Requirement :- By default, Menu1 should be displayed. When Menu2 is clicked, ...

Challenger arises in the realm of Chakra UI styling

Recently, I've encountered an issue with displaying a card using chakra UI and next js. The CSS of chakra UI seems to be messed up, causing all my components to display incorrectly. It was working perfectly fine until yesterday. I tried deleting the . ...

What is causing the col-auto with the red border to exceed its available height?

For this code, I've utilized version 5 of Bootstrap. In full screen width, the col-auto with the red border seems to be taking up more space than its content. The yellow border marks the available content space inside. I'm curious about what migh ...

Creating a dynamic `v-model` for computed properties that is dependent on the route parameter

I am creating a versatile component that can update different vuex properties based on the route parameter passed. Below is a simplified version of the code: <template> <div> <input v-model="this[$route.params.name]"/> </div&g ...

How to identify an element based on the text content of the element that follows it using XPath

I am working with this specific piece of HTML code <div class="a-expander-content a-spacing-base a-expander-inline-content a-expander-inner a-expander-content-expanded" style="" aria-expanded="true"> <form id="pp-yT-23" class="pmts-add-cr ...

"Enhancing user experience with jQuery hover effects on table

This is an example of the HTML structure: <tr class="row-1 row-first"> <td class="col-1 col-first"> <div class="views-field views-field-field-logo-image"></div> <div class="views-field views-field-field-logo-title"> ...

Users who are utilizing Internet Explorer are unable to complete the search input field on my website

Hello, I am in the process of creating a website that frequently uses lengthy search terms. To optimize user experience, I have implemented a dropdown search bar inspired by the bootsnipp example below. While I have applied some custom styling to the desig ...

Unsynchronized AJAX POST requests fail to function effectively

I am encountering an issue with an AJAX call that I am using to log in a user. Here is the code: function loginUser() { var xmlhttp; if(window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari xmlhttp = new XMLHttpRequest() ...