jQuery width (%) doesn't stop calculate on windowResize? - javascript

This is my code:
http://jsfiddle.net/7cXZj/
var callback = function () {
$('.progress-bar').width($('.progress-bar').parent().width() - 190);
$(".mainpart-background").animate({ width: "80%" }, 800 , function(){
var sidepartposition = $(".progress-bar").width() * 0.1 + $(".sidepart-content").width() * 0.5 ;
$(".sidepart").animate({ "margin-right": - sidepartposition }, 100);
});
};
$(document).ready(callback);
$(window).resize(callback);
var sidepartpositionResize = $(".progress-bar").width() * 0.1 + $(".sidepart-content").width() * 0.5 ;
$(window).resize(function(){
$(".sidepart").css( "margin-right", "sidepartpositionResize" );
});
This is the problem:
The span showing "20%" disappears when you resize the window. Why? Inspecting it with Firebug you will see jQuery won't stop calculate the 80%, it goes 80.00213 to 79.1241 to 79.12523 ... and so on. Suddenly after 1-4 seconds it's done with this strange process. Then the span contents the 20% appears.
Please note: This code should work on responsive websites.
I'm a JS beginner. Thank you so much for help!

Try this code: http://jsfiddle.net/7cXZj/5/
This code lets you bind to the end of the resize event and not executing the function many times during the resize of the window.
var animate = function(){
console.log('animando');
$(".mainpart-background").css('width', 0);
$(".mainpart-background").animate({
width: "80%"
}, 800, function () {
var sidepartposition = $(".progress-bar").width() * 0.1 + $(".sidepart-content").width() * 0.5;
$(".sidepart").animate({
"margin-right": -sidepartposition
}, 10);
}
);
}
window.resizeEvt;
$(document).ready(function(){
animate();
$(window).resize(function()
{
clearTimeout(window.resizeEvt);
window.resizeEvt = setTimeout(function()
{
animate();
}, 250);
});
});
Hope it helps.

Related

How can I recalculate a variable upon screen resize?

I have two variables that calculate the clientHeight, divide by 2 and add 44. It is currently working as intended except if the window is resized, the page needs to be refreshed for it to recalculate clientHeight. Once it is refreshed, it repositions the div correctly. How can I recalculate the clientHeight for each upon window resize so the page doesn't need to be refreshed for it to run the script again and grab the new height?
This is part of an animation that animates based on scroll position. As you scroll down the page, the div animates.
var triggerOffset = document.documentElement.clientHeight / 2 + 44;
var cardHeight = $('#card').outerHeight(true) / 2 + 22;
var duration = 1000;
var requestId = null;
var sceneStart;
if (window.matchMedia("(max-width: 1080px)").matches) {
sceneStart = 4000
} else {
sceneStart = 4000
}
console.log(sceneStart);
TweenLite.set(".contain", {
top: triggerOffset - cardHeight
});
TweenLite.set(".timeline-trigger", {
top: triggerOffset
});
TweenLite.set(".start-trigger", {
top: sceneStart
});
TweenLite.set(".end-trigger", {
top: sceneStart + duration
});
// SCROLL MAGIC!!!
var tl = new TimelineMax({ paused: true })
.set(".card", { }, sceneStart)
.to(".card", duration, { rotationY: 180 }, sceneStart)
.set(".card", { })
// Only update on animation frames
window.addEventListener("scroll", function() {
if (!requestId) {
requestId = requestAnimationFrame(update);
}
});
update();
// Set timeline time to scrollTop
function update() {
tl.time(window.pageYOffset + triggerOffset);
requestId = null;
}
I'm hoping to have the position of the card adjust when the window is resized. Currently, the window needs to be refreshed for it to recalculate.
You are looking for window.onresize
window.addEventListener("resize", function() {
triggerOffset = document.documentElement.clientHeight / 2 + 44;
});
You can use the window.onresize global event listeners be providing it a function that will simply recalculate your triggerOffset :
// THIS IS THE VARIABLE I WANT TO CHANGE ON RESIZE
var triggerOffset = document.documentElement.clientHeight / 2 + 44;
window.onresize = function() {
// each time the window will resize this code will trigger
// we re cacalculate the triggerOffset value
triggerOffset = document.documentElement.clientHeight / 2 + 44;
// we also need to se reset the top value onto the .contain dom element
// basically since we recalculated the triggerOffset you must also update where this value was needed
TweenLite.set(".contain", {
top: triggerOffset - cardHeight
});
TweenLite.set(".timeline-trigger", {
top: triggerOffset
});
}
TweenLite.set(".contain", {
top: triggerOffset - cardHeight
});
TweenLite.set(".timeline-trigger", {
top: triggerOffset
});
TweenLite.set(".start-trigger", {
top: sceneStart
});
TweenLite.set(".end-trigger", {
top: sceneStart + duration
});
UPDATE :
A better solution if you are using multiple scripts file where you are doing the same logic is using the 'resize' event provided by #ControlAltDel.
In each script file you will add en event listener and put your logic in the callback :
window.addEventListener("resize", function() {
triggerOffset = document.documentElement.clientHeight / 2 + 44;
TweenLit.set(...);
TweenLit.set(...);
});

