JQuery collapsing/expanding need to calculate height - javascript

I think I'm nearly there, I just need to calculate the height of the hidden children height and apply it to the div.
I probably need to write a function that dynamically changes based of the height of the children.
On the demo, click on the Expand/collapse image.
CLICK EXPAND
var currentHeight = $('.Tile.is-expanded .Tile-flyout').outerHeight();
TweenMax.fromTo(".Tile.is-expanded .Tile-flyout", 0.8, { height:0, autoAlpha:0, ease: Linear.easeNone }, { height:currentHeight, autoAlpha:1,});
TweenMax.fromTo(".Tile.is-expanded .Tile-flyout > *", 0.8, {height:0, ease: Linear.easeNone }, {height:"auto"});
CLICK COLLAPSE
var currentHeightOpen = $('.Tile .Tile-flyout').outerHeight();
TweenMax.fromTo(".Tile .Tile-flyout", 0.8, { height:currentHeightOpen, autoAlpha:1, ease: Linear.easeNone }, {height:0, autoAlpha:0,});
TweenMax.fromTo(".Tile .Tile-flyout > *", 0.8, { height:"auto", ease: Linear.easeNone }, {height:0,});
DEMO here, you need to fork it

Here is a Code pen with how to do what I explain in my comments on your main post:
https://codepen.io/anon/pen/mqLREK?editors=0010
function(code){ //Ignore this, I apparently need code to link codepen
//code code
}
You will notice, that in the expand, I grab a list of all the child elements you will be expanding and making visible, I then loop through, and for every 3 I add the cell block height to the running height of the items (because we have 3 per line).
Note, if there can be more or less than 3 per line, you may have to do something to determine this and adjust the loop increment accordingly

Related

Animating child elements in ScrollTrigger GSAP horizontal scroll

I have an svg which forms the basis of my horizontal scroller.
Within this svg, I have added the class .animate to the elements which I want to fade in up as the item comes into view. The .animate class for reference has been added to all the text items in the svg.
Currently, only the .animate elements that are in view initially fade in up. When I scroll down to continue the scroller, the other elements are static. They're not fading in or translating up or down in any way?
TL;DR, here is what I'm trying to achieve:
When the scroller pins in place, and the user continued to scroll down, start fading away .horizontalScroller__intro.
Once .horizontalScroller__intro has faded away, start the horizontal scroll for .horizontalScroller__items
Any elements with the class of .animate in my scroller will fade in up to its original position.
Note: I understand SO rules and preferences to post code here. But, my demo's contain a length SVG, which I cannot post here as it exceeds SO's character limit.
Here is a demo of my latest approach
From the scrollTrigger docs, containerAnimation is what helps achieve animations on horizontal scrollers, and is what I've tried to achieve.
However, in my demo above, I have the following issues:
.horizontalScroller__intro doesn't show initially, when it should, and should fade out on scroll.
The horizontal scroller doesn't work anymore
The .animate elements that are in view, do not fade in up
If I use timeline (see below snippet), then the intro fade out and scroller works. But, doesn't animate in the child elements, which is where I need containerAnimation
$(function() {
let container = document.querySelector(".horizontalScroller__items");
let tl = gsap.timeline({
scrollTrigger: {
trigger: ".horizontalScroller",
pin: ".horizontalScroller",
anticipatePin: 1,
scrub: true,
invalidateOnRefresh: true,
refreshPriority: 1,
end: '+=4000px',
markers: true,
}
});
tl.to('.horizontalScroller__intro', {
opacity: 0,
})
tl.to(container, {
x: () => -(container.scrollWidth - document.documentElement.clientWidth) + "px",
ease: "none",
})
});
I'm struggling to find a way in which I can make the intro fade in, the scroller scroll horizontally, and the .animate elements to fade in, or fade in up.
Edit:
#onkar ruikar, see notes based on your sandbox below:
When you scroll down and the comes into view, I want the initial .animate elements to scroll up into view (currently, once the text fade away, and then the horizontal scroller starts working, only then does the .animate that are suppose to be in view, fade in up
After the initial .animate elements have loaded, the next .animate elements that are part of the scroller, they do not fade in up. They're static. As each .animate element comes into view, then it should fade in up (I think it's currently triggering once, for all the elements).
See visual here:
In the above gif, you can see the first two text blocks are hidden, as soon as they're in view, I want them to fade up. Then the 3rd and 4th text blocks are static, when they should fade up as the user scrolls to that section.
You need to use onUpdate method on the scroll trigger.
onUpdate: self => console.log("progress", self.progress)
Based on the self.progress set opacity, x position etc.
Full demo on codesandbox. Click on "Open Sandbox" button on bottom right to see the code.
if ("scrollRestoration" in history) {
history.scrollRestoration = "manual";
}
$(function() {
let container = document.querySelector(".horizontalScroller__items");
let elements = gsap.utils.toArray(
document.querySelectorAll(".animate")
);
let intro = document.querySelector(".horizontalScroller__intro");
let svg = document.querySelector("svg");
let animDone = false;
window.scrollPercent = -1;
var scrollTween = gsap.to(container, {
ease: "none",
scrollTrigger: {
trigger: ".horizontalScroller",
pin: ".horizontalScroller",
anticipatePin: 1,
scrub: true,
invalidateOnRefresh: true,
refreshPriority: 1,
end: "+=600%",
markers: true,
onEnter: (self) => {
moveAnimate();
},
onLeaveBack: (self) => {
resetAnimate();
},
onUpdate: (self) => {
let p = self.progress;
if (p <= 0.25) {
let op = 1 - p / 0.23;
intro.style.opacity = op;
animDone = false;
}
if (p > 0.23) {
moveAnimate();
// we do not want to shift the svg by 100% to left
// want to shift it only by 100% - browser width
let scrollPercent =
(1 - window.innerWidth / svg.scrollWidth) * 100;
let shift = ((p - 0.22) * scrollPercent) / 0.78;
gsap.to(svg, {
xPercent: -shift
});
}
}
}
});
function resetAnimate() {
gsap.set(".animate", {
y: 150,
opacity: 0
});
}
resetAnimate();
function moveAnimate() {
for (let e of elements) {
if (ScrollTrigger.isInViewport(e, 0.4, true))
gsap.to(e, {
y: 0,
opacity: 1,
duration: 2
});
}
}
});
You need to set opacity 0 on .animate elements in CSS. And use end: '+=400%' instead of 4000px. Relative dimensions can be used in position based calculations easily.

JS/GSAP solution for infinite animation

I am trying to create a infinite star rain animation, all stars are SVG's.
I tried this to create the animation:
(function($) {
TweenMax.set(".astar", {
x:function(i) {
return i * 50;
}
});
TweenMax.to(".astar", 5, {
ease: Linear.easeNone,
x: "+=500", //move each box 500px to right
modifiers: {
x: function(x) {
return x % 500; //force x value to be between 0 and 500 using modulus
}
},
repeat: -1
});
})(jQuery);
The repeat process is not smooth as you can see on this Codepen:
https://codepen.io/daniellwdb/pen/NXogoB
Is there any JS or GSAP solution to make the animation smooth so that it will look like stars keep spawning from the left and move to the right?
With your current setup, I think the easiest way to pull this off would be to duplicate your starfield so that the beginning of your next loop is identical to the end of your first one. Let's say this is your starfield SVG:
|...o.|
|o....|
|..o..|
Your new "duplicated" starfield would essentially be:
|...o.|...o.|
|o....|o....|
|..o..|..o..|
So when you move that duplicated image from left to right 100%, what you see in the last "frame" is identical to what it will return to when it loops.
Here's a fiddle that shows this concept in action: https://jsfiddle.net/yarp4oLs/5/
I have two identical starfield images that are 200x200 (so 400x200 when side-by-side) and they are displayed in a "viewport" container that is 200x200. Then I just slide them to the left 200px and repeat. Instant stars!

Let only 1 accordion item stay open

So Im trying to build my small little accordion with some jquery
Everytime I push the accordion they add a class open and remove the class closed.
But now I want a maximum of 1 item open in the accordion. I can't figure out a way to build it inside my code.
I thought maby the else if statement when there is a open class already when you push the button it closes and it add to your current item a open class.
var accordion = ".accordion .section";
$(accordion).addClass("closed");
$(accordion).click(function(){
var $this = $(this),
$content = $this.find("ul");
if(!$this.hasClass("closed")){
TweenLite.to($content, 0.8, {height:0, ease: Power4.easeOut, y: 0 });
$this.addClass("closed");
$(accordion).append("closed")
$this.removeClass("open");
}
else {
TweenLite.set($content, {height: "auto"});
TweenLite.from($content, 0.87, {height: 0, ease: Power4.easeOut, y: 0});
$this.removeClass("closed");
$this.addClass("open");
}
});
Something like this.
Oh and for the (4) behind it, I also try to find a way to count the LI's inside 1 ul but I didn't really worked on that yet.
Small example I have build so far.
The issue is that you're not trying to close the others.
After opening/closing the clicked one, traverse up to .accordion then select the items, exclude the one that was clicked on, and close them.
$(accordion).click(function(){
var $this = $(this),
$content = $this.find("ul");
if(!$this.hasClass("closed")){
TweenLite.to($content, 0.8, {height:0, ease: Power4.easeOut, y: 0 });
$this.addClass("closed");
$(accordion).append("closed")
$this.removeClass("open");
}
else {
TweenLite.set($content, {height: "auto"});
TweenLite.from($content, 0.87, {height: 0, ease: Power4.easeOut, y: 0});
$this.removeClass("closed");
$this.addClass("open");
}
// close the others
$(this).closest('.accordion').find('.section ul').not($content).each(function(){
TweenLite.to($(this), 0.8, {height:0, ease: Power4.easeOut, y: 0 });
});
});
I would suggest using CSS animation though, so you only have to toggle classes.

Stop scrolling display element after

I want to run progressbar animation with scroll.
But it runs several times instead of once
Excuse me if it's not correct.
Please help me.
My code is:
<div class="demo-5" data-percent="80">
<script>
$(document).ready(function(){
$(document).scroll(function(){
$('.demo-5').percentcircle({
animate : true,
diameter : 100,
guage: 3,
coverBg:'#fff',
bgColor: '#efefef',
fillColor: '#8BC163',
percentSize: '48px',
percentWeight: '50px'
});
});
});
</script>
progressbar
</div>
A scroll event triggered every time a user scrolls to a different place in the element. In practice, it'll be triggered once for a smooth scrolling action, however if the scroll is 'jerky' or several small scrolls are made, this will trigger a number of times.
Check this,
I haven't tested yet, but I hope it works,
$(document).ready(function(){
$(document).scroll(function(){
$('.demo-5').fadeIn(200);
$('.demo-5').percentcircle({
animate : true,
diameter : 100,
guage: 3,
coverBg:'#fff',
bgColor: '#efefef',
fillColor: '#8BC163',
percentSize: '48px',
percentWeight: '50px'
});
setTimeout(function()
{
$('.demo-5').fadeOut(1000);
}, 500);
});
});

Cross-dissolve transition for scrolled elements

I am creating a long single page website and using ScrollMagicJS v1.3.0 to trigger events and to make some elements sticky. I would like to create a variety of other transition effects as one scrolls down the page.
Here's a jsfiddle that replicates the horizontal scrolling of my site.
scrollControl = new ScrollMagic({
vertical: false,
});
var myScrollScene = new ScrollScene({
triggerHook: 0,
offset: 0,
triggerElement: '#shot-0-1',
duration: '100vw',
pushFollowers: true
})
.setPin('#shot-0-1')
.addTo(scrollControl);
For instance, I want to create fade-to-black, flare-to-white, and cross-dissolve transitions between pages.
I understand some of the basic principles of HTML5 transitions, how to make one image dissolve into another, but I haven't been able to figure out a clever way to do it using the ScrollMagic scrolling.
Things I've considered: The next page slides under the current page and then transitions from 1.0 to 0 opacity using ScrollMagic triggers?
But how to do it in a way non-hacky and consistent with ScrollMagic's framework?
This has been asked and answered in the ScrollMagic's issues section:
https://github.com/janpaepke/ScrollMagic/issues/269
here's a copy:
A common misconception is that you need to do everything with the ScrollMagic pin functionality.
If the content isn't moving within the scroll flow anyway (it stays in position and is faded out or moved to side or sth. like that) you can have it as "fixed" right from the beginning.
That saves a lot of work and confusion.
The only reason to use ScrollMagic's pinning functionality is when an element should sometimes scroll naturally with the DOM and sometimes it shouldn't.
So if you have elements that are in place and should just be replaced by others, have them fixed the whole time.
Like this: https://jsfiddle.net/janpaepke/6kyd6ss0/1/
If it is indeed a case were you should use ScrollMagic's pinning method, then do the animation inside of a wrapper, that you pin.
Like this: https://jsfiddle.net/janpaepke/6kyd6ss0/3/
 
Here's the solution I settled on.
scrollControl = new ScrollMagic({
vertical: false,
});
vw = $(window).width();
console.log("width:" + vw + "px");
// pin frame 2
var myScrollScene = new ScrollScene({
triggerHook: 0,
triggerElement: '#shot-2',
// This pin is considerably longer than average
offset: 0,
// duration = stickyLength + disolve_duration
duration: 1.5 * vw + 'px'
})
.setPin('#content-2', {
pushFollowers: false
})
.addTo(scrollControl)
.addIndicators({
zindex: 100,
suffix: 'pin2'
});
// move frame 3 up early and pin it
var myScrollScene = new ScrollScene({
triggerHook: 0,
triggerElement: '#shot-2',
offset: 0,
// duartion = 1.5, but why?
duration: 1.5 * vw + 'px'
// the faux pin doesn't actually expand the container the way SM does
// so the results are a little strange
})
.on("start end", function (e) {
$('#content-3').css({left: 0, position:'fixed'});
})
.on("enter leave", function (e) {
$('#content-3').css({left: 0, position:'relative'});
})
.addTo(scrollControl)
.addIndicators({
zindex: 100,
suffix: 'pin3faux'
});
var dissolve = TweenMax.to('#content-2', 1, {
autoAlpha: 0
});
// dissolve frame 2 to frame 3
var myScrollScene = new ScrollScene({
triggerHook: 0,
// Note that though we are fading frame 2, we are
// using the arrival of frame 3 the trigger
triggerElement: '#shot-2',
// The sets the rapidity of the dissolve
// offset = stickyLength
offset: 0.33 * vw + 'px',
// The sets the rapidity of the dissolve
duration: 1 * vw + 'px'
})
.setTween(dissolve)
.addTo(scrollControl)
.addIndicators({
zindex: 100,
suffix: 'dissolve'
});
I used a pushFollowers: false on a pin and z-index to slide the next frame (also pinned) behind the first. Then a Tween to dissolve into the second frame. The result is a nice cinematic dissolve feature with adjustable duration.
Hope it is useful to others.
https://jsfiddle.net/wmodes/b4gdxeLn/

Categories

Resources