Best way to animate object/image randomly around within a div? - reactjs

I have an animated gif, which I want to animate slowly and smoothly around. The gif needs to stay with the parent div. Which reactJS libraries would you suggest using for this task? As I guess it cannot be done only using CSS.

You may want to take a look at tutorials like this one:
https://css-tricks.com/bounce-element-around-viewport-in-css/
body {
margin: 0;
}
img, div {
width: 100px;
height: 100px;
}
.x {
animation: x 2.6s linear infinite alternate;
}
.y {
animation: y 0.8s linear infinite alternate;
}
#keyframes x {
100% {
transform: translateX( calc(100vw - 100px) );
}
}
#keyframes y {
100% {
transform: translateY( calc(100vh - 100px) );
}
}
<div class="x">
<img class="y" src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/ef/Stack_Overflow_icon.svg/768px-Stack_Overflow_icon.svg.png" alt="codepen" />
</div>

Related

Framer Motion - fade out element according to scroll position

Using framer motion, I am trying to fade in an object when it enters the viewport. Then I would like it to stay fixed for a while and eventually fade out.
So far I have only managed to fade the element in and fade it out when it leaves the viewport, which is too late. I was not able to figure out how to fix the element at a certain scroll position.
Here is what I have achieved:
This is what I am trying to achieve:
This is the Code Sandbox: https://codesandbox.io/s/vigorous-dawn-q4figi?file=/src/App.js
Here is the code:
export default function App() {
const [ref, inView] = useInView({
threshold: 0.5,
triggerOnce: false
});
const variants = {
visible: { opacity: 1, scale: 1, y: 0 },
hidden: {
opacity: 0,
scale: 0.65,
y: 50
}
};
return (
<div className="App">
<div style={{ height: 500 }} />
<motion.div
animate={inView ? "visible" : "hidden"}
variants={variants}
exit="hidden"
transition={{ duration: 2, ease: "easeOut" }}
className="box"
ref={ref}
/>
</div>
);
}
I would be very thankful for any kind of help!
You're almost there, just a couple of tweaks - mostly CSS for how you should position your animated element.
body {
margin: 0;
}
.App {
height: 300vh;
display: flex;
justify-content: center;
align-items: center;
background-color: #3b6fe0;
}
.box {
width: 200px;
height: 200px;
background-color: #fff;
border-radius: 20px;
}
Here's a full demo: https://codesandbox.io/s/flamboyant-sara-ce4pvx?file=/src/App.js
Note: it's a bit buggy to combine the useInView hook with the scale animation, as scaling the element will affect the in-view threshold. You could also consider use-scroll as an alternative, it may be harder to implement but provide more control over the animation.

How to loop a Draggable slider in React

I have a draggable horizontal slider in my current project and I would like to setting up it also to loop continuously. By loop continuously I mean it should respond to the process of showing images one after another when dragging? Right now, I do have only 3 images in my slider and when I drag slider to the left, slider with its 3rd image and a blank white space starts showing just after. Here at this point I want images to get start again continuously from the very beginning i.e. from the 1st image with aim to cover the white blank space.
Apart, one error I'm getting with my existing code is that when I start to drag slider to right side, suddenly a scroll comes up on browser and keep going in never ending state. By never ending state, I mean it still remain on screen when I drag all my 3 images fully in right direction.
So these are the two things I want to apply and want to resolve in my current project. I'm sharing my code below.
src > Routes > Home > Components > Carousel > Components > SliderDataItems > index.js
import React, { useRef, useEffect } from "react";
import { gsap } from "gsap";
import { Draggable } from "gsap/Draggable";
import { ZoomInOutlined } from '#ant-design/icons'
import { Images } from '../../../../../../Shared/Assets';
import ImagesIcon from '../../../../../../Components/Cells/ImagesIcon'
gsap.registerPlugin(Draggable);
const pictures = [
{
img: Images.xgallery1,
icon: <ZoomInOutlined />
},
{
img: Images.xgallery2,
icon: <ZoomInOutlined />
},
{
img: Images.xgallery4,
icon: <ZoomInOutlined />
},
];
const Slide = ({ img, icon }) => {
return (
<div className="slide">
<div className="image">
<ImagesIcon src={img} />
<div className="icon">
{icon}
</div>
</div>
</div>
);
};
export const Slider = () => {
const sliderRef = useRef(null);
useEffect(() => {
Draggable.create(sliderRef.current, {
type: "x"
});
}, []);
return (
<div className="slider" ref={sliderRef}>
{pictures.map((item, index) => {
return (
<Slide key={index} img={item.img} icon={item.icon} />
);
})}
</div>
);
};
export default Slider;
src > Routes > Home > Components > Carousel > style.scss
.slider {
display: flex;
cursor: unset !important;
overflow: hidden !important;
.slide {
.image {
position: relative;
img {
width: 100% !important;
height: auto !important;
object-fit: cover;
}
.icon {
transition: 0.5s ease;
opacity: 0;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%);
text-align: center;
span {
svg {
font-size: 30px;
color: #fff;
}
}
}
}
}
.image:hover .icon {
opacity: 1;
}
}
.image:after {
content: "";
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background: rgba(211, 208, 208, 0.6);
opacity: 0;
transition: all 0.5s;
-webkit-transition: all 0.5s;
}
.image:hover:after {
opacity: 1;
}
Here's the link of demo (kindly see just above the footer section) for your reference.
Thank you for any help.
For draggle Slider there is a very lightweight JS Carousel package - siema
It is a great, lightweight carousel that is made with JS. There are also other packages built on top of this purely made for React.
In your case, I would offer to try out react-siema.
With it, you can simply use the carousel like that and it will be draggable by default. Plus, no need to load any css.

