multiple animations (timeline) in react-spring - reactjs

I have a component with 2 Boxes and a shadow:
First Box is outside the view: topBox
Second Box is inside the view at the bottom: middleBox
Third is the shadow of the Box on the bottom (a png): Shadow
If i start the animation (or if the component loads) i want to have the following animation:
Step 1
middleBox move up 50px
shadow grows (from scale(0.8) to scale(1))
Step 2
topBox moves down 50px into the view
Step 3
(this animation should look like the two boxes smash into each other, like if if they would crash. like two balls hitting each other and go back to origin.)
middleBox moves up 20px and back down 20px
topBox moves down 20px and back up 20px
Shadow scales 1.1 and back to 1
Step 4
topBox moves back outside the view
So i created useSprings for all steps and i tried to update state when the first animation finished based on this update the other animation. i also tried with useChain to have the animations together. But nothing seems to work.
so i would have state
const [isAnimationMove, setAnimationMove] = useState(true)
const [isAnimationHit, setIsAnimationHit] = useState(false)
and then change the state after the second animation finishes to trigger the new animations
const topBoxMoveDown = useSpring({
from: { transform: 'translate(-20%, 100%)' },
transform: 'translate(-10%, 60%)',
onRest: () => {
setAnimationMove(false);
setIsAnimationHit(true);
}
and render the different animation on the element
<BoxFromTop
animationStyle={
isAnimationMove ? topBoxMoveDown :
isAnimationHit ? topBoxHit : null } />
which is
const topBoxHit = useSpring({
from: { transform: 'translate(-10%, 60%) rotate(0)' },
transform: 'translate(-10%, 55%) rotate(10deg)',
reset: true,
});
However it works kind of as long as i would not use transform again in the topHitBox but i think my question is more about the concept in general:
How do i animate different states and have control over what starts when and what follows what. I mean i just be a simple animation with multiple steps but i can not get my head around how this works with react-spring. Am i using the wrong library? is there a better one to use for this? or did i just use the wrong approach?

Related

Why Does Text Blur on 3D Rotation in React?

I'm creating an image carousel for React that I style and rotate using the code found here: https://3dtransforms.desandro.com/carousel
When I first load the carousel things are nice and clear, but as soon as I rotate it, everything blurs (even once motion has stopped), except the item in the original 0-degree position when it finally rotates back around to the front. I tried using -webkit-filter: blur(0); but that doesn't have an impact. Any idea how I can avoid the text blurring?
Before:
After:
I've isolated it to this transform call:
transform: rotateY( ${(props : any) => props.yAngle}deg ) translateZ(${(props : any) => props.zAmount}px)
Since if I put 0 for the props.yAngle everything is clear but if there's any degree that's not zero there, it all becomes blurred.

nganimate leave taking too long

I'm using angular-ui-modal, which automatically applies nganimate classes when opening and closing a modal. This is causing all sorts of problems, not least the fact that the backdrop takes a while to be removed from the dom after my custom css transition has finished. It's hard to reproduce but basically I have the following SASS:
.modal-backdrop{
background-color: black;
opacity: 0;
transition: all 4s ease-out;
&.in{
opacity: 0.8;
}
}
When the in class is added, the backdrop fades in, but when the modal is closed the backdrop fades but stays in the dom with the "in-remove in-remove-active" classes for a while then the "ng-leave ng-leave-active" classes applied until it's removed.
I can't seem to work out how it calculates how long to wait before removing from the dom but it seems related to the transition time, putting it up to 4 seconds seemed to make it wait around 6 seconds in the in-remove stage and 6 seconds in the ng-leave stage. Reducing the transition time to 1 second made it wait about 2 seconds in each stage.
The ng-animate stuff seems completely removed from the ui-modal stuff. Like a black box you can't get into. ui-modal doesn't seem to have any settings to change the time that animations take so I can only assume it's incorrectly calculating it by looking at my css.
I found two workarounds.
1) use pointer-events none to stop the blocking of the ui, as discussed here -https://github.com/angular-ui/bootstrap/issues/5407
2) Use the JavaScript animation hooks. This wasn't working until a recent update but they say it is now fixed. Code would look like this...
angular.module('app').animation('.modal', [function() {
return {
enter: function(element, doneFn) {
console.log("entering");
$(element).css({
'opacity': '0',
'background-color': 'black'
}).animate({
opacity: 0.6
}, 200, doneFn);
},
leave: function(element, doneFn) {
console.log("leaving");
$(element).animate({
opacity: 0
}, 200, doneFn);
}
}
}]);
Sorry for the formatting, looks like you can't format code easily on mobile version of Stack Overflow.

Creating an animated 1-3 column layout using Angular

