Reputation: 2434
I am developing a ReactJs
app, I need to animate a bus in a visual path.
The bus should make stops. So the bus first go from A -> B , then when the user click a button it goes from B -> C , ect..
I have already made the animations and the logic
.bus_0 {
animation: move 3s linear forwards;
}
.bus_1 {
animation: move2nd 3s linear forwards;
}
@keyframes move {
20% {
transform: translate(50px, 0px);
}
40% {
transform: translate(50px, 0px) rotate(-90deg);
}
80% {
transform: translate(50px, -130px) rotate(-90deg);
}
100% {
transform: translate(50px, -125px) rotate(0deg);
}
}
@keyframes move2nd {
20% {
transform: translate(100px, 0px);
}
40% {
transform: translate(100px, 0px) rotate(-90deg);
}
100% {
transform: translate(100px, -50px) rotate(-90deg);
}
}
Here I add classNames
based on an index
let bus = document.getElementById('bus');
bus && bus.classList.add(`bus_${data.selectedIndex}`);
The problem is when the first animation starts, the bus reachs point B , but for the second animation , it starts from point A.
Example the bus first position (0, 0), after the first animation (100, 100), when the second animation plays it start from (0, 0) but i need it the start from the last position reached.
Upvotes: 0
Views: 524
Reputation: 1170
There must be a better way probably but that is what i got and i think it will solve your problem
So i collect boxes x and y coordinates when animation button clicks and after the animationend event, i collect both x and y coordinates again and calculate difference of them and add to box style.
const firstButton = document.querySelectorAll('button')[0];
const secondButton = document.querySelectorAll('button')[1];
const myBox = document.querySelector('div')
let rectBefore;
let rectAfter;
let positionBeforeX;
let positionBeforeY;
let positionAfterX;
let positionAfterY;
let differenceX;
let differenceY;
firstButton.addEventListener('click', () => {
rectBefore = myBox.getBoundingClientRect();
positionBeforeX = rectBefore.left;
positionBeforeY = rectBefore.top;
myBox.classList.toggle('first');
})
secondButton.addEventListener('click', () => {
rectBefore = myBox.getBoundingClientRect();
positionBeforeX = rectBefore.left;
positionBeforeY = rectBefore.top;
myBox.classList.toggle('second');
})
myBox.addEventListener('animationend', (event) =>{
rectAfter = myBox.getBoundingClientRect();
positionAfterX = rectAfter.left;
positionAfterY = rectAfter.top;
differenceX = positionAfterX - positionBeforeX;
differenceY = positionAfterY - positionBeforeY;
if(myBox.style.left !== ""){
myBox.style.left = `${parseInt(myBox.style.left.split('px')) + differenceX}px`;
myBox.style.top = `${parseInt(myBox.style.top.split('px')) + differenceY}px`;
}
else{
myBox.style.left = `${differenceX}px`;
myBox.style.top = `${differenceY}px`;
}
myBox.classList.remove(`${event.animationName}`);
})
*,
*::before,
*::after {
box-sizing: border-box;
}
body{
min-height: 100vh;
position: relative;
display: grid;
place-content: center;
}
button{
position: absolute;
background-color: greenyellow;
width: 5rem;
height: 5rem;
}
button:nth-of-type(1){
top:5rem;
right: 10rem;
margin-right: 1rem;
}
button:nth-of-type(2){
top:5rem;
right: 5rem;
}
.box{
position:relative;
width: 100px;
height: 100px;
background-color: blue;
}
.first {
animation: first 3.0s linear forwards;
}
.second {
animation: second 3.0s linear forwards;
}
@keyframes first {
20% {
transform: translate(50px, 0px);
}
40% {
transform: translate(50px, 0px) rotate(-90deg);
}
80% {
transform: translate(50px, -130px) rotate(-90deg);
}
100% {
transform: translate(50px, -125px) rotate(0deg);
}
}
@keyframes second {
20% {
transform: translate(100px, 0px);
}
40% {
transform: translate(100px, 0px) rotate(-90deg);
}
100% {
transform: translate(100px, -50px) rotate(-90deg);
}
}
<div class="box"></div>
<button>First Animation</button>
<button>Second Animation</button>
Upvotes: 1