Link clicked first time - on scroll animation doesn't work

Issue:
When I click the skill-set link for the first time, the animation occurs but does not occur when you scroll down. Each circle is to start it's own animation when the user scrolls down the page. If you click the skill-set link twice though, everything works as its supposed to.
So my question at hand is, why doesn't the animation on scroll occur on the first time the skill-set link is clicked?
Here is a DEMO of what I am talking about, please excuse the terrible layout. Once you click on the skill-set link, you see the animation happen, but when you scroll down, the animation is already completed...However, if you click the skill-set link twice, and then scroll down, you see each circle animate when you scroll down. This is what should happen on the first time the link is clicked, but for some odd reason it isn't.
JS:
$('#skill-set-link').click(function () {
function animateElements(index, element) { // (e, init)
if (element) { // (init)
$('.progressbar').data('animate', false);
}
$('.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() + 10 && !animate) {
$(this).data('animate', true);
$(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({}, true);
$('.about_body_wrapper').scroll(animateElements);
});
=========================================================================
Any idea as to why the animation on scroll doesn't occur the first time the link is clicked?
The behavior is occurring because everything in the skill-set-link DIV is still hidden when it runs the first time, so the top position of all of the progressbar elements is zero. Since they are zero, they are meeting the criteria of the if statement and the animation is being enabled on all of them.
To fix it, I added a call to show() the progressbar elements, including the parameter to run animateElements when show() is complete.
I moved the call to set "animate" to false to the menu item click function as it didn't really serve any purpose in animateElements. I also removed the animateElements function from the click event handler to simplify reading the code.
function animateElements(index, element) { // (e, init)
$('.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() + 10 && !animate) {
$(this).data('animate', true);
$(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();
}
});
}
$('#skill-set-link').click(function () {
$('.progressbar').data('animate', false);
$('#skill-set').fadeIn(animateElements);
});
$(window).scroll(animateElements);
Thanks to the help from Tony Hinkle - Here is the answer.
Due to the main div being hidden - we needed to show() the main div beforehand...However, adding $('#skill-set').show(0, animateElements); as suggested by Tony, didn't quite work right - so instead $('#skill-set').fadeIn(animateElements) replaced that along with taking out the 0 which seemed to do the trick.
Many thanks to Tony though for steering me in the right direction!
Here is the final snippet used to make this work as desired:
function animateElements(index, element) { // (e, init)
$('.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() + 10 && !animate) {
$(this).data('animate', true);
$(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();
}
});
}
$('#skill-set-link').click(function () {
$('.progressbar').data('animate', false);
$('#skill-set').fadeIn(animateElements);
});
$(window).scroll(animateElements);
And here is the final iteration: DEMO
Don't mind the layout... :)

setInterval- Javascript not working

Trying to loop a function.
It's a simple text animation - The text will
1.Fade in left letter by letter and then
2.Fade out up letter by letter.
3.This will repeat, but the text will appear again at another random location on the
page.
When I set the interval delay to 1000, the text appears 4 times in all with a gap of 1 sec each. The first time, the text appears with fade in left, the second & third the text just flashes as a whole and finally, the fade out happens letter by letter.
So, I set the delay to 4700. The animation works as desired, but it is not looping.
http://jsfiddle.net/y5C4G/3/
The callback function in textillate wasn't working too, so i chose setInterval.
HTML :
<span class="brand">
<h1>
<ul class="texts">
<li>E L Y S I U M</li>
<li></li>
</ul>
</h1>
</span>
JS :
$(window).bind("load", function () {
function ShowBrand() {
var docHeight = $(document).height();
var docWidth = $(document).width();
$newSpan = $(".brand");
spanHeight = $newSpan.height();
spanWidth = $newSpan.width();
maxHeight = docHeight - spanHeight;
maxWidth = docWidth - spanWidth;
$newSpan.show().css({
top: Math.floor(Math.random() * maxHeight),
left: Math.floor(Math.random() * maxWidth)
}).textillate({
in: {effect:'fadeInLeft'},
out: {effect:'fadeOutUp'}
});
}
setInterval(ShowBrand,4700);
});
I'm not so sure about what you want to achieve exactly on your animation, but I guess what you would like to do is something like this:
DEMO:http://jsfiddle.net/YKebf/9/
loadTextillate(jQuery);
$newSpan = $(".brand");
$newSpan.show().textillate({ in : {
effect: 'fadeInLeft'
},
out: {
effect: 'fadeOutUp',
callback: function () {
ShowBrand(); //set as a callback function
}
},
loop: true
});
function ShowBrand() {
var docHeight = $(document).height();
var docWidth = $(document).width();
var spanHeight = $newSpan.height();
var spanWidth = $newSpan.width();
var maxHeight = docHeight - spanHeight;
var maxWidth = docWidth - spanWidth;
var newPosTop = Math.floor(Math.random() * maxHeight);
var newPosLeft = Math.floor(Math.random() * maxWidth);
console.log("New Position",newPosTop,newPosLeft);
$newSpan.css({
top:newPosTop,
left:newPosLeft
});
}
CSS:
.brand{
position:absolute;
}
Hope this helps.
Edit: As mentioned by naota, you can set a callback. By doing this you will not be needing any setInterval and also you might not have to modify any code in plugin file in my case. See the updated demo : http://jsfiddle.net/lotusgodkk/y5C4G/6/
Instead of initializing textillate in each interval, why not just change the top and left value of span and rather add loop:true to the textillate.
JS:
$(window).bind("load", function () {
ShowBrand();
$('.brand').textillate({ in : {
effect: 'fadeInLeft'
},
out: {
effect: 'fadeOutUp',
callback: function () {
ShowBrand()
}
},
loop: true,
});
});
function ShowBrand() {
var docHeight = $(document).height();
var docWidth = $(document).width();
$newSpan = $(".brand");
spanHeight = $newSpan.height();
spanWidth = $newSpan.width();
maxHeight = docHeight - spanHeight;
maxWidth = docWidth - spanWidth;
$newSpan.show().css({
top: Math.floor(Math.random() * maxHeight),
left: Math.floor(Math.random() * maxWidth)
});
}
Also, make sure you have .brand positioned.
CSS:
.brand{position:absolute;}
Demo: http://jsfiddle.net/lotusgodkk/y5C4G/6/

Change menu option width with jQuery

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

Linear animation with jQuery and fixed step-number

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/

Categories

Resources