I have 5 divs layered and a object in the foreground I want to move across them. This is using the paralax effect. I have been sucessfully able to move the object using basic .animate in jQuery.
The problem I'm having is getting the background divs to animate properly - or at all. What happens is when I click on my trigger div - the div.cloud1 and div.cloud2 move BEFORE my object does. They also change positions despite my playing with the timing values.
All objects in the divs are absolutely positioned - the divs are relative for being able to use z-index.
Specifically I'm trying to move div.cloud1, div.cloud2, div.ground, div.Mountain all at different speeds so it gives the illusion of 3d.
The object I'm sending across is a different div.
I'm not sure what the problem is.
Here is my JSfiddle: http://jsfiddle.net/U6Mu6/
jQuery(document).ready(function () {
jQuery('#cloud-01').css({
backgroundPosition: '50 -180px'
});
jQuery('#cloud-02').css({
backgroundPosition: '0 -100px'
});
jQuery('#mountains-03').css({
backgroundPosition: '0 50px'
});
jQuery('#trees-04').css({
backgroundPosition: '0 50px'
});
jQuery('#ground').css({
backgroundPosition: 'left bottom'
});
jQuery('#branding').css({
backgroundPosition: 'center 0'
});
jQuery('#content').css({
backgroundPosition: 'center 0'
});
jQuery('#sec-content').css({
backgroundPosition: 'center 0'
});
jQuery('#footer').css({
backgroundPosition: 'center 0'
});
jQuery('#wrapper').css({
overflow: "hidden"
});
jQuery('#klicker').click(function () {
jQuery('#cloud-01').animate({
backgroundPosition: '(-100px -10px)'
}, 200000);
jQuery('#cloud-02').animate({
backgroundPosition: '(-400px 0px)'
}, 20000);
jQuery('#mountains-03').animate({
backgroundPosition: '(-2500px 50px)'
}, 20000);
jQuery('#ground').animate({
backgroundPosition: '(-5000px bottom)'
}, 20000);
startHim();
jQuery("#full-robot").animate({
left: "50%",
marginLeft: "-150px"
}, 2000);
setTimeout("leaveScreen()", 15000);
});
});
var num = 1;
function startHim() {
num++;
jQuery("#sec-content").animate({
top: "-=5px"
}, 150).animate({
top: "+=5px"
}, 150);
jQuery("#content,#branding").animate({
top: "-=" + num + "px"
}, 150).animate({
top: "+=" + num + "px"
}, 150);
if (num < 4) {
setTimeout("startHim()", 300);
} else {
setTimeout("bounceHim()", 300);
}
}
function bounceHim() {
jQuery("#sec-content,#branding").animate({
top: "-=4px"
}, 150).animate({
top: "+=4px"
}, 150);
jQuery("#content").animate({
top: "-=8px"
}, 150).animate({
top: "+=8px"
}, 150);
setTimeout("bounceHim()", 300);
}
function leaveScreen() {
jQuery("#full-robot").animate({
left: "100%",
marginLeft: "0px"
}, 2000);
}
Just FYI - some of the objects in the fiddle are not included on purpose. I just want to get things working first.
I did see a error in JSFIDDLE dealing with implied eval on my setTime expression. But I'm not sure how to fix it. I suppose I could pass the div as function and use .hide instead.
All help is welcome thanks!
EDIT:::
I forgot this:
/**
* v. 1.02
*/
(function($) {
$.extend($.fx.step,{
'background-position': function(fx) {
if (fx.state === 0 && typeof fx.end == 'string') {
var start = $.curCSS(fx.elem,'background-position');
start = toArray(start);
fx.start = [start[0],start[2]];
var end = toArray(fx.end);
fx.end = [end[0],end[2]];
fx.unit = [end[1],end[3]];
}
var nowPosX = [];
nowPosX[0] = ((fx.end[0] - fx.start[0]) * fx.pos) + fx.start[0] + fx.unit[0];
nowPosX[1] = ((fx.end[1] - fx.start[1]) * fx.pos) + fx.start[1] + fx.unit[1];
fx.elem.style.backgroundPosition = nowPosX[0]+' '+nowPosX[1];
function toArray(strg){
strg = strg.replace(/left|top/g,'0px');
strg = strg.replace(/right|bottom/g,'100%');
strg = strg.replace(/([0-9\.]+)(\s|\)|$)/g,"$1px$2");
var res = strg.match(/(-?[0-9\.]+)(px|\%|em|pt)\s(-?[0-9\.]+)(px|\%|em|pt)/);
return [parseFloat(res[1],10),res[2],parseFloat(res[3],10),res[4]];
}
}
});
})(jQuery);// JavaScript Document
I don't know if this is too obvious, but your trying to set the "background-position"attribute of the clouds by using backgroundPosition
You might just change them to
$("#cloud-01").css({'background-position': '50px -180px'})
Notice the background-position instead of backgroundPosition
If you want to stagger the time each cloud takes to move, you need to offset your animation durations, like
$('#cloud-01').animate({
'background-position' : '(-100px -10px)'
}, (1000) ); // 1 second duration
$('#cloud-02').animate({
'background-position' : '(-400px 0px)'
}, (2000) ); // 2 seconds
$('#mountains-03').animate({
'background-position' : '(-2500px 50px)'
}, (2000) ); // 3 seconds
Related
I am trying to make a cart fly effect but I am getting an error and not sure why the top is being called undefined. I am already able to add the product on the basket but the image just got stuck and appears randomly on screen instead of animation from the parent image to the cart upward
$('.add').on('click', function () {
var cart = $('.cart');
var imgtodrag = $('.zoomImg');
if (imgtodrag) {
var imgclone = imgtodrag.clone()
.offset({
top: imgtodrag.offset().top,
left: imgtodrag.offset().left
})
.css({
'opacity': '0.5',
'position': 'absolute',
'height': '150px',
'width': '150px',
'z-index': '100'
})
.appendTo($('body'))
.animate({
'top': cart.offset().top + 10,
'left': cart.offset().left + 10,
'width': 75,
'height': 75
}, 1000, 'easeInOutExpo');
setTimeout(function () {
cart.effect("shake", {
times: 2
}, 200);
}, 1500);
imgclone.animate({
'width': 0,
'height': 0
}, function () {
$(this).detach()
});
}
});
P.S.
I am using Jquery 2.1.3 and jqueryui 1.11.2
already figured it out, the element was missing on some page causing the error
I am looking to animate this progress bars, but I'm having a different behavior using jQuery animate() method. I want to animate the progress bars one by one with a 0.1s delay. I will need help with choosing the right animation, because now my animation is behaving downwards. I'd like to do it in the simplest way possible.
Here is what I have so far:
$('.vertical-bars .progress-fill span').each(function() {
var percent = $(this).html();
var pTop = 100 - (percent.slice(0, percent.length - 1)) + "%";
$(this).parent().css({
'height': percent,
'top': pTop
});
$(this).parent().animate({
height: "toggle"
}, {
duration: 900,
specialEasing: {
height: "swing"
}
});
});
I have prepared a JSFiddle with my progress bars HERE.
The right behavior is to fill the progress-bars upwards, like in THIS example.
You need to animate both the height and top of your bars, or you need to construct them such that they are pinned to the horizontal axis when you change the height. The second takes a little more thought, but the first, although not as elegant, is straight forward.
To animate top you can't use toggle (as it is animating to 100% and back, not to 0), so you will need to animate both the shrink and grow separately using done to trigger a second animation. Taking the same style as you used above:
$('.vertical-bars .progress-fill span').each(function () {
var percent = $(this).html();
var pTop = 100 - ( percent.slice(0, percent.length - 1) ) + "%";
$(this).parent().css({
'height': percent,
'top': pTop
});
var self=this;
$(this).parent().animate({
height: 0,
top: "100%"
}, {
duration: 900,
specialEasing: {
height: "swing",
top: "swing"
},
done:function(){
$(self).parent().animate({
height: percent,
top: pTop
}, {
duration: 900,
specialEasing: {
height: "swing",
top: "swing"
}
})
}
});
});
Of course you can also achieve the same thing using css animation. If I have time to figure it out I'll post an edit.
I don't know what height: "toggle" does but you basically want to set 0 height and 100% offset from top and then start animation that adjusts both styles.
The 100ms between animations is done simply by using setTimeout and incrementing the timeout.
https://jsfiddle.net/kss1su0b/1/
var elm = $(this).parent();
elm.css({
'top': '100%',
'height': 0
});
setTimeout(function() {
elm.animate({
'height': percent,
'top': pTop
}, {
duration: 900,
specialEasing: {
height: "swing"
},
});
}, animOffset);
animOffset += 100;
The simplest and most performing way to invert the animation direction is to align the bars at the bottom with css:
vertical-bars .progress-fill {
position: absolute;
bottom: 0;
}
Then you don't need to set the top any more with jQuery and set a delay:
$('.vertical-bars .progress-fill').each(function (index) {
var percentage = $(this).find('.percentage').html();
$(this).delay(index * 100).animate(
{
height: percentage
}, {
duration: 900,
done: function () {
$(this).find('span').show("normal");
}
}
);
});
jsfiddle
I made a little function that allows to click on a text element which then flys (animated top/left offset with absolute position) to a specific location and disappears.
Here is a fiddle of the problem.
Here is my code from the click handler (in coffescript):
var hoveringSelection = $ "<div class='flying cm-variable'>#{selection}</div>"
var dropdownToggle = $ '#watchlist-dropdown'
hoveringSelection.css({
position: 'absolute'
top: window.mouse.y
left: window.mouse.x
display: 'block'
opacity: 1
})
.appendTo('body')
.animate({
top: dropdownToggle.offset().top
left: dropdownToggle.offset().left
opacity: 0.0
},
{
duration: 1500
easing: 'easeOutCubic'
complete: () ->
hoveringSelection.remove()
updateQueueSize()
}
as you can see it should be at opacity 0 and then removed. The problem is that it shows for a split second (with a ~50% chance) before it gets removed.
I tested it with alerts before the .remove() is called so that the javascript execution halts, but it still did it before the alert was executed. Therefore the issue has to appear right before the completion callback of animate() is called.
I could not observe such behaviour in Firefox.
How can I avoid it?
I have seen that this is a bug (http://www.brycecorkins.com/blog/jquery-fadein-opacity-bug-in-chrome-and-ie-8/). The problem is the opacity. I made a few changes to your script to get your goal. At the end of animation I set opacity to 0.01 and then on complete I execute function that remove the element. I hope that this help you.
http://jsfiddle.net/XjesX/1/
$(function () {
$.extend($.easing, {
easeOutCubic: function (x, t, b, c, d) {
return c * ((t = t / d - 1) * t * t + 1) + b;
}
});
var mouseListener = function (event) {
if (!window.mouse) window.mouse = {
x: 0,
y: 0
};
window.mouse.x = event.clientX || event.pageX;
window.mouse.y = event.clientY || event.pageY;
};
document.addEventListener('mousemove', mouseListener, false);
var fly = function() {
var hoveringSelection = $("<div class='flying'>A word</div>");
var dropdownToggle = $('#flytome');
hoveringSelection.css({
position: 'absolute',
top: window.mouse.y,
left: window.mouse.x,
display: 'block',
opacity: 1.0
})
.appendTo('body')
.animate({
top: dropdownToggle.offset().top,
left: dropdownToggle.offset().left,
opacity: 0.01
}, 1500, 'easeOutCubic' ,function(){
alert($('.flying').length);
$('.flying').remove();
alert($('.flying').length);
});
};
$('#flyBtn').click(fly);
});
I have added alert($('.flying').length); before and after remove to show that that element is removed from the DOM. If you remove that 2 lines you'll see in a better way that there is no flickering effect.
I have got a menu on my homepage and on hover I would like them to enlarge. This is exactly what I have achieved, except there is one flaw:
When I move off before the animation ends, the option stops the animation and subtracts 30 from the width that left off from the previous animation. So it always intersects with the other animation and causes false results.
Example:
I move quickly to menu option 1, it only expands little - let's say by 10px - while I am on it, and as I move off the width decreases by 30px, which is more than the previously moved 10px, which results in a smaller button overall.
I would like to somehow capture how much it has moved during the mouseover animation and only decrease the width in the leaving function by that amount. Or, of course some other easy solution, if there is one...
Here's the code:
$('.menu_option').hover(
function() {
var w = $(this).width()+30+"";
$(this).stop().animate({ width:w}, 150, 'easeOutQuad');
}, function() {
var w = $(this).width()-30+"";
$(this).stop().animate({ width:w}, 150, 'easeOutQuad');
});
What you can do is make another variable which is the origin width then when you put it back go back to the origin:
js:
var o = $('.menu_option').width();
$('.menu_option').hover(function () {
var w = $(this).width() + 30 + "";
$(this).stop().animate({
width: w
}, 150, 'easeOutQuad');
}, function () {
$(this).stop().animate({
width: o
}, 150, 'easeOutQuad');
});
http://jsfiddle.net/Hive7/qBLPa/6/
You need to complete the previous animation before the width is calculated
$('.menu_option').hover(function () {
var $this = $(this).stop(true, true);
var w = $this.width() + 30;
$this.animate({
width: w
}, 150, 'easeOutQuad');
}, function () {
var $this = $(this).stop(true, true);
var w = $this.width() - 30 + "";
$this.animate({
width: w
}, 150, 'easeOutQuad');
});
Demo: Fiddle
I'm trying to animate the backgroundPositionY of an <div> element. What I try to do is to animate it linearly. Every step should be in between a fixed range.
For example:
step1: backgroundPositionY: 0 (192*0)
step2: backgroundPositionY: 192 (192*1)
step3: backgroundPositionY: 384 (192*2)
... and so on
My current code looks like the following:
$curtains = $("#unshredder-curtains");
$curtains.data('backgroundPositionY', -3456);
$curtains.animate({
backgroundPositionY: 3648
}, {
duration: 2000,
easing: "linear",
step: function(now, fx) {
var newTop = Math.floor(now / 192) * 192;
$(fx.elem).css('backgroundPositionY', newTop+'px');
}
});
But that does nothing. It just animates the background as it usually does. The steps are just ignored.
Does anyone know how to do that special animation?
Thanks :)
I'd probably do something like:
var step = 192;
setInterval(function(){
$('#unshredder-curtains').css('backgroundPositionY', function(i, val){
var bgPosY = (parseInt(val) + step) + 'px';
$(this).html('New position: ' + bgPosY);
return bgPosY;
});
}, 100);
You can see it in action here: http://jsfiddle.net/pr7cc/