I'm trying to write a menu that expands the subcategories on hover - so only one subcategory can be expanded at a time. It will looks something like this (completely expanded):
X
Y
Y.1
Y.2
Z
Z.1
Z.2
My issue is this:
The animation works correctly, except if I hover over Y and then try to hover over Z, all of X closes. I know why: there needs to be a delay because Z starts moving up, so you're no longer hovering on Z and it starts closing.
Below is the code:
$( document ).ready(function() {
$("#m2l2").hoverIntent(
function() {
clearTimeout(z_timer);
$("#m2l2").toggleClass("child childopen");
$("#u12").slideToggle("slow", "linear");
},
function() {
z_timer = setTimeout(function() {
$("#u12").slideToggle("slow", "linear", function () {
$("#m2l2").toggleClass("childopen child");
});
}, 10000);
});
});
Is there any way to avoid a delay or to make a delay that only activates in certain case?
Here's the link: http://jsfiddle.net/stamblerre/XYp48/12/
Thank you!!!
Here's how to add timeout for hoverIntent by using the object from hoverIntent jQuery Plugin
$('.selector').hoverIntent({
over: function(){},
out: function(){},
timeout: 1000 // in miliseconds
});
so here's what it will look like : JSFIDDLE, even though sometimes it takes to long before the out function called, so define it with whatever best usage for your case
It is not the js code issue but css issue, you have a vertical menu where 3rd level also opens vertically.
Its tricky but try to visualize
When your mouse enters option Y its 3rd level menu shows ,now when you take mouse on option Z the mouseout event for Y fires and it hides its 3rd level due to which position of option Z shifts and now your mouse pointer is outside the main menu #id="m2l0" and its mouseout event fires and hides both options Y and Z.
Related
So I am using a toggle button in which a menu is toggled on the side. It slides in and out from the left hand side. I am also using bootstrap so it takes up 2 out of 12 sections of a row, with another div (which I will refer to as div x) taking up the other 10. When the button is pressed I am also toggling the class of div x so that it takes up the entire grid space when the menu is toggled off. The issue is it is changing grid size before the animation is finished which makes it go to the bottom of the page and then back to the top. I want the toggling of div x to be done after the menu has been toggled. I have tried moving it around to different parts of the function, and even creating a different function which is called after, but the same issue arises. Here is what I have:
$('#toggle,.contents').click(function() {
if ($('#toggle').is(':visible')) {
$('#moduleList').toggle('slide', {
direction: 'left'
}, 1000);
}else {
$('#moduleList').toggle('slide', {
direction: 'left'
}, 1000, function() {
});
}
$('#toggler').toggleClass('col-md-12 col-md-10');
});
Thanks in advance for any help!
Place $('#toggler').toggleClass('col-md-12 col-md-10'); inside of your empty function. The function should be called once the animation is complete, following the link #Rajesh mentioned.
Issue:
I am using the Circle Progress JQuery plugin (version: 0.6.0) for a project and have made some modifications to it, however, each circle seems to repeat itself (or loop) for an extended period of time rather than only performing the animation once.
Due to the modifications made, such as adding a link to where if it is clicked, the animation begins, doesn't seem to be where the issue lies. It's when you start to scroll down, and when you do - every circle starts animating based on the percentage set but keeps repeating itself several times before it stops. It should only start the animation for each circle once when the user scrolls down but I can't seem to figure out the root of why this is occurring.
Here is what I have:
$('.about_nav a:nth-of-type(2)').click(function () {
function animateElements() {
$('.progressbar').each(function () {
var elementPos = $(this).offset().top;
var topOfWindow = $(window).scrollTop();
var percent = $(this).find('.circle').attr('data-percent');
var percentage = parseInt(percent, 10) / parseInt(100, 10);
var animate = $(this).data('animate');
if (elementPos < topOfWindow + $(window).height() - 30 && !animate) {
$(this).data('animate', false); // Change this 'false -or- true' - Currently set to false so that each time a user clicks on 'Skill-set' link, animation occurs
$(this).find('.circle').circleProgress({
startAngle: -Math.PI / 2,
value: percent / 100,
thickness: 2, // Change this for thickness
fill: {
color: '#16A085'
}
}).on('circle-animation-progress', function (event, progress, stepValue) {
$(this).find('.percent').text((stepValue*100).toFixed(0) + "%"); // NOTE: Change '.toFixed(0)' to '.toFixed(1)' to get 1 decimal place to the right...
}).stop();
}
});
}
animateElements();
$('.about_body_wrapper').scroll(animateElements);
});
Here is a rough demo of what I mean: DEMO - Click "Skill-set" tab and scroll down.
Any help on this would be greatly appreciated!
so I think I've achieved what you wanted on This updated(again) JSFIDDLE
basically, I set the data-animate property to true right before the animation begins, which stops any subsequent animate calls from animating it again (the looping issue you were seeing).
Then, I took the animateElements function definition out of the click handling event. I did this so I could call it on a more global scope. I now call animateElements in the click handler that changes the tabs. Had to do that because it being fired on page load was making all the elements offsetTop = 0 because they started out hidden.
Lastly, I added an init property to the animate elements function which resets all the data-animate to false when true. Its only true when called from a tab click, not by the scroll event.
heres the relevant code update:
...new init param (also have to make room for the scroll event passed in)
function animateElements(e, init) {
if(init){
$('.progressbar').data('animate', false);
}
...animateElements is now initially called by the tab click handler
$(currentlist).fadeOut(250, function () {
$(newlist).fadeIn(200, function(){
animateElements({}, true);
});
});
lastly, note theres a bunch of stuff in there now you can cut out now that I forgot to in the jsfiddle from when I was proving the concept.
cheers!
I am trying to create an 'application' contained in a div on a web page. This can't be any larger than certain dimensions (lets say: 550px by 280px). I have a menu with at least 1-3 sub menus for each item. The problem is, while I know the submenu is no larger than 280px high, the submenus often extend beyond the parent div's bounds (except for the last one which always grows upward not down).
Is there any way to make the menus grow up or down depending on whether it will extend beyond the div's bounds?
Here is a JSFiddle: http://jsfiddle.net/3FqcG/
Notice how the "Salzburg" submenu grows down beyond the bounds of the black DIV? I want that to grow up if it is too long and down if there is enough room.
Currently, I am just using the basic initialization: $( "#menu" ).menu();
Thanks!
I don't believe you can do this in CSS.
This leaves us with javascript. The basic idea is to:
calculate the baseline of the menu
if this lies outside the boundary
move the menu upwards to correct the position
live almost happily ever after
But, we have one major issue:
Though we capture the focus of an element, we don't know when its submenu is displayed & positioned. So although your problem is technically solved, it is by far not a desirable solution.
UPDATE
The best workaround I could come up with was to:
Turn off the animation (to avoid ugly glitches)
Add a watcher that would constantly monitor the element that is about to be opened
If opened, apply the position correction
Anyway, if you consider coming this far, you might as well override the default positioning of the jquery ui component, with the note that you will not be able to easily update the library. Update: or try Rudy Garcia's version if it works
Demo
Code of the demo:
var BASE_OFFSET = $('#menuContainer').offset().top;
var MAX_OFFSET = $('#menuContainer').height(); // get the offset of the container
var whenVisible = function($el, callback){ //executes callback when $el is visible
if($el.is(':visible')){ // if visible
callback(); // execute callback
}else{ // otherwise
setTimeout(function(){whenVisible($el, callback);},10); // do the same check in 10 ms
}
};
var fixPosition = function($menu){ // correct the position of the menu in respect to #menuContainer
var h = $menu.outerHeight(true); // take the height of the menu
var menuBottom = $menu.offset().top + h - BASE_OFFSET; // the baseline of the menu (taking into consideration the BASE_OFFSET)
if(menuBottom > MAX_OFFSET){ // if this is outside the MAX height
var diff = MAX_OFFSET - menuBottom; // calculate the difference
var newTop = $menu.position().top + diff; // modify current positioning with the calculated diff value
$menu.css('top', newTop + 'px'); // apply it to top (which is also used by jquery to position submenus
}
$.fx.off = false; // switch animations back on
};
$( "#menu" ).menu().on('menufocus', function(ev, ui){ // on the event menufocus
var $ui = $(ui.item); //take the focused element
var $menu = $ui.children('ul'); // take its related submenu
if($menu.length === 0){ // if there is none
return; // just terminate
}
$.fx.off = true; // switch off jQuery effects (otherwise you'll have glitches)
whenVisible($menu, function(){fixPosition($menu);}); // execute fixPosition when $menu is visible
});
You could also look at the API for this widget:
http://api.jqueryui.com/menu/
You can use the position option to position the elements how you want.
This will change the position so that they are within the box, however you will want to dynamically access the last to give it the position you want as the code below will change all menu items to move up 50.
$( "#menu" ).menu({ position: { my: "left top", at: "right+5 top-50" } });
A complete list of positioning options are also found here: http://api.jqueryui.com/position/
Apparently jquery UI has accounted for this and has given the option "within" to make sure your element stays within another element of your choice.
Therefore Your solution should be this:
$( "#menu" ).menu({ position: {within: '#menuContainer' } });
In a webapp I'm working on, I want to create some slider divs that will move up and down with mouseover & mouseout (respectively.) I currently have it implemented with JQuery's hover() function, by using animate() and reducing/increasing it's top css value as needed. This works fairly well, actually.
The problem is that it tends to get stuck. If you move the mouse over it (especially near the bottom), and quickly remove it, it will slide up & down continuously and won't stop until it's completed 3-5 cycles. To me, it seems that the issue might have to do with one animation starting before another is done (e.g. the two are trying to run, so they slide back and forth.)
Okay, now for the code. Here's the basic JQuery that I'm using:
$('.slider').hover(
/* mouseover */
function(){
$(this).animate({
top : '-=120'
}, 300);
},
/* mouseout*/
function(){
$(this).animate({
top : '+=120'
}, 300);
}
);
I've also recreated the behavior in a JSFiddle.
Any ideas on what's going on? :)
==EDIT== UPDATED JSFiddle
It isn't perfect, but adding .stop(true,true) will prevent most of what you are seeing.
http://jsfiddle.net/W5EsJ/18/
If you hover from bottom up quickly, it will still flicker because you are moving your mouse out of the div causing the mouseout event to fire, animating the div back down.
You can lessen the flicker by reducing the delay, however it will still be present until the delay is 0 (no animation)
Update
I thought about it and realized that there is an obvious solution to this. Hoverintent-like functionality!
http://jsfiddle.net/W5EsJ/20/
$(document).ready(function() {
var timer;
$('.slider').hover(
/* mouseover */
function(){
var self = this;
timer = setTimeout(function(){
$(self).stop(true,true).animate({
top : '-=120'
}, 300).addClass('visible');
},150)
},
/* mouseout*/
function(){
clearTimeout(timer);
$(this).filter(".visible").stop(true,true).animate({
top : '+=120'
}, 300).removeClass("visible");
}
);
});
You could use .stop() and also use the outer container position
$(document).ready(function() {
$('.slider').hover(
/* mouseover */
function(){
$(this).stop().animate({
top : $('.outer').position().top
}, 300);
},
/* mouseout*/
function(){
$(this).stop().animate({
top : $('.outer').position().top + 120
}, 300);
}
);
});
DEMO
Hope this helps
Couldn't reproduce your issue but I believe that hover is getting called multiple times. To work around this you can check if the div is already in animation. If yes, then don't run another animation again.
Add following piece of code to check if the div is already 'animating':
if ($(this).is(':animated')) {
return;
}
Code: http://jsfiddle.net/W5EsJ/2/
Reference:http://api.jquery.com/animated-selector/
I understand the problem and reproduced it, it happens when hovering from the bottom up. The hovering with the mouse is what's causing the problem since the animation function will be called when the mouse hovers over the image. You need to control what happens here by using mouse enter and mouse leave, check out a similar example: Jquery Animate on Hover
The reason it's like that is because the hover is getting queued up causing it to slide up and down multiple times. There's a plug-in called hoverIntent which fixes the issue. http://cherne.net/brian/resources/jquery.hoverIntent.html
If you do decide to use hoverIntent, the only thing you have to change in your code is .hover > .hoverIntent
I have some items lets say X, Y, and Z. I use hoverIntent for the hovering event. Let's say when I hover on X I display a tooltip with such kind of code
jQuery('.tooltiper').hoverIntent({
over: showPopup,
timeout: 1000,
out: hidePopup
});
So it will be visible for 1 second. What I want is if I hover on Y or Z hidePopup() to run for X and clear the timeout of hoverIntent, so it won't be visible for 1 second. I tried many things but they don't work.
Anyone has experience about this?
clearTimeout($(".tooltiper").prop("hoverIntent_t"));
$(".tooltiper").prop("hoverIntent_s", 0);
This should work
Add $(this).stop(); in the hidePopup function.