Reactjs: Wait for animation to finish

inside my react app, users are able to enter data that is saved on the server. The data is saved immediatly, users don't have to press any "save" button. I want to display a short animation (similar to https://codepen.io/Sixclones/pen/VBdeXL) whenever I'm sending data to the server. After doing some research, I figured out that I should use react-transition-group (http://reactcommunity.org/react-transition-group/css-transition).
I made a component savingIcon:
const SavingIcon: React.SFC<SavingIconProps> = ({
className,
saving,
}) => {
return (
<div className={ classNames(className, "saving-icon") }>
<CSSTransition
timeout={ 200 }
classNames="saving"
in={ saving }
>
<div className="saving-balls">
<div className="saving-balls__item" />
<div className="saving-balls__item" />
<div className="saving-balls__item" />
</div>
</CSSTransition>
</div>
);
}
Whenever something is being saved, saving is set to true and I'd like to display the animation.
Inside saving-icon.scss I put the following CSS (I tried out several approaches, therefore there might be some unnecessary css):
#keyframes bouncing {
0% {
transform: translate3d(0, 10px, 0) scale(1.2, 0.85);
}
100% {
transform: translate3d(0, -20px, 0) scale(0.9, 1.1);
}
}
div.saving-icon {
position: sticky;
top: 15vh;
display: flex;
flex-direction: column;
justify-content: end;
height: 84vh;
$anim-drt: 0.4s;
$anim-ease: cubic-bezier(.6, .05, .15, .95);
.saving-enter {
div.saving-balls{
&__item {
background-color: $success-color;
transition: background-color 20ms;
}
}
}
.saving-enter-active {
div.saving-balls{
&__item {
background-color: $active-color;
transition: background-color 20ms;
}
&:nth-child(1) {
animation: bouncing $anim-drt alternate infinite $anim-ease;
transition: animation 1000ms;
}
&:nth-child(2) {
animation: bouncing $anim-drt $anim-drt/4 alternate infinite
$anim-ease backwards;
transition: animation 1000ms;
}
&:nth-child(3) {
animation: bouncing $anim-drt $anim-drt/2 alternate infinite
$anim-ease backwards;
transition: animation 1000ms;
}
}
}
.saving-exit {
div.saving-balls{
&__item {
background-color: $active-color;
transition: background-color 20ms;
}
&:nth-child(1) {
animation: bouncing $anim-drt alternate infinite $anim-ease;
transition: animation 1000ms;
}
&:nth-child(2) {
animation: bouncing $anim-drt $anim-drt/4 alternate infinite
$anim-ease backwards;
transition: animation 1000ms;
}
&:nth-child(3) {
animation: bouncing $anim-drt $anim-drt/2 alternate infinite
$anim-ease backwards;
transition: animation 1000ms;
}
}
}
.saving-exit-active {
div.saving-balls{
&__item {
background-color: $success-color;
transition: background-color 20ms;
transition: animation 1000ms;
}
}
}
div.saving-balls {
width: 3em;
height: 10vh;
z-index: 5;
display: flex;
justify-content: space-between;
align-items: center;
&__item {
width: 0.7em;
height: 0.7em;
border-radius: 50%;
background: $success-color;
}
}
}
My issue is the following:
Usually saving something only takes very short time; not enough time to actually run the animation once. My balls just become red for a split second and return being green (active and success color are some type or red and green). I would like to have the animation running a longer period of time, something around 2 seconds. I tried some hacks using effects, states and timeouts, but they didn't work well and I'd rather use a correct solution instead of some dirty hack.
I'm not very familiar with css transitions and animations, neither with react-transition-group. I hope for some existing easy way to play an animation for a certain minimum amount of time (if the connection is weak, the animation should show until the data is saved).
As an alternative, I accept different suggestions on how to tell the user that his input has been saved instead of an animation at the corner of the page. Currently, everything the user enters is saved, but he might not notice that this happened and search for a "save" button.
For anybody with a similar issue: I solved the issue by using useState and only changing the state value for saving if it indeed changed. I didn't use a transition group.
The working saving component:
const SavingIcon: React.SFC<SavingIconProps> = ({
className,
saving,
}) => {
const [ isSaving, setIsSaving ] = useState(false);
useEffect(() => {
if (isSaving !== saving) setIsSaving(saving);
}, [ saving ]);
return (
<div className={ classNames(className, "saving-icon", {
"saving-active": isSaving
}) }>
<div className="saving-balls">
<div className="saving-balls__item" />
<div className="saving-balls__item" />
<div className="saving-balls__item" />
</div>
</div>
);
}
scss:
#keyframes bouncing {
0% {
transform: translate3d(0, 10px, 0) scale(1.2, 0.85);
}
100% {
transform: translate3d(0, -20px, 0) scale(0.9, 1.1);
}
}
div.saving-icon {
position: fixed;
top: 86px;
right: 1.3vw;
$anim-drt: 0.4s; /* duration */
$anim-ease: cubic-bezier(.6, .05, .15, .95);
&.saving-active {
div.saving-balls {
div.saving-balls__item {
background-color: $active-color;
transition: background-color 20ms;
&:nth-child(1) {
animation: bouncing $anim-drt alternate infinite $anim-ease;
}
&:nth-child(2) {
animation: bouncing $anim-drt $anim-drt/4 alternate infinite
$anim-ease backwards;
}
&:nth-child(3) {
animation: bouncing $anim-drt $anim-drt/2 alternate infinite
$anim-ease backwards;
}
}
}
}
div.saving-balls {
width: 3em;
height: 30px;
z-index: 5;
display: flex;
justify-content: space-between;
align-items: center;
&__item {
width: 0.7em;
height: 0.7em;
border-radius: 50%;
background: $success-color;
}
}
}

