Reputation: 936
What i am trying to build is a vertical timeline component with some animation. The animation which am trying is that it starts from the first circle, whichever item has status true the vertical line will draw from top to bottom meanwhile whichever steps gets completed will change from round circle to completed checkmark when the line crosses it.
How can I achieve the above animation on this, I have tried so far but didn't know how to achieve the above.
What am i trying to achieve this
Any help is appreciated.
Upvotes: 4
Views: 2490
Reputation: 18438
I've modified your sandbox to make it work:
https://codesandbox.io/s/animable-timeline-reactjs-tiofz
For animation I used following CSS:
div {
height: 200px;
width: 10px;
}
.green-progress {
background: linear-gradient(0, #00a36c, #00a36c) no-repeat, #ccc;
background-size: 100% 0;
animation: progressAnim 3s linear infinite forwards;
}
@keyframes progressAnim {
0% {
background-size: 100% 0;
}
100% {
background-size: 100% 100%;
}
}
<div class="green-progress"></div>
Converted App
to stateful component so that we can maintain animation states.
In constructor, for each entry added id
, startAnim
, and checked
state. Here, we'll set startAnim
flag to start animation on corresponding TimelineConnector. and checked
is used to control checkmarking the circle.
In TimelineConnector
set class to green-progress if this.props.startAnim
is true. Also added onAnimationEnd
handler as {() => this.props.onAnimDone(this.props.id)}
. This tells App component that animation is done on this component with id
.
In TimelineDot
used props.event.checked
to set the checked status.
In App added a lifecycle hook componentDidMount
which will get called when all components gets added to actual DOM. In the hook you checkmark the first circle and start animation on first TimelineConnector.
When TimelineConnector is done with the animation, it calls startNextAnim
in the App. In the method you first complete the checkmark on last entry. And start next animation if the entry has status:true
.
Upvotes: 2
Reputation: 349
You can try this
/* timeline css */
@keyframes fill-color {
0% {
height: 0;
}
100% {
height: 100%;
}
}
@keyframes fill-color1 {
0% {
height: 0;
}
100% {
height: 50%;
}
}
@keyframes scaleup {
0% {
transform: scale(0);
}
100% {
transform: scale(1);
}
}
@keyframes fade {
0% {
color: rgba(black, 0.4);
}
100% {
color: rgba(black, 1);
}
}
body {
margin: 0;
padding: 0;
}
.timeline {
padding: 0;
list-style: none;
margin: 32px;
overflow: hidden;
position: relative;
}
.details {
margin-left: 48px;
border-bottom: 1px solid #f2f2f2;
min-height: 85px;
display: flex;
justify-content: center;
flex-direction: column;
}
.list,
.list-content {
position: relative;
width: 100%;
}
.list-content::before,
.list-content::after {
content: "";
display: block;
position: absolute;
left: 0;
transition: 0.2s all linear;
width: 0.714rem;
height: 0.714rem;
border-radius: 50%;
background-color: gray;
top: 50%;
z-index: 3;
margin-left: 0.35rem;
margin-top: rem(-8px);
}
.list-content::after {
z-index: 2;
}
.list {
position: relative;
width: 100%;
}
.list.active .list-content:before {
transform: scale(0);
width: 17px;
height: 17px;
border: 2px solid white;
background-color: red;
background-image: url("https://upload.wikimedia.org/wikipedia/commons/thumb/2/27/White_check.svg/2048px-White_check.svg.png");
background-position: center;
background-repeat: no-repeat;
background-size: 9px 7px;
margin-left: 0;
margin-top: -8px;
animation: scaleup 0.4s forwards;
}
.list:before,
.list:after {
content: "";
display: block;
position: absolute;
left: 0;
transition: 0.2s all linear;
width: 0.214rem;
margin-left: 0.6rem;
}
.list:before {
background: #f2f2f2;
height: 100%;
}
.list:after {
background: red;
height: 0;
z-index: 1;
}
.list:before {
top: -50%;
}
.list.active:after {
top: 0;
animation: fill-color 0.4s forwards;
}
.list:last-child:after {
display: none;
}
.list:last-child.active:after {
display: block;
bottom: 50%;
animation: fill-color1 0.4s forwards;
}
.list:last-child .details {
border-bottom: none;
}
.list:first-child:before {
display: none;
}
.list:first-child.active:after {
animation: fill-color1 0.4s forwards;
top: 50%;
}
.list:first-child.active:after {
animation-delay: 1s;
}
.list:first-child.active .list-content:before {
animation-delay: 0.5s;
}
.list:nth-child(2).active:after {
animation-delay: 2s;
}
.list:nth-child(2).active .list-content:before {
animation-delay: 2s;
}
.list:nth-child(3).active:after {
animation-delay: 3s;
}
.list:nth-child(3).active .list-content:before {
animation-delay: 3s;
}
.list:nth-child(4).active:after {
animation-delay: 4s;
}
.list:nth-child(4).active .list-content:before {
animation-delay: 4.15s;
}
<body>
<ul class="timeline">
<li class="list active">
<div class="list-content">
<div class="details">
<h4 class="status-title">Step 1</h4>
</div>
</div>
</li>
<li class="list active">
<div class="list-content">
<div class="details">
<h4 class="status-title">Step 2</h4>
</div>
</div>
</li>
<li class="list active">
<div class="list-content">
<div class="details">
<h4 class="status-title">Step 3</h4>
</div>
</div>
</li>
<li class="list active">
<div class="list-content">
<div class="details">
<h4 class="status-title">Step 4</h4>
</div>
</div>
</li>
</ul>
</body>
you can also check on Sandbox
here I have added active
class in all li
elements but if you want to two steps active so apply only first two li (i.e that class is conditional)
Upvotes: 1
Reputation: 744
It's possible to animate a background. Please check the example below
.bg {
min-height: 300px;
width: 10px;
background: linear-gradient(0, red, red) no-repeat;
background-size: 100% 0;
animation: gradient 15s ease infinite;
}
@keyframes gradient {
0% {
background-size: 100% 0;
}
100% {
background-size: 100% 100%;
}
}
<div class="bg"></div>
Your TimelineConnector could be updated with include of that CSS class.
Upvotes: 0