Skip to content

Instantly share code, notes, and snippets.

@seangeleno
Created May 1, 2019 15:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save seangeleno/140b065de106a1a4dbb908f666902b68 to your computer and use it in GitHub Desktop.
Save seangeleno/140b065de106a1a4dbb908f666902b68 to your computer and use it in GitHub Desktop.
Bubble Sort Colors

Bubble Sort Colors

Using CSS grid and a few lines of JavaScript, visualize a bubble sort algorithm with a bit of a rainbow.

A Pen by Gabriele Corti on CodePen.

License.

<!-- include a single button, to be absolute positioned in the center of the viewport
the columns of different colors are added through the script
-->
<button>
🌈 Sort <span>🌈</span>
</button>
/*
variables tweaking the design
- numberOfColumns: the number of columns to be included in the viewport
! the value is capped to 360 to have at most one color for each hue in the [0-360] color wheel
- duration: the number of seconds it takes to complete the bubble sort
! this does not account for the animation of the button, but the animation of the columns only
- lightness and saturation: default values for the hsl color
*/
const numberOfColumns = 359;
const duration = 7.5;
const saturation = 70;
const lightness = 70;
// array describing the hues of the different columns, to avoid doubles
const hues = [];
// function returning a random hue, which is not already in the hues array
const uniqueHue = () => {
const hue = Math.floor(Math.random() * 360);
// if the hue is already present re-run the function
if (hues.includes(hue)) {
return uniqueHue();
}
// else add the hue to the array and return its value
hues.push(hue);
return hue;
};
// select the node in which to add the columns
const body = document.querySelector('body');
// in the body include as many div elements as specified by the columns variable
for (let i = 0; i < Math.min(numberOfColumns, 359); i += 1) {
const columns = document.createElement('div');
// with a unique hue
const hue = uniqueHue();
columns.style.background = `hsl(${hue}, ${saturation}%, ${lightness}%)`;
// with a transition incrementally delayed for each successive column
// ! ultimately this has the effect of swapping the columns one after the other
columns.style.transition = `all 0.2s ${duration / numberOfColumns * i}s ease-out`;
// add a data attribute to rapidly order the columns according to the hue value
columns.setAttribute('data-hue', hue);
body.appendChild(columns);
}
// target the button
const button = document.querySelector('button');
// function called to sort the items of an array according to data-hue attribute
function bubbleSort(arr) {
// bubble sort algorithm
// instead of swapping the items based on their values, swap them on the basis of the data-hue attribute
for (let n = arr.length; n >= 0; n -= 1) {
for (let i = 0; i < n - 1; i += 1) {
const currentPosition = i;
const nextPosition = i + 1;
const current = arr[currentPosition];
const next = arr[nextPosition];
const currentHue = Number.parseInt(current.getAttribute('data-hue'), 10);
const nextHue = Number.parseInt(next.getAttribute('data-hue'), 10);
if (currentHue > nextHue) {
[arr[currentPosition], arr[nextPosition]] = [arr[nextPosition], arr[currentPosition]];
}
}
}
return arr;
}
// function called when the button is pressed
function handleClick() {
// add the class prompting the transition
button.classList.add('clicked');
// once the button's animation is complete
button.addEventListener('animationend', () => {
// target all the columns
const columns = body.querySelectorAll('div');
// sort an copy of the node list, converting it first to an array
const sortedColumns = bubbleSort([...columns]);
// loop through the sortedColumns array
for (let i = 0; i < sortedColumns.length; i += 1) {
// find the column in the unsorted data structure with the data-hue attribute matching the sorted value
const sortedColumn = sortedColumns[i];
const matchingColumn = [...columns].find(column => column.getAttribute('data-hue') === sortedColumn.getAttribute('data-hue'));
// apply a property of order beginning with the smallest values, pushing the smaller hues to the beginning of the grid
matchingColumn.style.order = i - sortedColumns.length;
}
});
}
// on click call the function prompting the sorting and the application of the order property according to the hue
button.addEventListener('click', handleClick);
@import url("https://fonts.googleapis.com/css?family=Luckiest+Guy");
* {
box-sizing: border-box;
padding: 0;
margin: 0;
}
/* specify the width and height of the body to encompass the viewport */
body {
width: 100vw;
height: 100vh;
/* include a grid whose items are automatically added as column and occupy a fraction of the width */
display: grid;
grid-auto-columns: 1fr;
grid-auto-flow: column;
}
/* absolute position the button in the center of teh viewport */
button {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
padding: 0.6rem 1.25rem;
background: hsl(0, 0%, 100%);
border: none;
border-radius: 10px;
box-shadow: 0 2px 5px hsla(0, 0%, 0%, 0.3);
color: #1c2d4a;
text-transform: uppercase;
font-family: "Luckiest Guy", cursive;
font-size: 2rem;
letter-spacing: 0.3rem;
/* transition for the transform and box-shadow properties */
transition: all 0.3s ease-out;
}
/* on hover slightly elevate the button */
button:hover {
transform: translate(-50%, calc(-50% - 2px));
box-shadow: 0 2px 7px hsla(0, 0%, 0%, 0.4);
}
/* when a class of .clicked is added (through the script) animate the button out of sight */
button.clicked {
animation: clicked 0.8s cubic-bezier(0.13, 1.03, 0.72, 1.32) forwards;
}
/* animation to have the button pushed downward and then disappear as it returns to its original location */
@keyframes clicked {
10%,
35% {
transform: translate(-50%, calc(-50% + 8px)) scaleY(0.95);
box-shadow: 0 1px 5px hsla(0, 0%, 0%, 0.2);
opacity: 1;
visibility: visible;
}
80%,
100% {
opacity: 0;
visibility: hidden;
}
}
button span {
display: inline-block;
transform: rotateY(180deg);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment