How can I remove a class *after* a GSAP timeline animation finishes? - javascript

I've created a simple GSAP timeline animation to slide a fullscreen div over the entire viewport.
Because the page that it's going to be sliding in over has scrollable content on it, I've set the visibility to hidden, and pushed it off of the page. When I click the selected nav link, the class of "active" is added and the animation fires.
For some reason, when I reverse it, it removes the class immediately, even if I add something like this:
$(closeAbout).on('click', "#close", function () {
timeline.reversed() ? timeline.play() : timeline.reverse();
$("#teambio").removeClass('active');
});
I've included all of the timeline code below, in case that's helpful to anyone:
var closeAbout = $('#close');
var openAbout = $('#about');
var main = $('main');
var timeline = new TimelineMax({
paused: true,
reversed: true
});
timeline
.to( "main", 0.3, {
opacity: 0,
}, 0)
.to(".about", 1, {
y: "0%",
ease: Power4.easeInOut
})
.to(".blurb", 1, {
y: "0%",
opacity: 1,
ease: Power4.easeInOut,
delay: 0.5
}, 0)
.to("#close", 0.5, {
opacity: 1,
ease: Power4.easeInOut,
delay: 0.8,
}, 0);
$(openAbout).on('click', "#about", function () {
$("#teambio").addClass('active');
timeline.reversed() ? timeline.play() : timeline.reverse();
});
$(closeAbout).on('click', "#close", function () {
timeline.reversed() ? timeline.play() : timeline.reverse();
$("#teambio").removeClass('active');
});
All I want is for the class to be removed AFTER the timeline finishes, and for some reason nothing that I've tried is working.
Also, I know that I could probably structure and name all of this better than it appears here, but I'm both new to GSAP and also just trying to get this to work.
Any help and patience would be greatly appreciated.

With something like this:
timeline.reversed() ? timeline.play() : timeline.reverse();
$("#teambio").removeClass('active');
The .play() or .reverse() function will run and start animating. Once that function returns, the next line will run, removing the class. You wouldn't want the next line to wait for the animation to complete because then all of your JavaScript would be waiting for the animation to complete!
What you should do instead is make use of GSAP's onComplete callback:
var timeline = new TimelineMax({
paused: true,
reversed: true,
onComplete: function() {
$("#teambio").removeClass('active');
}
});
GSAP will fire that function every time the tween completes.
By the way, we recommend that you upgrade to GSAP 3 doing so is easy! The new formatting is quite nice once you're used to it.

Related

velocity stagger with own function

I switched from anime.js to velocity.js and try to defnine a simple animation with delayed opacity. For this I use the stagger.
But if I put a function for the stagger delay in it, I have no delayed stag animation. every elemenet is popping up but not animated and delayed.
In the first i tried what I have used for the animation with anime.js and the second one is directly from the github issue.
Here is also my jsbin:
https://jsbin.com/firetuh/edit?html,css,js,output
var greenElem = $('.pointGreen');
var yellowElem = $('.pointYellow');
var redElem = $('.pointRed');
setInterval(function() {
greenElem
.velocity({
fill: '#5cb83f',
opacity: 1
}, { stagger:
function(elem, index) {
return index * 500
}
});
yellowElem
.velocity({
fill: '#feb65c',
opacity: 1
}, { stagger:
function(elementIndex, element) {
return 1000 * (0.85 - Math.exp(-elementIndex/10));
}
});
redElem
.velocity({
fill: '#d43f3a',
opacity: 1
}, { stagger: 500 });
});
It looks like this could be either an intentional oversight or a bug with velocity. It looks like from the code that stagger only works if the first value passed in is a pre-canned effect like fadeIn or transition.slideLeftIn - it doesn't look like it is supported for other animation types. You could, in theory, achieve this on your own with something like
yellowElem
.each(function(index, element) {
$(element).velocity({
fill: '#feb65c',
opacity: 1
},{
delay: index * 500
});
});
Also, you will want to change your setInterval to setTimeout

Swipe element down and up to delete/remove element using hammer.js and jQuery?

