I'm trying to make a few elements on my website rotate loopingly on hover. I've done it with css keyframe animation but when I mouse over or out, the element jumps uglingly.
So I'm trying to do it with some fancy jQuery (since I already have it loaded on my page) and I came across this very helpful stack which the answer explains how to loop with the hover. BUT the explanation is for movement. I managed to move it around with hover, but would be cool to rotate (maybe even both, if it can handle it).
Code for looping:
$.fn.loopingAnimation = function(props, dur, eas) {
if (this.data('loop') === true)
{
this.animate( props, dur, eas, function() {
if( $(this).data('loop') === true ) $(this).loopingAnimation(props, dur, eas);
});
}
return this; // Don't break the chain
};
$("#animate").hover(function(){
$(this).data('loop', true).stop().loopingAnimation({ 'margin-top': '50px'}, 500).loopingAnimation({'margin-top':'10px'},500);
}, function(){
$(this).data('loop', false).stop();
// Now our animation will stop after fully completing its last cycle
});
I then came across yet another stack which explains how to animate rotation with jQuery, but now I can't seem to be able to meld both codes together...
code for rotate:
$(document).ready(function (){
$({deg: 0}).animate({deg: 90}, {
duration: 2000,
step: function(now){
$("#rotate").css({
transform: "rotate(" + now + "deg)"
});
}
});
}
);
I made a pen with both codes to get things easier. Anyone knows how to do it?
How about the following?
function AnimateRotate(elt, d, duration, ondone){
$({deg: 0}).animate({deg: d}, {
easing: 'linear',
duration: duration,
step: function(now, fx){
$(elt).css({
transform: "rotate(" + now + "deg)"
});
},
complete: ondone.bind(elt)
});
}
$.fn.loopingRotation = function(msPerRotation) {
if (this.data('rotating') === true) // already rotating
return;
this.data('rotating', true);
AnimateRotate(this, 360, msPerRotation, function() {
if (this.data('rotating') !== true)
return;
this.data('rotating', false);
$(this).loopingRotation(msPerRotation);
});
}
$.fn.stopRotation = function() {
this.data('rotating', false);
}
$("#rotate").hover(function(){
$(this).loopingRotation(1000);
}, function(){
$(this).stopRotation();
});
Related
I built a minimal carousel that seems to work fine when there are 3 or more slides, but once I remove some slides, things begin to break. Some things I noticed were:
It removes the sliding animation on 'next'
It will make my divs flicker
It will break the animation completely
I worked on some possible solutions that deal with .clone() on the first slide, then .append() to the end of the container, and that makes it work somewhat, however it usually will only make 1 rotation and then be stuck on slide2.
Here is my logic that handles clicking the prev/next buttons
var before_clone = $(elm + ':first').clone();
var after_clone = $(elm + ':last').clone();
$('#buttons a').click(function(e) {
//slide the item
if (container.is(':animated')) {
return false;
}
if (e.target.id == previous) {
container.stop().animate({
'left': 0
}, 1500, function() {
//container.find(elm + ':first').before(container.find(elm + ':last'));
container.append(after_clone);
container.find(elm + ':last');
resetSlides();
});
}
if (e.target.id == next) {
container.stop().animate({
'left': item_width * -1
}, 1500, function() {
//container.find(elm + ':last').after(container.find(elm + ':first'));
container.append(before_clone);
container.find(elm + ':first');
resetSlides();
});
}
//cancel the link behavior
return false;
});
and here is my logic that handles the automatic animations
function rotate() {
$('#next').click();
container.append(before_clone);
container.append(after_clone)
}
Here are two fiddles as well for helping diagnose my problem
my current attempt
my original code(make sure to remove/comment out 2 of the lis)
Appreciate any help you can provide to solve this!
Thanks!
Have a look at this fiddle.
I changed your next to the following:
if (e.target.id == next) {
container.find(elm + ':last').after(container.find(elm + ':first'));
container.css({
'left': 0
});
container.stop().animate({
'left': item_width * -1
}, 1500, function () {
resetSlides();
});
}
I have a problem with this animation:
http://jsfiddle.net/pietrofxq/6kjnnkqx/
function hideIconPicture() {
self = $(this);
var p = self.find("p");
self.find("span").velocity("stop").velocity({
"opacity":0
},{
duration:100,
complete: function() {
p.velocity({"right":"0"}, {
duration:100,
delay:100
})
}
})
}
function showIconPicture() {
var self = $(this);
var p = self.find("p");
p.velocity({
"right":"60px",
}, {
duration:100,
complete: function() {
self.find("span").show().velocity({
"opacity":1
},100)
}
});
}
$(".uploadPicture .icon-container").hover(showIconPicture, hideIconPicture);
If you place your mouse above the middle of the black circle, and the mouse fast until below the black circle, the animation get bug: the icon goes back to its place, but the text remains with opacity:1.
How is that possible if in the code, i'm only setting the position of the icon to its original position AFTER the text get opacity:0?
First you must STOP current animations then start new animations.
add $('.icon-container>*').velocity("stop") to your show and hide functions.
See [ THIS ].
and it's not necessary to put the properties in quote. (use opacity, right instead of 'opacity', 'right')
and for changing your display value do this: (instead of show() hide() functions)
See the [ Documentation ]
$elm.velocity({
...
},{
display: 'none' //or 'block'
});
Whenever I use Velocity for hover effects, I use the data attribute to ensure that the animation is doing the right thing. The answer from #MeTe-30 didn't perform very well for me. This solution might be a little more useful for you: DEMO
var container = $('.icon-container');
var icon = container.find('p');
var text = container.find('span');
var group = icon.add(text);
container.data({animating:false}); // add data for animation queue purposes
function showIconPicture() {
/*
if the path is in the middle of an animation, stop it immediately and reverse the animation. This prevents many unwanted animations if the user hovers in and out quickly
*/
if (container.data('animating') === true){
icon.velocity("stop", true).velocity('reverse',{ duration:0});
container.data({animating:false});
} else { // begin default animation
icon.velocity({right :60, opacity: 1},{
duration:300,
begin: function(){
container.data({animating:true});
},
complete: function() {
text.velocity({ opacity:1 }, {duration: 300, delay: 0});
container.data({animating:false});
}
});
} // end of conditional statement
} // end of function
function hideIconPicture() {
/*
if the path is in the middle of an animation, stop it immediately and reverse the animation. This prevents many unwanted animations if the user hovers in and out quickly
*/
if (container.data('animating') === true){
icon.velocity("stop", true).velocity('reverse',{ duration:0});
container.data({animating:false});
} else { // begin default animation
icon.velocity({ right: 0, opacity:0 }, {
duration:200,
begin: function(){
container.data({animating:true});
},
complete: function(){
group.velocity({ opacity:0 },{ duration:200 });
container.data({animating:false});
}
});
} // end of conditional statement
} // end of function
$(".cover-profile").hover(showIconPicture, hideIconPicture);
I have an animation that causes boxes to appear in sequence when clicking a link. I'm finding that the animation does not stop when clicking a new link and will often cause the it to appear out of sequence. You can see this here when clicking between guests rapidly. I thought something like $.animation.stop() would solve the issue but it hasn't. Any help would be appreciated.
var stepFade = function() {
if ($($this).data("known1") === undefined || null) {
$('.guest-data .known-for').css('display', 'none');
} else {
$('.guest-data .known-for').css('display', 'block');
$('.guest-data .known-for li').eq(0).delay(200).fadeIn( 300);
$('.guest-data .known-for li').eq(1).delay(300).fadeIn( 300);
$('.guest-data .known-for li').eq(2).delay(400).fadeIn( 300, function() { animating = false; });
}
}
//Fade guest
if (!featured) {
featured = true;
getData();
$('.featured').fadeOut( 500, function () {
$('.selected').animate({ opacity: 'toggle'}, 500, function() {
stepFade();
});
})
} else {
$('.selected, .guest-data .known-for, .guest-data .known-for li').fadeOut( 500, function () {
getData();
$('.selected').fadeIn( 500, function() {
stepFade();
});
});
}
Have you tried setting the queue option of .animate() to false?
This way, the animation won't be queued and will begin immediately:
$('.selected')
.animate({opacity: 'toggle'},
{duration: 500, queue: false,
complete: function() { stepFade(); }
});
...OR you could call .stop() right before you call .animate():
$('.selected')
.stop(true, false) //clear the queue and don't jump to the end
.animate({opacity: 'toggle'}, 500, function() {
stepFade();
});
I developed a simple jQuery animation first and later I create a jQuery function for reusability which will do the same thing. Here is a demo: http://jsfiddle.net/SpMns/
My code is working but not reliably so: when I click on the button to run the code, nothing happens; clicking it two or three times will start the animation. Why wouldn't it work the first time?
Please have a look at my routine and tell me which area I need to rectify:
jQuery.fn.busyToggle = function(ImgLoadSrc, marginBottom, opacity, speed,
easing, callback) {
var oDiv = $("<div id='BusyBox'><img src='" + ImgLoadSrc
+ "' alt='Loading...'/><div><em>Loading Wait...</em></div></div>");
if ($("#BusyBox").exists() == false) {
//alert('div not exist');
oDiv.css("background", "-moz-linear-gradient(center top , #F1F2F2 0%, #F1F2F2 100%) repeat scroll 0 0 transparent");
oDiv.css("border-top-left-radius", "5px");
oDiv.css("border-top-right-radius", "5px");
oDiv.css("bottom", "0px");
oDiv.css("font-size", "0.8em");
oDiv.css("font-style", "normal");
oDiv.css("font-weight", "normal");
oDiv.css("left", "50%");
oDiv.css("margin-left", "-45px");
oDiv.css("padding-top", "20px");
oDiv.css("position", "fixed");
oDiv.css("text-align", "center");
oDiv.css("width", "90px");
oDiv.css("height", "50px");
oDiv.css("margin-bottom", "-70px");
oDiv.css("background-repeat", "no-repeat");
oDiv.css("background-position", "center center");
oDiv.data('IsUp', 1)
oDiv.appendTo('body');
}
// i work with jquery data function for achieving toggle behaviour
if (oDiv.data('IsUp') == 1) {
oDiv.data('IsUp', 0);
return this.stop(true).animate({
marginBottom: marginBottom,
opacity: opacity
}, {
queue: false,
duration: speed,
complete: callback
});
}
else {
oDiv.data('IsUp', 1);
return this.stop(true).animate({
marginBottom: marginBottom,
opacity: opacity
}, {
queue: false,
duration: speed,
complete: callback
});
}
};
$(document).ready(function() {
$("#Process").click(function() {
if (flag == 1) {
$('#BusyBox').busyToggle('images/loader.gif', 0, 1, 500, 0, function() {
alert('div visible')
});
flag = 0;
}
else {
$('#BusyBox').busyToggle('images/loader.gif', -70, 0, 500, 0, function(){
alert('div hide')
});
flag = 1;
}
return false;
});
});
What could be causing this to fail the first time it's run?
The problem are is the this usage in the #busyToggle
On the first call $('#BusyBox') becomes an empty Array, which means that this (in #busyToggle) is also empty Array.
A better solution to your probelm would be to call busyToggle this way:
$('#Process').busyToggle('images/loader.gif', 0, 1, 500, 0, function() {
alert('div visible')
});
and use $('#BusyBox') instead of this in your function.
You can find all the code over there: http://jsfiddle.net/ubmCt/8/
P.S: I've also added following line to the ready function, otherwise it won't run in most browsers
var flag = 1;
jQuery("#markets_served").hover(function(){
jQuery.data(document.body, "ms_height", jQuery(this).height());
if(jQuery.data(document.body, "ms_height") == 35) {
jQuery(this).stop().animate({height:'195px'},{queue:false, duration:800, easing: 'easeOutQuad'});
jQuery("#btn_ms_close").css("display","inline");
}
});
jQuery("#btn_ms_close").hover(function(){
jQuery.data(document.body, "ms_height", jQuery("#markets_served").height());
jQuery("#markets_served").stop().animate({height:'35px'},{queue:false, duration:800, easing: 'easeOutQuad'});
jQuery(this).css("display","none");
});
Problem with hovering out. It wont work. It wont hover out when the mouse is out of the content that appears on hover.
http://uscc.dreamscapesdesigners.net/ - example at the bottom " Markets Covered"
Take a look at the hover declaration on the jQuery site. You can specify a handler for the mouseover and mouseout event in one swoop. No need to calculate heights or bind another handler to a new div that appears.
$("#markets_served").hover(
function () {
//do this when over
},
function () {
//do this when out
}
);
Use is like:
$('#el').hover(function(e) { /* hover; */ }, function(e) { /* unhover */ });
here is documentation
Or simplier without data:
jQuery("#markets_served").hover(function() {
jQuery(this).stop().animate({height:'195px'},{queue:false, duration:800, easing: 'easeOutQuad'});
jQuery("#btn_ms_close").css("display","inline");
}, function() {
jQuery(this).stop().animate({height:'35px'},{queue:false, duration:800, easing: 'easeOutQuad'});
jQuery("#btn_ms_close").css("display","none");
});
When mouse comes in you increase the height of the div but you dont reset it when mouse is outside the div hence the issue.
You should do something like this:
jQuery("#markets_served").hover(
function(){
jQuery.data(document.body, "ms_height", jQuery(this).height());
if(jQuery.data(document.body, "ms_height") == 35) {
jQuery(this).stop().animate({height:'195px'},{queue:false, duration:800, easing: 'easeOutQuad'});
jQuery("#btn_ms_close").css("display","inline");
} ,
function(){
jQuery.data(document.body, "ms_height", jQuery("#markets_served").height());
jQuery(this).stop().animate({height:'35px'},{queue:false, duration:800, easing: 'easeOutQuad'});
jQuery("#btn_ms_close").css("display","none");
}
});