Tengo un mapa SVG formado por hexágonos que se dividen en grupos. Cuando el usuario se desplaza sobre un grupo, me gustaría que apareciera una información sobre herramientas. La cuestión es que quiero que haya un retraso de 3 segundos en esta información sobre herramientas. Entonces, si el usuario decide alejarse durante ese retraso, me gustaría borrar ese retraso para evitar que aparezca la información sobre herramientas, ya que ya no se desplazan sobre él. También hay un retraso en el momento en que desaparece la información sobre herramientas en caso de que pase el cursor sobre otro elemento después de alejarse rápidamente del anterior.
Estoy usando setTimeout para esto. Lo que he hecho aquí funciona el 50 % del tiempo, pero descubro que si paso el cursor por encima y dejo que se muestre la información sobre herramientas, y luego paso el cursor rápidamente sobre un montón de otros elementos diferentes antes de pasar el cursor, la información sobre herramientas desaparecerá pero luego rápidamente. reaparecer de nuevo.
Aquí está mi código, estoy feliz de explicar algo más si es necesario. ¡Salud!
// Setting the tooltip to appear below the tooltip wrapper gsap.set(tip, { yPercent: 100 }); // Tooltip Hovering Functionality with Timeouts let hoverOutTimeout; // Timeout for hovering out // GO through grouped elements with an event listener on mouse move, and use timeouts to delay hover for (i = 0; i < lgas.length; i++) { lgas[i].onmouseover = function () { if (hoverOutTimeout) { // Check to see if the delay for the mouseleave function is running clearTimeout(hoverOutTimeout); //console.log("Hover back in"); } else { //console.log("Hovering in"); } // Set 3s delay to display tooltip hoverTimeout = setTimeout(function () { //console.log("Hovered in"); gsap.to(tip, { yPercent: 0, ease: 'bounce.out' }); }, 3000); } lgas[i].onmouseleave = function () { if (hoverTimeout) { // If delay to show tooltip is running, clear it clearTimeout(hoverTimeout); //console.log("Hovering back out") hoverOutTimeout = setTimeout(() => { // Start new delay to hide tooltip //console.log("Hovered out"); gsap.to(tip, { yPercent: 100, ease: 'back.in' }); }, 2000); } clearTimeout(hoverTimeout); } }Pude lograr esto vinculando eventos a una identificación asociada. La idea es que setTimeout verificará si su ID es la ID generada actualmente. El ID se genera en el momento del enlace del evento.
Al entrar con el mouse, el evento se asocia al ID generado actualmente. En mouseleave, los eventos se desvinculan y luego se vuelven a vincular con una nueva ID generada. Este enfoque es lo que evita que los hovers se acumulen.
Espero que tenga sentido. Desarrollé un fragmento para experimentar.
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>Estoy seguro de que hay otros que pueden hacer todo esto en una sola línea con algún tipo de truco mágico, pero esto hará el trabajo.
Falta parte de su código en su publicación, por lo que me tomé la libertad de proporcionar una estructura DOM de ejemplo y funciones genéricas para mostrar/ocultar la información sobre herramientas. En el siguiente código, el color de fondo de cada elemento cambiará en función de si la información sobre herramientas está visible o no. El concepto clave es que necesita almacenar algún estado para cada elemento (su 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>