Create Smooth Ranking Animations for a JavaScript Voting System

There are some issues JavaScript with your code in achieving a smooth animation for dynamically ranking options based on votes. Here a below code:

Error Code:

function updateResults() {
for (let option in votes) {
let percentage = (votes[option] / totalVotes) * 100 || 0;
document.getElementById(option.toLowerCase().replace(' ', '')).style.width = percentage + '%';
document.getElementById(`${option.toLowerCase().replace(' ', '')}-percentage`).innerText = Math.round(percentage) + '%';
}
}

Issue with Updating Order in Place

When you update the style.width of each element, you aren’t dynamically reordering the elements based on their current votes. The elements might also “teleport” instead of animating because the new order is set directly, rather than using a smooth transition or animation to gradually move them.

Using CSS Transitions and JavaScript Sorting

To achieve the ranking switch with a smooth animation, you can:

  • Sort the elements based on the votes.
  • Apply CSS transitions to each element for smooth movement.
  • Reposition each element by updating the order in the DOM or by using position: relative and adjusting top values.

Here’s how you can modify your code to include these steps:

Correct Code:

function updateResults() {
// Sort options by vote count in descending order
const sortedOptions = Object.keys(votes).sort((a, b) => votes[b] - votes[a]);

// Get the results container element
const resultsContainer = document.getElementById("results");
resultsContainer.innerHTML = ''; // Clear existing content to re-render sorted elements

// Loop through each sorted option
sortedOptions.forEach(option => {
// Calculate the vote percentage
let percentage = (votes[option] / totalVotes) * 100 || 0;

// Create a container div for each option with transition style
const optionDiv = document.createElement("div");
optionDiv.classList.add("vote-option"); // Assume CSS applies smooth transitions
optionDiv.id = option.toLowerCase().replace(' ', '');

// Add inner HTML for option name, progress bar, and percentage display
optionDiv.innerHTML = `
<span>${option}</span>
<div class="bar" style="width: ${percentage}%; transition: width 0.5s ease;"></div>
<span id="${option.toLowerCase().replace(' ', '')}-percentage">${Math.round(percentage)}%</span>
`;

// Append each option to the container, which now reflects the new sorted order
resultsContainer.appendChild(optionDiv);
});
}

Explanation of Changes:

  1. Sorting Options by Votes: The options are sorted in descending order based on the vote count to dynamically rank them.
  2. Re-rendering Sorted Options: Each option is rendered in the sorted order by first clearing the container (resultsContainer.innerHTML = '') and then appending each option div in the correct order.
  3. Smooth Width Transition: The progress bar’s width update includes a transition style (transition: width 0.5s ease), which animates the bar’s width as votes are updated.

With this change, each option will smoothly animate to its new position in the ranking according to its vote percentage, creating a dynamic and visually appealing effect.

Related blog posts