Trying to use ReactCSSTransitionGroup for a Singleton

I'd like to move something bottom: +/- 100px.
So that when focused, it slides up. When unfocused, it slides back down.
I've created this React render() :
var component = (
<div key={"trayResponder_" + this.props.trayOpen} >
</div>
);
return(
<ReactCSSTransitionGroup transitionName="tray-responder">
{component}
</ReactCSSTransitionGroup>
);
And then I toggle it's key state, by updating this.props.trayOpen
And then my Less is like this :
.tray-responder-enter {
}
.tray-responder-enter-active {
.animation(slideUp 1s ease infinite )
}
.tray-responder-leave {
}
.tray-responder-leave-active {
.animation(slideDown 1s ease infinite )
}
.keyframes(slideUp;{
0% {transform: translateY(100%);}
50% {transform: translateY(-8%);}
65% {transform: translateY(4%);}
80% {transform: translateY(-4%);}
95% {transform: translateY(2%);}
100% {transform: translateY(0%);}
});
.keyframes(slideDown;{
0% {transform: translateY(-100%);}
50%{transform: translateY(8%);}
65%{transform: translateY(-4%);}
80%{transform: translateY(4%);}
95%{transform: translateY(-2%);}
100% {transform: translateY(0%);}
});
Which adopts from animation.less :
.keyframes(#name; #arguments) {
#-moz-keyframes #name { #arguments(); }
#-webkit-keyframes #name { #arguments(); }
#keyframes #name { #arguments(); }
}
.animation(#arguments) {
-webkit-animation: #arguments;
-moz-animation: #arguments;
animation: #arguments;
}
Unfortunately, this doesn't seem to work. Nothing occurs. No animation. Not really sure why.
Update
The trouble with ReactCSSTransitionGroup is that enter-active and leave-active occur simultaneously. Which doesn't seem to be a problem if you're toggling opacity. But if you're moving things up and down like I am, then you see both at the same time.
As seen here :
As much as I understand, CSS Transition is for enter and leave. You want animation on hover, which can probably be achieved by using :hover selector.
const TransitionDemo = React.createClass({
render : function () {
return(
<div className="demo">
<p>Some Text Here</p>
</div>
);
}
});
ReactDOM.render(<TransitionDemo trayOpen={1}/>, document.getElementById('root'));
//css
.demo {
height : 100px;
position : relative;
}
.demo p {
position : absolute;
bottom : 0px;
transition : all 1s ease;
}
.demo:hover > p{
bottom : 50px;
transition : all 1s ease;
}
See this pen : http://codepen.io/umgupta/pen/dNNLxL

AngularJS 1.2 fade animation from 0 to 0.5 not working

So I have this simple fade animation using AngularJS 1.2 and the ngAnimate module but I'm having a small issue.
I want to show/hide an element with a fade animation but I want the element to fade from opacity: 0 to opacity: 0.5. The thing is, the element fades from 0 to 0.5 within the duration period I set, but after the animation ends, it sets the opacity to 1. I don't want that.
This is my CSS code:
.overlay {
background-color: #ff0000;
position: absolute;
width: 150px;
height: 150px;
}
.fade-animation.ng-hide-add, .fade-animation.ng-hide-remove {
transition: 2s linear all;
display: block !important;
}
.fade-animation.ng-hide-remove {
opacity: 0;
}
.fade-animation.ng-hide-remove.ng-hide-remove-active {
opacity: .5;
}
.fade-animation.ng-hide-add {
opacity: .5;
}
.fade-animation.ng-hide-add.ng-hide-add-active {
opacity: 0;
}
Here's a sample of the problem: http://jsfiddle.net/Kn3th/8/
I'm testing this on Firefox.
That's because as soon as the animation completes, the animation-related classes are removed, so only the .overlay definition applies. Just add this to your CSS:
.overlay {
...
opacity: .5; // <-- add this line to apply an opacity of 0.5
} when the animation is over
See, also, this short demo.

Resources