I'm currently making a little navigation menu. In one of those dropdown menus, I need one category to expand. It works. But, when category retracts with the help of jQuery .hide('slow'), the menu I want to hide blinks once at the end of the hide animation, and then is properly hidden.
Here's some code below to illustrate my problem :
$(document).ready(function(){
var verif = false;
$("a").hover(function() {
var texte = $(this).text();
var tab = new Array;
tab = texte.split(" ");
if (tab[0] === "+ Deroule" && verif === false) {
$("#submenu").show("slow");
verif = true;
}
else if (tab[0] === "+ Deroule" && verif === true) {
$("#submenu").hide(8000);
//There, I can clearly see, at the end of the hide animation, the previously opened content blinking once before it hides completely.
verif = false;
}
});
});
Without seeing your HTML/CSS it's hard to actually pin the problem down - hint hint create a fiddle hint hint :) - but the first thing that I would do, if I were you, is change the .hover() method to .mouseenter() and .mouseleave() (NOT .mousein() and .mouseout() - that's another conversation about IE support - you can/should look that up on jQuery's site, if you're not familiar).
Why do this? The .hover() method is actually just shorthand for .mouseenter()/.mouseleave() but, for various reasons (including the fact that it is not as widely supported as the two full methods), it occasionally fails to work properly. I cannot guarantee that this is the problem in this situation, but, especially since this appears to be a browser issue, it is always best to go back to basics and start with as much support as possible.
EDIT:
After seeing your simplified fiddle, I think I have a better understanding of what your issue is and what you're trying to do. I have had the same issue before and, from my experience, I can tell you that it is actually a difficult issue to account for.
Elements jump when they are shown/hidden using the .show(), .hide(), slide, and fade methods because as soon as the animation completes they are removed from the flow (in most browsers - not chrome - the show/hide methods do not cause the element to shrink all the way to nothing, so there is still choppiness). Here are two of my most recent solutions to this issue:
In one situation, I was tasked with creating view-more and view-less buttons inside a menu, which would make elements appear/disappear SMOOTHLY one at a time. If you simply try to call a show/hide, slide, or fade method on the collection to be shown, they will all animate at the same time, and the same thing happens when trying to make them run on callback. Additionally, sliding methods wouldn't work because this animation was going to be called on multiple items at a time, thus causing a lot of overhead and making the effect choppy in slower browsers (and even a bit in FF). The show/hide methods worked in some browsers, as they actually do reduce the size of the element, but they are choppy in others so they were out (effectively, their animations don't "complete" in all browsers - see above). Thus, I was left with three options: use fade, animate, or a combination of both.
Solution 1:
The original plan, as it was (with the given specs) the best solution at the time, was to use the animate method to simply slide a wrapper div (with overflow set to hidden up or down, based on the offset of a target element in the list). This worked great, but I was then given the requirement of having each element disappear in succession, via a fade effect. If you do choose this method, then I suggest that you instead use slide methods - as you are not attempting to show view more/less links, this shouldn't be a problem (yes, I know that this probably doesn't sound like it would be an issue for view more/less links, but the way I had to implement it, slides actually did cause an issue).
Solution 2:
Using fade on its own was an issue because everything was still going to fade at the same time and, even if they didn't, the animation would still jump once the fade finished. Thus, the first issue I needed to solve was the animations running at the same time. Using a timer was out of the question because of the overhead, so I wrote a function that recursively called the fade on each element in the collection after calculating the necessary delay between calls (based on a supplied speed argument, and the number of elements to be faded). Next, I still had to solve the jumping issue once the animations were complete. To fix this, I implemented the .fadeTo() method, thus keeping the elements in the flow of the document after their animations. This did, however, cause two more issues:
The .fadeTo() method is not supported in IE (it may be in 9 and 10 - I can't remember)
After the animation, there was a lot of empty space due to the elements not being removed from the flow
To remedy the first issue, I added a browser-specific method for IE, which set the display property of each element to block and their visibility to hidden once their fade-outs were completed - it also did the reverse just before their fade-ins were started.
I solved the second issue by using the animation method that I described previously. To make this work, I had to write another auxiliary method that calculated the speed at which the container needed to slide, based on a given speed of the animation and the number of elements being shown/hidden.
I know that this was a lot of detail, but I hope it helps you determine how best to go about this.
Let me know if you have any questions or need any clarification when you move forward with your implementation. Good luck! :)
Related
I'm looking to do something like this. I'm using code from this answer here but the answer is never made entirely clear. They are suggested to use this jquery plugin here but I haven't been able to get it to work. I would go with the first example's code, only, I'm using Foundation 4 and the progress bars are something that come with it and are simpler to create. Also, the animation code provided in the second example is a lot cleaner-- overall, the first example is kinda messy, code heavy, and redundant.
My code is live here. I'm working with the skill bars in the about section. Before the user gets to this point, the animation should be paused. Once the user scrolls to this part of the page, the animation should play.
EDIT: Also, if you have any suggestions to stop the bars from "breaking" out of their containers when you scale the page (this site is meant to be responsive), I would appreciate that as well.
EDIT2: I've noticed as I've been playing with this that overflow: hidden; on .progress fixes my "breaking" issue.. however, when you resize the window, the sizes stay at what they initialized at. I know realistically users visiting my site likely won't be resizing the window a whole lot, but for employers looking at it, it'll kinda be lame if it doesn't work properly. I'm having this same issue with the grumpy-cat button overlays where it initializes at the first size and doesn't resize the overlay after that. Suggestions to this would be really, really appreciated!
If you know where your skill bar is and you know where your screen is at, you only need javascript. (no plugins or weird stuff)
To get the vertical position of your screen it's simple:
window.pageYOffset
To get the vertical position of your div, you just need
div.offsetTop
In your case, I would give an id to the div that wraps all the skill bars and set a loop (window.requestAnimationFrame https://developer.mozilla.org/en-US/docs/Web/API/window.requestAnimationFrame ) to check if you're within reach of the div (say, if the difference between the window offset and the div is less than some amount).
If the answer is yes, trigger the animation.
The best way to do the animation is by a css transition. (if you need a good intro to css animations here's a video that i found helpful: http://www.youtube.com/watch?v=VoncDvOfUkk )
You can set css animations from javascript.
The idea is that you would set all your "meter" widths to 0. Then in javascript do something like:
div.style.transition = "width 1s";
div.style.width = someValue;
My recommendation for the value to include in the div is some constant fraction of the "progress" div, as in with % as opposed to em or px. This technique should work. (in case you still have issues, you have a window.requestAnimationFrame loop going on so you can recalculate the values at each timestep... although... beware performance).
The reason you were recommended jQuery is because when you're going to have to update all the divs in order to animate them, just writing $(this).find('.meter') and then addClass('.expand') is so much easier.
Hope this helps
I have a slider a little like this:
________
------------| |---------------------------------------
: <-- | slider | --> : : : :
------------|________|---------------------------------------
I'm using jQuery UI to make the slider draggable. This works fine.
The problem is that I'm executing a function each time the slider crosses a section boundary (indicated by :). This function takes approximately 30ms to execute (it's constructing a DocumentFragment and inserting it into the document). During this time the browser does not respond to events, so jQuery UI stops adjusting the slider's position and the drag is prematurely ended (the user is forced to release the mouse button and commence a new drag). This makes the slider feel jerky and buggy.
Is there a solution to this problem?
Edit: I've created a simple fiddle which demonstrates the problem. Note that while the drag is essentially paused during the execution of the slow function, it resumes afterwards. This makes me suspect that there's something about my more complex scenario which is causing the drag event to be cut short (perhaps the DOM manipulation is causing the position of the slider to change briefly).
Edit: After further investigation I'm much closer to understanding the problem. The DOM manipulation code contains a line something like $('.droppable').remove(). This removes the matching elements from the DOM after detaching any event handlers bound to them and removing any associated data. If I use .detach() instead, the behaviour is the same as in the simple fiddle above. Something untoward is happening during the cleanup.
I'd suggest to use jQuery's or Underscore's debounce function, or some equivalent method, to call the function just once every 100 or 200 ms or so.
This won't make things smooth, but at least they won't feel buggy.
Interesting article about it.
I have a grid of div boxes that I will be animating. They will be moving across the screen after a user drags one of the boxes (to re-align into a grid).
Currently I am using JQuery to change the css left and top positions of all of the divs and running this on an interval.
It is laggy if there are more than 50 boxes. How do I make this less laggy? Is there an animation library that is better for this, or do I just need to limit it to 50 boxes?
Image of layout:
You have a few options to optimize the performance.
Newer browsers have requestAnimationFrame that lets the browser take care of the animation timing in order to optimize Javascript animations. Rather than using times to perform the animation, which is what jQuery framework uses, you repeatedly a callback to requestAnimationFrame. The browser will call your function with a progress variable for the animation, and you render the current stage of your animation based on the progress variable. requestAnimationFrame for smarting animating talks about this in depth. Google Closure is the only framework I am aware of that uses requestAnimationFrame however, and it's rather heavyweight.
CSS animations. jQuery offers CSS animation, so do many other frameworks. CSS animations give you hardware acceleration, so the animation is much faster. Unfortunately, CSS animations are relatively new and not yet well supported, so you'll probably end up falling back to Javascript animation on older browsers, depending on the library you use.
Optimize your Javascript. Instead of animation each and every box in the grid, encapsulate each row in a div and animate the entire div instead. That should speed the animation up by a bit. I'm sure there are other ways you can optimize based on your current implementation.
Honestly, I don't know of any library that will make this work more efficiently for you, though there are many libraries out there that are faster than jQuery. The issue isn't just the jQuery, its the fact that you have 50 elements that are all moving/draggable, thus requiring a lot of the browser's resources.
If you can post your code there may be a few things that we could suggest to speed it up slightly.
The two biggest things problems that I can think of are if you added those boxes programmatically and added the handler for each as you added the element to the page, and if you don't store your selectors in variables. Aside from that I would have to see the code.
Have a look at:
jQuery isotope
It has options to allow you to use css3 animations if available or use jQuery / JS animations.
Handy for grid like animation and arrangements.
Some brave soul has managed to add drag and drop to isotope too. http://tyler-designs.com/masonry-ui/ (a bit clunky but works)
There are several ways of increasing the performance. One would be to reduce the amount of DOM elements required for each box. Another is to not animate (and render) boxes outside of the current viewport. Give all boxes that are outside of the viewable area "display: none;" and exclude them before starting a new animation. If you want to go even further you can start to recycle boxes instead of showing and hiding them when the user is scrolling through the page.
This way you will always get the same performance no matter how many boxes you have (above the amount that you can fit in the viewport).
This technique is called UI virtualization. There are several projects that use it like: http://github.com/mleibman/SlickGrid/wiki. It's really useful when you need to render a lot of elements (hundreds, thousands, millions). But it takes quite some work to get it right. And I don't know about any generic working components that are easy to plug in. I tried to find an article that explains it. This is the only thing I could come up with for now, it's for Silverlight though: http://www.silverlightshow.net/items/Virtualization-in-Silverlight-4-RC.aspx
Also try this this plugin for jQuery. Use the regular 'animate' method and it will try to use (hardware accelerated) CSS animations where possible: http://playground.benbarnett.net/jquery-animate-enhanced/
I am using jQuery Tools scrollable for a carousel with three items in view at a time and scrolling one single item in an autoscrolling and circular fashion.
I have used CSS to show the three items. This works ok until the carousel reaches the last item, it seems to wait until it has gone past it to load in the following items.
It also seems to wait until the middle item is fully in view before displaying the last item.
Demo here:
http://jsfiddle.net/pgxSm/6/
Is there anything I can do about this?
Yes you can. I've had that very same problem.
The element that contains the items needs to have a very large width. Try adding CSS like this:
.items {
width: 20000em;
}
Actually this is one of the requirements to make jQuery Tools Scrollable work properly, as stated on the developer's demo page. This way all items can be displayed in one row to that there is no space visible after the last item while scrolling. It doesn't matter if it's larger than needed, as long as it is never too small.
jQuery Tools Scrollable is actually built to only display one item at a time. This means you have to change the code of the script:
You can find the non-minified script here. Search for the line in the Scrollable script that says
cloned2 = self.getItems().eq(1).clone().appendTo(itemWrap);
Replace it with this line:
cloned2 = self.getItems().slice(1,4).clone().appendTo(itemWrap);
This way you clone the first 3 items (instead of only the first item) and add it to the end of the items, so that circular scrolling is possible even though more than one items are visible at a time. If you want more items to be visible at a time, just replace 4 with [number of visible items] + 1. Afaik, there's no other way to make jQuery tools work with multiple items being visible at a time. I also use this solution at work.
If you want to get the minified version of the script again, after your changes, simply use this minifier. It works like a charm. :)
If this was what you were looking for, please consider marking it as the correct answer. Thank you!
The above answer is technically correct, however, if you're downloading it in a bundle from the jQuerytools site, it is worded slightly differently.
The line you might be looking for instead is:
l = f.getItems().eq(1).clone().appendTo(h);
Which should change, in a similar way to the above answer, to this:
l = f.getItems().slice(1,4).clone().appendTo(h);
Not fully tested, use at your own risk.
If you'd like to make it configurable, just add
circularVisibleItems:1
into conf object and then change
l=f.getItems().eq(1).clone().appendTo(h);
into
l=e.circularVisibleItems>1?f.getItems().slice(1,e.circularVisibleItems+1).clone().appendTo(h):f.getItems().eq(1).clone().appendTo(h);
Than you can define how many items have to be cloned in which slider.
When running a Jquery animation like slideDown(), it looks like a number of element-specific css properties is set to be updated at a specific interval and when the animation is complete these properties are unset and the display property is simply set to auto or whatever. At least in firebug you can't see those temporary properties any more.
The problem I've encountered is the scenario where we stop the slide down with stop(). The element is then left with the current temporary css values. Which is fine because it has to, but let us say that I stoped the slidedown because I have decided to slide it back up again a bit prematurely. It would look something like this:
$(this).slideDown(2000)
//The below events is not in queue but will rather start execute almost
simultaneously as the above line. (dont remember the exact syntax)
$(this).delay(1000).stop().slideUp(2000)
The above code might not make much sense, but the point is:
After 1 second of sliding down the animation is stopped and it starts to slide back up. Works like a charm.
BUT!!! And here is the problem. Once it it has slid back up the elements css properties are reset to the exact values it had 1000ms into the slideDown() animation (when stop() was called). If we now try to run the following:
$(this).slideDown(2000)
It will slide down to the very point the prior slideDown was aborted and not further at half the speed (since it uses the same time for approximately half the height). This is because the css properties were saved as I see it. But it is not especially wished for. Of course I want it to slide all the way down this time.
Due to UI interaction that is hard to predict everything might soon break. The longer animations we use increases the risk of something like this happening.
Is this to be considered a bug, or am I doing something wrong? Or maybe it's just a feature that is not supported?
I guess I can use a callback function to reset the css properties, but depending on the animation used, different css properties are used to render it, and covering your back would result in quite a not-so-fancy solution.
You could try to replace the slideUp and slideDown with animate.
http://api.jquery.com/animate/
This way, you are explicitly telling it what to do.
This is the expected (though not desirable) behavior...to get the .slideDown() to go to the full height, start the slides from the finished position, by using .stop(true, true), so the animation completes. The second true argument, telling it to skip to the end of the animation is the important part here, so those "final" values it slides back to are the full height, etc...rather than the height it was at when it stopped sliding.
This was a bug that has been fixed in jQuery 1.7.2: http://bugs.jquery.com/ticket/8685