March 10, 201016 yr Hello, I'm having a real nightmare making my menu images animate out and back again, triggered from a mouseover/mouseout event. I finally got it working, but I'm getting a horrible 'flickering' effect when I mousover/mouseout quickly (I'm assuming this is because the functions are in conflict). I need to find a way for the menuSlideIn() function to be interrupted and replaced by the menuSlideOut() function on mouseout so the transition is smooth regardless of how fast you run the mouse over the list items/anchors. I'm very much a beginner at this (as you'll see) and I'd be extremely grateful if anyone can offer me some help regarding a solution to this...having sat here looking at this for a week and pulling up nothing but jQuery tutorials on Google, my brain is now officially jelly! Here's my Javascript: window.onload = function() { menuAnchor1.addEventListener('mouseover', animateIn1, false); menuAnchor2.addEventListener('mouseover', animateIn2, false); menuAnchor3.addEventListener('mouseover', animateIn3, false); menuAnchor4.addEventListener('mouseover', animateIn4, false); menuAnchor5.addEventListener('mouseover', animateIn5, false); menuAnchor6.addEventListener('mouseover', animateIn6, false); menuAnchor7.addEventListener('mouseover', animateIn7, false); function animateIn1() { menuHighlight = document.getElementById('menuHighlight1'); menuSlideIn(menuHighlight, -340, 0, 0); } function animateIn2() { menuHighlight = document.getElementById('menuHighlight2'); menuSlideIn(menuHighlight, -340, 0, 0); } function animateIn3() { menuHighlight = document.getElementById('menuHighlight3'); menuSlideIn(menuHighlight, -340, 0, 0); } function animateIn4() { menuHighlight = document.getElementById('menuHighlight4'); menuSlideIn(menuHighlight, -340, 0, 0); } function animateIn5() { menuHighlight = document.getElementById('menuHighlight5'); menuSlideIn(menuHighlight, -340, 0, 0); } function animateIn6() { menuHighlight = document.getElementById('menuHighlight6'); menuSlideIn(menuHighlight, -340, 0, 0); } function animateIn7() { menuHighlight = document.getElementById('menuHighlight7'); menuSlideIn(menuHighlight, -340, 0, 0); } menuAnchor1.addEventListener('mouseout', animateOut1, false); menuAnchor2.addEventListener('mouseout', animateOut2, false); menuAnchor3.addEventListener('mouseout', animateOut3, false); menuAnchor4.addEventListener('mouseout', animateOut4, false); menuAnchor5.addEventListener('mouseout', animateOut5, false); menuAnchor6.addEventListener('mouseout', animateOut6, false); menuAnchor7.addEventListener('mouseout', animateOut7, false); function animateOut1() { if(menuHighlight = document.getElementById('menuHighlight1')) { menuSlideOut(menuHighlight, 0, -340, 0); } } function animateOut2() { if(menuHighlight = document.getElementById('menuHighlight2')) { menuSlideOut(menuHighlight, 0, -340, 0); } } function animateOut3() { if(menuHighlight = document.getElementById('menuHighlight3')) { menuSlideOut(menuHighlight, 0, -340, 0); } } function animateOut4() { if(menuHighlight = document.getElementById('menuHighlight4')) { menuSlideOut(menuHighlight, 0, -340, 0); } } function animateOut5() { if(menuHighlight = document.getElementById('menuHighlight5')) { menuSlideOut(menuHighlight, 0, -340, 0); } } function animateOut6() { if(menuHighlight = document.getElementById('menuHighlight6')) { menuSlideOut(menuHighlight, 0, -340, 0); } } function animateOut7() { if(menuHighlight = document.getElementById('menuHighlight7')) { menuSlideOut(menuHighlight, 0, -340, 0); } } } /* ******************** SLIDE MENU HIGHLIGHT ******************** */ function menuSlideIn(menuHighlight, currentBgPositionX, targetBgPositionX, currentBgPositionY) { if(currentBgPositionX < targetBgPositionX) { currentBgPositionX += Math.ceil((targetBgPositionX - currentBgPositionX) / 20); menuHighlight.style.backgroundPosition = currentBgPositionX + 'px' + ' ' + currentBgPositionY; setTimeout(function() {menuSlideIn(menuHighlight, currentBgPositionX, targetBgPositionX, currentBgPositionY);}, 1); } } function menuSlideOut(menuHighlight, currentBgPositionX, targetBgPositionX, currentBgPositionY) { if(targetBgPositionX < currentBgPositionX) { currentBgPositionX -= Math.ceil((currentBgPositionX - targetBgPositionX) / 20); menuHighlight.style.backgroundPosition = currentBgPositionX + 'px' + ' ' + currentBgPositionY; setTimeout(function() {menuSlideOut(menuHighlight, currentBgPositionX, targetBgPositionX, currentBgPositionY);}, 1); } } Here's my HTML which the above code relates to: <ul id="bullet" class="bullet"> <li> <div id="menuHighlight1"><!-- --></div> <div id="menuItem"> <a href="" id="menuAnchor1">Some Text</a> <p class="subList">Some Text</p> </div> </li> <li> <div id="menuHighlight2"><!-- --></div> <div id="menuItem"> <a href="" id="menuAnchor2">Some Text</a> <p class="subList">Some Text</p> </div> </li> <li> <div id="menuHighlight3"><!-- --></div> <div id="menuItem"> <a href="" id="menuAnchor3">Some Text</a> <p class="subList">Some Text</p> </div> </li> <li> <div id="menuHighlight4"><!-- --></div> <div id="menuItem"> <a href="" id="menuAnchor4">Some Text</a> <p class="subList">Some Text</p> </div> </li> <li> <div id="menuHighlight5"><!-- --></div> <div id="menuItem"> <a href="" id="menuAnchor5">Some Text</a> <p class="subList">Some Text</p> </div> </li> <li> <div id="menuHighlight6"><!-- --></div> <div id="menuItem"> <a href="" id="menuAnchor6">Some Text</a> <p class="subList">Some Text</p> </div> </li> <li> <div id="menuHighlight7"><!-- --></div> <div id="menuItem"> <a href="" id="menuAnchor7">Some Text</a> <p class="subList">Some Text</p> </div> </li> </ul> Thank you in advance...
March 10, 201016 yr Author Wow at all that JavaScript you've written. I've have a google of JQuery drop down menus personally. Hi rallport, I agree, jQuery would definitely be a LOT quicker. I'm just trying to learn 'under-the-hood' Javascript. Nothing wrong with the libraries in my opinion. Thanks for your reply
March 10, 201016 yr At the moment, you're not clearing your setTimeout functions via clearTimeout. Basically, when one animation is in progress, it will interfere with another one unless you use clearTimeout to get rid first. So the event (mouseover/mouseout) needs to look for a reference to an existing setTimeout call. Sorry for not explaining very well I'm off to bed now (v.tired) but have a google for clearTimeout. If you haven't got it sorted tomorrow, I'll post an example for you.
March 11, 201016 yr Author At the moment, you're not clearing your setTimeout functions via clearTimeout. Basically, when one animation is in progress, it will interfere with another one unless you use clearTimeout to get rid first. So the event (mouseover/mouseout) needs to look for a reference to an existing setTimeout call. Sorry for not explaining very well I'm off to bed now (v.tired) but have a google for clearTimeout. If you haven't got it sorted tomorrow, I'll post an example for you. Hi ElanMan, Thank you for your help. As you suggested I looked up the clearTimeout function, and it does indeed seem to be along the lines of what I need. I followed the online documentation to the letter but sadly, that alone hasn't worked. I feel like I need some kind of conditional statement whereby the menuSlideIn() will run UNTIL you mouseout, in which case the menuSlideOut() function will stop it (clearTimeOut perhaps?), grab the currentBgPositionX value from menuSlideIn() and run backwards from there. I just can't wrap my head around it. I'm struggling to write it in a way that I can make menuSlideOut() pick up the returned value from menuSlideIn()....My apologies for the long and confusing explanation! Again, thank you for your help and patience
March 11, 201016 yr Ok, here's some sample code to get you started. It might look a bit daunting at first but most of it is comments to try and explain what it is doing. html: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <title>Moving Background</title> <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> <link rel="stylesheet" media="screen" type="text/css" href="style.css" /> <script type="text/javascript" src="moveBackground.js"></script> </head> <body> <ul id="mylist"> <li>One</li> <li>Two</li> <li>Three</li> <li>Four</li> </ul> </body> </html> css: ul { list-style-type:none; } li { width: 360px; height: 100px; background:#beb397 url('rect2816.png') no-repeat; margin:5px 0; } js: the important stuff!! var moveBackGround = { //this is the function that we call on pageload init: function(){ //loop through the links and add events to each var myList = document.getElementById('mylist'); var links = myList.getElementsByTagName("li"); for (var i=0; i < links.length; i++) { //for each link, set the background position so no image shows links[i].style.backgroundPosition = '-360px 0px'; //for each link, add events for mouseover and mouseout //this specifies a listener for each event links[i].addEventListener("mouseover",moveBackGround.overListener,false); links[i].addEventListener("mouseout",moveBackGround.outListener,false); } }, //animate on mouseover //increments the background position on mouseover slideIn: function(object, targBg){ //this is the important bit //here we clear any setTimeout function referenced by object.moveBgOut (set in slideOut function) clearTimeout(object.moveBgOut); currentBgPosition = parseInt(object.style.backgroundPosition); if (currentBgPosition == targBg) { clearTimeout(object.moveBgOver); } if (currentBgPosition < targBg) { //the amount of pixels moved each iteration //increase or decrease according to taste currentBgPosition += 20; object.style.backgroundPosition = currentBgPosition + "px 0px"; } //another important part //create a reference to this setTimeout //this lets us cancel it in the slideOut function //alter '50' at the end for a different speed object.moveBgOver = setTimeout(function(){moveBackGround.slideIn(object,targBg)},50); }, //animate on mouseout //decrements the background position on mouseout slideOut: function(object, targBg){ //this is the important bit //here we clear any setTimeout function referenced by object.moveBgOver (set in slideIn function) clearTimeout(object.moveBgOver); currentBgPosition = parseInt(object.style.backgroundPosition); if (currentBgPosition == targBg) { clearTimeout(object.moveBgOut); } if (currentBgPosition > targBg) { //the amount of pixels moved each iteration currentBgPosition -= 20; object.style.backgroundPosition = currentBgPosition + "px 0px"; } //another important part //create a reference to this setTimeout //this lets us cancel it in the slideIn function //alter '50' at the end for a different speed object.moveBgOut = setTimeout(function(){moveBackGround.slideOut(object,targBg)},50); }, //these two functions are called by addEventListener in the init() function //called on mouseover overListener: function(event){ var link = this; this._timer = setTimeout(function() { moveBackGround.slideIn(link, 0);},200); }, //called on mouseout outListener: function(event){ var link = this; this._timer = setTimeout(function() { moveBackGround.slideOut(link, -360);},200); } }; //finally, call moveBackground onload window.onload = function() { moveBackGround.init(); } I've put an example up for you here. Read the comments in the code. Hopefully, they will make it easier for you to grasp what is going on regarding clearTimeout. Also, at the moment, this won't work in IE. You'll need to account for attachEvent as well (IE is a pain in the arse regarding js) so there is a bit more work for you yet Finally, if you're looking to buy a book on js, 'Simply Javascript' is a great read and covers this type of stuff in much better detail. Good luck ps this forum always shags my code indentation. Sorry if it looks a mess.
March 12, 201016 yr Author Wow! I can't tell you how much of a help this has been...thank you! Having only just read your example, I've yet to try it out but It's already made a couple of things crystal clear that I was at a dead end with. For example, adding an event listener to the links as you have, instead of my rather long way of doing it. Also, the previously discussed setting and canceling of Timeouts. I hope to spend as much of today getting this working as I can, so I will let you know how it goes. Thanks again ElanMan for taking the time to help
Create an account or sign in to comment