Here's the situation:
I'm building a page for an application which consists of a navbar, a footer and a 3 column body.
Initially, only one column should be shown. This first column will be filled with clickable divs (let's call them cards). When one of these cards is clicked, the second column should slide open from the side, revealing more information about the clicked card.
The same workflow applies to the second column: the details displayed in the second column contains its own cards, which - when clicked - open up the third column with more details about the card in the second column.
The second and third column can also be closed, while the first can not.
I'm loading the column information using Angular, and so far I've had no real struggle implementing the 1-3 column layout.
But when I try to make this work smooth - e.g. using animations - things get weird. I don't really know how I can animate the (dis)appearance of one of each columns.
Here's what I have so far: Codepen example
<div class="container" ng-controller="Controller as ctrl">
<div class="column" ng-repeat="column in ctrl.columns" ng-class="[column.mode, column.color]" ng-show="column.open">
<button ng-click="ctrl.close(this)" ng-show="column.id != 0">Close</button>
<p ng-click="ctrl.open(this)">Name: {{column.name}}</p>
<p>Open: {{column.open}}</p>
<p>Mode: {{column.mode}}</p>
<p>Color: {{column.color}}</p>
</div>
</div>
CSS:
.container {
height: calc(100% - 50px);
display: flex;
}
.column {
padding: 10px 0 0 10px;
overflow-y: auto;
}
.column-narrow {
flex: 33;
}
.column-wide {
flex: 66;
}
.column-full {
flex: 100;
}
The second and third column can be triggered by clicking the name paragraph.
Don't worry about the colors, they're definitely not final and are used only for a clear visual difference between containers etc.
Can any one of you offer me a CSS(3) solution to this? If my code can be optimised please do, as I'm currently learning Angular.
There is not a lot of code needed to get some basic animations working.
The ng-show and ng-hide directives already provide support for animations out of the box. That means that AngularJS will add animation hooks in the form of additional classes ng-hide-add, ng-hide-add-active, ng-hide-remove, ng-hide-remove-active.
So these classes get added to your CSS column.
I literally only had to add these CSS lines to make animations work in your Codepen.
.column.ng-hide-add.ng-hide-add-active,
.column.ng-hide-remove.ng-hide-remove-active {
-webkit-transition: all linear 0.5s;
transition: all linear 0.5s;
}
Here is the updated codepen:
http://codepen.io/anon/pen/XbVLxO

ngAnimate not adding classes to image gallery using ngRepeat

Demo: http://plnkr.co/edit/gehNa1s62ipRcny5Uzkj?p=preview
I'm attempting to make my image gallery animate when you hit the left/right arrows. Ideally, they would work like they do here.
I tried doing this:
.gallery-image {
opacity: 1;
&.ng-enter {
transition: transform 0.5s;
opacity: 0;
}
&.ng-enter-active {
opacity: 0.5;
}
}
But it just seems like ngAnimate doesn't want to add any classes to my elements on the DOM. My repeater is declared like this:
<img class="gallery-image"
ng-repeat="image in images | limitTo:3:currentIndex-1"
ng-show="$index+currentIndex-1 >= 0 && $index+currentIndex-1 < images.length"
ng-src="{{images[$index+currentIndex-1].url}}" />
So what I do is just change the current index I'm looking at, and that adjusts what images are visible.
The weird thing is, if you resize the plunk (sm to md, md to lg) you can see the images very clearly animating.
Why isn't ngAnimate adding any classes to my DOM?
It seems that ngAnimate will not do anything unless you actually modify the underlying array. The solution here is to keep a list of "visible" items, and modify that, instead of basing everything off of the currently visible index.

What's a good way to move items in an list with AngularJS and ng-animate?

I want to be able to reorder a list, right now I have buttons on each item to move them up and down the list. I want to use ng-animate to make the items move smoothly, but I can only find the -move animation, and that apparently only works on the top element of the two that are switching places. I can't get it to look right. Here's what I have so far: Fiddle
.person-move {
transition: all 0.5s;
position: relative;
height: 0;
}
.person-move.person-move-active {
height: 26px;
overflow: hidden;
}
I guess I'm not sure of the purpose of -move. I'm swapping the places of two people, but it only seems to affect the top one. I'd like it to look like they are being swapped. in the sample fiddle there's a checkbox to create new objects instead of moving existing ones to fire -enter and -leave, maybe I could combine the two methods:
use -move for the top person (who used to be below), animating relative position upwards
use -enter for the bottom person by creating a new object, animating relative position
Is there an easier or better way to do this?
Other thoughts:
Something like jquery-ui's drag and drop would be nice, but I don't want to have to include it and find out if I can get it to work with AngularJS.
After a lot of messing around, I got it to work the way I wanted using the CSS next sibling selector, +: (Fiddle)
.person-move {
position: relative;
top: 26px;
}
.person-move.person-move-active {
transition: all 0.5s ease;
top: 0;
}
.person-move + div {
/* cannot have transition on this element */
/*transition: all 1s ease;*/
position: relative;
top: -26px;
}
.person-move.person-move-active + div {
transition: all 0.5s ease;
position: relative;
top: 0;
}
The key was to have the transition style only on the active class selectors. The examples I've seen like on yearofmoo have them on the base classes which I can't see any reason for since those are there solely to set up the initial condition for the animation I believe. Chrome doesn't like it anyway and tries to animate to the initial condition when using the sibling selector.

Resources