Reputation: 11
I am wanting to move an element from one position to another, on a click event, but the animation is really janky.
You can view the prototype here.
My JS
// intialize the selected card as false
let selectedCard = false;
// find all the cards
let cards = document.querySelectorAll('.flex-item');
console.log(cards);
// grab the button
let button = document.querySelector('button')
// initialize the first card position
let firstCardPosition = '';
// intialize the selected card position
let selectedCardPosition = '';
//
let isAnimating = false;
// Get the selected card position
function getSelectedCardPosition(card) {
selectedCardPosition = card.getBoundingClientRect();
console.log(selectedCardPosition);
};
// Get the first card position
function getFirstCardPosition(cards) {
if (cards) {
firstCardPosition = cards[0].getBoundingClientRect();
}
};
// Change the display of the card
function hideCards(card, interval) {
isAnimating = true;
setTimeout(function() {
isAnimating = false;
card.hidden = true;
}, interval)
};
function showCards(card, interval) {
isAnimating = true;
setTimeout(function() {
isAnimating = false;
card.hidden = false;
}, interval)
};
function fadeCards(cards) {
cards.forEach(function(card) {
if (!card.selectedCard) {
card.classList.remove('card-show');
card.classList.add('card-hide');
hideCards(card, 785);
}
});
};
function revealCards(cards) {
cards.forEach((card) => {
if (!card.selectedCard) {
showCards(card, 0);
card.classList.remove('card-hide');
card.classList.add('card-show');
}
})
}
// Go through each card
// Add an attribute 'selectedCard'
// On first click, it is selected. We toggle it based on click
// If 'selectedCard' is true, than display the selected div - otherwise
// hide the div.
cards.forEach(function(card) {
// initialize the value to false
card.selectedCard = false;
// Grab the div that is the selected div.
let showSelected = card.firstElementChild;
// on click, do the things below.
card.addEventListener('click', function() {
// if animating, get out of this function so no jankiness occurs
if (isAnimating){
return
}
// Toggle the value of the selected card
card.selectedCard = !card.selectedCard;
card.selectedCard ? showSelected.style.display = 'block' : showSelected.style.display = 'none';
getSelectedCardPosition(card);
getFirstCardPosition(cards)
if (card.selectedCard) {
fadeCards(cards);
} else {
revealCards(cards);
}
moveToDestination(card, firstCardPosition, selectedCardPosition);
});
});
function moveToDestination(card, firstCardPosition, selectedCardPosition) {
const firstCardX = firstCardPosition.x;
const firstCardY = firstCardPosition.y;
let selectedCardX = selectedCardPosition.x;
let selectedCardY = selectedCardPosition.y;
let moveToXPosition = (selectedCardX - firstCardX) * -1;
let moveToYPosition = (selectedCardY - firstCardY) * -1;
let translateX = 'translateX' + '(' + moveToXPosition + 'px' + ')';
let translateY = 'translateY' + '(' + moveToYPosition + 'px' + ')';
console.log(translateX);
console.log(translateY);
card.animate(
[
// keyframes
{ transform: translateX },
{ transform: translateY }
], {
duration: 800,
easing: "ease-in-out"
});
}
There are a few challenges here:
transitions
element.animate()
method to change the X and Y of the selected card, to that of the first card in the array
Am I trying to do something that just isn't going to work the way I intend it to or is my implementation poorly done?
Upvotes: 1
Views: 1587
Reputation: 378
cards.forEach(function(card) {
// initialize the value to false
card.selectedCard = false;
// Grab the div that is the selected div.
let showSelected = card.firstElementChild;
// on click, do the things below.
card.addEventListener('click', function() {
// if animating, get out of this function so no jankiness occurs
if (isAnimating){
return
}
// Toggle the value of the selected card
card.selectedCard = !card.selectedCard;
card.selectedCard ? showSelected.style.display = 'block' : showSelected.style.display = 'none';
// only save the coordinates of the selected card if it's being selected and don't overwrite those when it's clicked again
if (card.selectedCard)
getSelectedCardPosition(card);
getFirstCardPosition(cards)
console.log(card, selectedCardPosition);
// Modifications to the method to add the animation onclick
if(card.selectedCard){
card.style.position = 'fixed';
// subtract 32px for padding
card.style.top = selectedCardPosition.y - 32 + 'px';
card.style.left = selectedCardPosition.x - 32 + 'px';
setTimeout(function () {
card.style.top = firstCardPosition.y - 32 + 'px';
card.style.left = firstCardPosition.x - 32 + 'px';
}, 1000)
}
// if the card is being unselected return it to it's previously saved coordinates
else {
card.style.top = selectedCardPosition.y - 32 + 'px';
card.style.left = selectedCardPosition.x - 32 + 'px';
}
if (card.selectedCard) {
fadeCards(cards);
} else {
revealCards(cards);
setTimeout(() => {
card.style.position = 'relative';
card.style.left = 'auto';
card.style.top = 'auto';
}, 500)
moveToDestination(card, firstCardPosition, selectedCardPosition);
}
});
});
I have made a change to your onclick handler and made the position of the card fixed on click. I have also added a setTimeout function to make sure the animation occurs 1 second after the element is clicked. This will definitely need to be refactored. Otherwise, it will work.
Here's the modified pen.
https://codepen.io/faisalrashid/pen/zYOBVPg
Upvotes: 2