Ошибка очень незначительная: вы сравниваете строки, а не числа в вашем роде. Добавьте преобразование чисел:
if (+document.querySelectorAll('.sortBar')[j].getAttribute('value') < +document.querySelectorAll('.sortBar')[j-1].getAttribute('value')) {
В виде строк, например, "3" > "29"
.
Визуализация не отображается в реальном времени, потому что код действительно завершается очень быстро, а также без снятия контроля и ожидания DOM-рендеринга. Есть некоторые незначительные проблемы с принудительным повторным рендерингом DOM, но я не думаю, что это имеет здесь большое значение.
Чтобы исправить это, добавьте задержку в циклы, это очень просто, все, что вам нужно является канонической функцией задержки (const delay = ms => new Promise(res => setTimeout(res, ms));
), async
перед вашим sort
(async function sort
) и соответствующей задержкой между свопами (await delay(DELAY_BETWEEN_SWAPS);
, 25 мс в настоящее время. Точное время не гарантируется, оно может потребоваться, например, 22 мс один раз и 27 мс в следующий раз из-за множества факторов, но это не так уж важно).
Однако это вызывает проблемы с отменой: теперь возможно выполнить сброс, а сортировка все еще продолжается (дилемма аснихронности). Поэтому необходимо проверить, была ли текущая сортировка отменена или нет. Поэтому для каждого процесса сортировки требуется токен отмены, который можно использовать для остановки старой сортировки при нажатии кнопки сброса. И последнее, но не менее, начиная новую сортировку (просто нажав «кнопку»), автоматически отменяется и последняя сортировка.
Обратите внимание, что я показываю некоторые концепции, но не обязательно код, который получит награды за красоту. Я также не изменяю ничего, что «работает, но я бы так не делал» - например, я бы предпочел холст вместо анимации с тоннами DOM-обновлений.
Рабочая версия:
const sortDisplay = document.getElementById('sortDisplay');
let resetbtn = document.querySelector('.reset');
resetbtn.addEventListener('click', reset);
const DELAY_BETWEEN_SWAPS = 25;
const delay = ms => new Promise(res => setTimeout(res, ms));
let cancelLast = () => {};
let count = 0;
let amount = 100;
// create div that has custom attribute value, unique style tag, default bar style and append.
function generateBar() {
// generate div
let bar = document.createElement('div');
// keep track of the total amount of bars
count++;
// assign random number 0-100 and setAttribute to the div
let temp = Math.floor(Math.random() * 101);
// create custom attribute that holds its value
bar.setAttribute('value', temp);
// create unique style tag with height as a percentage based on Attribute
let barHeight = document.createElement('style');
barHeight.innerHTML = `.barHeight${count} {height: ${temp}%;}`;
// add that unique style to the DOM
sortDisplay.appendChild(barHeight);
// now add that unique style to the div
bar.classList.add(`barHeight${count}`);
// use standard style from css as well
bar.classList.add('sortBar');
// now add that div to the DOM
sortDisplay.appendChild(bar);
}
// clear container div and regenerate
function reset() {
cancelLast();
// clear all data within the container
sortDisplay.innerHTML = '';
// reset the count
count = 0;
// generate k bars
for (let i = 0; i < amount; i++) {
generateBar();
}
}
// when page is loaded reset
reset(amount);
// swap elements within the DOM
function swapElements(obj1, obj2) {
// create marker element and insert it above where obj1 is
var temp = document.createElement("div");
obj1.parentNode.insertBefore(temp, obj1);
// move obj1 to right before obj2
obj2.parentNode.insertBefore(obj1, obj2);
// move obj2 to right before where obj1 used to be
temp.parentNode.insertBefore(obj2, temp);
// remove temporary marker node
temp.parentNode.removeChild(temp);
}
// sort the divs within the DOM
async function sort(cancellationChecker) {
for (let i = 1; i < amount; i++) {
let j = i;
for (j; j > 0; j--) {
if (cancellationChecker()) return;
if (+document.querySelectorAll('.sortBar')[j].getAttribute('value') < +document.querySelectorAll('.sortBar')[j-1].getAttribute('value')) {
swapElements(document.querySelectorAll('.sortBar')[j], document.querySelectorAll('.sortBar')[j-1]);
await delay(DELAY_BETWEEN_SWAPS);
}
else {
break;
}
}
}
}
function btnSort() {
let cancelled = false;
cancelLast();
cancelLast = () => cancelled = true;
sort(() => cancelled);
}
// Button to run the sort function
button = document.querySelector('.button');
button.addEventListener('click', btnSort);
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
height: 100vh;
width: 100%;
}
.sortDisplay {
background-color: #305c50;
background-image: linear-gradient(28deg, #305c50 0%, #6ab19e 70%, #82d8a6 100%);
display: flex;
align-items: flex-end;
justify-content: space-between;
height: 100%;
width: 100%;
overflow: hidden;
}
.btn-container {
position: absolute;
right: 0;
bottom: 0;
margin: 25px;
}
.btn-container button {
padding: 25px;
}
.sortBar {
flex: 1;
background-color: #0007;
}
<div class="btn-container">
<button class="reset">reset</button>
<button class="button">button</button>
</div>
<div id="sortDisplay"class="sortDisplay"></div>