I'm trying to swipe an element up/down to delete it.
I am using hammer.js and jQuery.
So far I can delete the element using swipe left/right which works fine.
But I need to achieve the exact same thing using swipe up/down.
I have created this working example here:
https://codepen.io/anon/pen/YJPPyB
click on the button and an element will appear and then Swipe left/right to delete it.
With the code above, I tried the followings but it doesn't work as expected:
$toast.animate({ top: event.deltaX, opacity: opacityPercent }, { duration: 50, queue: false, specialEasing: 'easeOutQuad' });
and
$toast
.removeClass('panning')
.animate({ bottom: 0, opacity: 1 }, {
duration: 300,
specialEasing: 'easeOutExpo',
queue: false
});
Can someone please advice on this issue?
Thanks in advance.
EDIT:
When I change this:
hammerHandler.on('pan', function (event) {
To this:
hammerHandler.on('pandow', function (event) {
I can move the element when I pandown but I dont know why it is very wonky!
This is how I swipe down now but it somtimes freezes the whole page and I dont undertand why!
hammerHandler.on('pandown', function (event) {
// Change toast state
$toast.addClass('panning');
var opacityPercent = 1 - Math.abs(event.deltaX / activationDistance);
if (opacityPercent < 0)
opacityPercent = 0;
$toast.animate({ marginBottom: event.deltaX, opacity: opacityPercent }, { duration: 50, queue: false, specialEasing: 'easeOutQuad' });
});

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/

How to replace a CSS3 transition

I'm trying to apply a CSS transition to an element, but at some point before it completes, remove the transition entirely and start another one.
This question answers how to stop a transition in its tracks, but I modified the jsFiddle there to illustrate the issue:
http://jsfiddle.net/zXVLd/
var $div = $('div');
$div.click(function(){
$div.css({
left: 0,
transition: 'none'
});
$div.transit({
top: 600,
},5000);
});
function complete(){
$div.css('backgroundColor', 'blue');
}
$div.transit({left: 600}, 5000, 'linear', complete);
What I want to happen is for the box to reset its position and move down when clicked, and for the completed handler on the first transition to not fire.
What does happen is the box resets its position when clicked, but doesn't move down until the first transition completes (even though the motion from the first transition is no longer happening). The completed handler still fires on the first transition as well.
I've updated your fiddle with the clearQueue method: http://jsfiddle.net/zXVLd/1/
var $div = $('div');
$div.click(function(){
$div.clearQueue().css('left', $div.css('left')).transit({
top: 600,
},5000);
});
function complete(){
$div.css('backgroundColor', 'blue');
}
$div.transit({left: 600}, 5000, 'linear', complete);
That does the trick. See http://api.jquery.com/clearQueue/ for more information on the clearQueue method.
To do this kind of animations, you can try to use GSAP's TweenLite. It's incredible what you can achieve with it. http://www.greensock.com/jump-start-js/ If you include this on your page and add the following code:
div.bind('click', function(e) {
// note that you can animate two directions, from and to
TweenLite.from(div /*element*/, 0.2 /*easing in seconds*/, {
// the css, but for positioning elements you can also use x and y.
x: 600,
easing: linear,
onStart: function() {
Stuff you want to do before the animation
},
onComplete: function() {
Stuff you want to do after animationg
}
});
});
The plugin which you use is using queue. So, it is just enough to call $div.dequeue(); I.e.
var $div = $('div');
$div.click(function(){
$div.dequeue();
$div.css({
left: 0,
top: 0,
transition: 'none'
});
$div.transit({
top: 600,
},5000);
});
function complete(){
$div.css('backgroundColor', 'blue');
}
$div.transit({left: 600}, 5000, 'linear', complete);
fiddle -> http://jsfiddle.net/krasimir/zXVLd/2/

JQuery Tools Multiple Overlay

I am having a slight issue with Overlay (JQuery Tools) - what I need to do is allow people to click on another overlay from overlay.
The problem is that the overlay opens behind the already active overlay, which causes issues because I need it to load in front of the open overlay.
Does anyone know how I can load multiple overlay's but make sure the last overlay loads in-front?
This is the code I am using ...
/
/ select the overlay element - and "make it an overlay"
$("#overlay").overlay({
// custom top position
//top: 200,
// some mask tweaks suitable for facebox-looking dialogs
mask: {
// you might also consider a "transparent" color for the mask
color: '#fff',
// load mask a little faster
loadSpeed: 200,
// very transparent
opacity: 0.8
},
// disable this for modal dialog-type of overlays
closeOnClick: true,
// load it immediately after the construction
load: false,
oneInstance: false
});
// Modal on click
$("a[rel]").overlay({
// disable this for modal dialog-type of overlays
closeOnClick: true,
top: '3%',
mask: {
color: '#fff',
loadSpeed: 200,
opacity: 0.8
},
onBeforeLoad: function() {
// grab wrapper element inside content
var wrap = this.getOverlay().find(".contentWrap");
// load the page specified in the trigger
wrap.load(this.getTrigger().attr("href"));
},
oneInstance: false
});
I am using this to open the second overlay ..
Link
Thanks.
I had a similar problem and I solved it by setting the z-index property for all involved elements. Very important to realize here is that if you use a mask you need to set the z-index of that mask too!
For example:
$('#some_overlay_element').overlay({
mask: {
maskId: "defaultMask" ,
color: null ,
zIndex: 9001
},
effect: "apple",
zIndex: 9100
});
You can use this code to open multiply overlay, or overlay over overlay with different mask.
For Example:
//Global Variable//
var zindx=99999;
var mask_Zindex=99990;
//Code to open the Overlay//
$("yourDynamicID").overlay({
effect: 'apple',
oneInstance:false,
closeOnClick: false,
closeOnEsc: false,
zIndex: ++zindx,
api: true,
load: true,
onBeforeLoad: function () {
var wrap = this.getOverlay().find(".contentWrap");
wrap.load(this.getTrigger().attr("href"));
},
onLoad: function(){
if($.mask.isLoaded()) {
//this is a second overlay, get old settings
oldMaskZ[counters] = $.mask.getConf().zIndex;
$oldMask[counters] = $.mask.getExposed();
$.mask.getConf().closeSpeed = 0;
$.mask.close();
counters++;
this.getOverlay().expose({
color: 'darkgrey',
zIndex: mask_Zindex,
closeOnClick: false,
closeOnEsc: false,
maskId: maskID,
loadSpeed: 0,
closeSpeed: 0
});
}else{
this.getOverlay().expose({
color: 'darkgrey',
zIndex: mask_Zindex,
maskId: maskID,
closeOnClick: false,
closeOnEsc: false
});
}
//Other onLoad functions
},
onClose: function(){
counters--;
// $.mask.close();
//re-expose previous overlay if there was one
if($oldMask[counters] == null){
$.mask.close();
}
}
});
I am having a different but similar problem and ran into the following potential solution:
http://sdevgame.wordpress.com/2011/01/26/modal-on-modal-with-jquery-tools/
I have not yet tried it.
Though this the question is not fresh - there may be some toolbox users out there with the same problem.
I'm using a very simple hack. Just wait for a milisecond allowing the overlay to be set up correctly then I'm changing the z-index. Simple as pie:
window.setTimeout(function(){
$("#YourSecondOverlayIdName").css("z-index", "11000");
},60);

Categories

Resources