Сроки анимации для Ханойской башни визуализатора - PullRequest
0 голосов
/ 09 февраля 2020

В настоящее время я строю башню Ханоя Visualizer. Идея состоит в том, что вы вводите число, алгоритм создает диски, а затем вы можете видеть, как он перемещает диски, пока Башня не будет закончена. Пока все работает отлично, единственная проблема в том, что я не могу заставить анимацию работать.

Я пытался запустить функцию тайм-аута перед каждым изменением стиля, но всякий раз, когда я нажимал на кнопку отправки, я видел только конечный результат и никаких анимаций. Результат, который я ищу, состоит в том, чтобы увидеть, как каждый диск поднимается, перетаскивается на колышек назначения, а затем падает.

Я думаю, что проблема в том, что созданные элементы визуализируются последними и, следовательно, всегда имеют свойства css с конца. Тем не менее, я, конечно, могу ошибаться, поскольку ничего не знаю о временных анимациях.

Вот ссылка на этот проект. CSS просто для наглядности, я знаю, это выглядит плохо:)

https://jsfiddle.net/jakob_mayerhofer/rgx17hps/12/

//get submit values
const submit = document.getElementsByClassName('submit')[0];
var numberInput = document.getElementsByClassName('number')[0];
const tower1 = document.getElementsByClassName('tower1')[0];

submit.addEventListener('click', (e)=> {
  const number = parseInt(numberInput.value);
  towerOfHanoi(number);
  numberInput.value = "";
  e.preventDefault();
});


//start the game
async function towerOfHanoi(number){
  const a = [];
  const b = [];
  const c = [];
  let iterator = number;

//fill first tower with disks equal to number imput
  for(iterator; iterator > 0; iterator--){
    a.push(iterator);
  }

// create the disks
  a.forEach((item) => {
    element = document.createElement("div");
    element.className = "disk";
    element.setAttribute("id", item);
    const style = {
      width: 400/(number+1)*item + "px",
      bottom: a.indexOf(item)*10 + "px",
      background: "rgb(" +Math.floor(Math.random()*256) +"," +Math.floor(Math.random()*256) +"," +Math.floor(Math.random()*256) +")",
      transform: "translateX(0px)"
    }
    Object.assign(element.style, style);
    tower1.appendChild(element);
  });

// this moves the disks
  if(number%2 != 0){
    while(c.length < number){
      moveDisk(a, c, c, number, 2);
      moveDisk(a, b, c, number, 1);
      moveDisk(b, c, c, number, 1)
      console.log(a, b, c);
    }
  }else {
    while(c.length < number){
      moveDisk(a, b, c, number, 1);
      moveDisk(a, c, c, number, 2);
      moveDisk(b, c, c, number, 1);
      console.log(a, b, c);
    }
  }
};



// move disk function, parameters are start, destination, finsh peg and distance between start and destination
function moveDisk(a, b, c, number, distance) {
    if (c.length == number) return;

    if(!a.length && b.length){
      draw(b, a, distance*-1);
      a.push(b[b.length-1]);
      b.pop();
    } else if (!b.length && a.length) {
      draw(a, b, distance);
      b.push(a[a.length-1]);
      a.pop();

    } else {
      if(a[a.length-1] < b[b.length-1]){
        while(a[a.length-1] < b[b.length-1]){
          draw(a, b, distance);
          b.push(a[a.length-1]);
          a.pop();
        }

      } else if(b[b.length-1] < a[a.length-1]){
        while(b[b.length-1] < a[a.length-1]){
          draw(b, a, distance*-1);
          a.push(b[b.length-1]);
          b.pop();
        }
      }
    }
};

//moving function: this should animate the disks
function draw(a, b, distance){
  num = a[a.length-1].toString();
  disk = document.getElementById(num);

//get current translateX css value and then add the distance between start and destination peg
  regEx = /\.*translateX\((.*)px\)/i;
  translate = disk.getAttribute('style')
  value = parseInt(regEx.exec(translate)[1]) + (distance*400);

//move disk up 
  disk.style.bottom = "385px";
//move disk to the destination peg
  disk.style.transform = "translateX(" + value +"px)";
//drop disk
  disk.style.bottom = b.length*20 +"px";

};

Если у вас есть предложения по улучшению моего кода, Я, конечно, рад получить любую Обратную связь.

Я благодарен за каждый совет, который я могу получить.

1 Ответ

1 голос
/ 09 февраля 2020

Ваш код не имеет ничего, что вводит задержки / паузы. Простое определение функции как async не даст ничего полезного без ожидаемого внутри нее обещания.

Шаги, чтобы заставить ее работать:

  1. Определить функция, которая возвращает обещание, которое разрешается через некоторое время:

    const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
    
  2. Создает draw async функцию и добавляет задержки между каждым изменением стиля:

    //move disk up 
    disk.style.bottom = "385px";
    await delay(250);
    //move disk to the destination peg
    disk.style.transform = "translateX(" + value +"px)";
    await delay(250);
    //drop disk
    disk.style.bottom = b.length*20 +"px";
    await delay(250);
    
  3. Сделайте moveDisk функцией async и, где вы вызываете draw, добавьте к ней префикс await, например:

    await draw(b, a, distance*-1);
    

    Do куда бы вы ни позвонили draw.

  4. Куда бы вы ни позвонили moveDisk, также ожидайте своего решения, например:

    await moveDisk(a, c, c, number, 2);
    

    Делайте это везде Вы звоните moveDisk.

const delay = ms => new Promise(resolve => setTimeout(resolve, ms));

//get submit values
const submit = document.getElementsByClassName('submit')[0];
var numberInput = document.getElementsByClassName('number')[0];
const tower1 = document.getElementsByClassName('tower1')[0];

submit.addEventListener('click', (e)=> {
  const number = parseInt(numberInput.value);
  towerOfHanoi(number);
  numberInput.value = "";
  e.preventDefault();
});


//start the game
async function towerOfHanoi(number){
  const a = [];
  const b = [];
  const c = [];
  let iterator = number;

//fill first tower with disks equal to number imput
  for(iterator; iterator > 0; iterator--){
    a.push(iterator);
  }

// create the disks
  a.forEach((item) => {
    element = document.createElement("div");
    element.className = "disk";
    element.setAttribute("id", item);
    const style = {
      width: 400/(number+1)*item + "px",
      bottom: a.indexOf(item)*10 + "px",
      background: "rgb(" +Math.floor(Math.random()*256) +"," +Math.floor(Math.random()*256) +"," +Math.floor(Math.random()*256) +")",
      transform: "translateX(0px)"
    }
    Object.assign(element.style, style);
    tower1.appendChild(element);
  });

// this moves the disks
  if(number%2 != 0){
    while(c.length < number){
      await moveDisk(a, c, c, number, 2);
      await moveDisk(a, b, c, number, 1);
      await moveDisk(b, c, c, number, 1)
    }
  }else {
    while(c.length < number){
      await moveDisk(a, b, c, number, 1);
      await moveDisk(a, c, c, number, 2);
      await moveDisk(b, c, c, number, 1);
    }
  }
};



// move disk function, parameters are start, destination, finsh peg and distance between start and destination
async function moveDisk(a, b, c, number, distance) {
    if (c.length == number) return;

    if(!a.length && b.length){
      await draw(b, a, distance*-1);
      a.push(b[b.length-1]);
      b.pop();
    } else if (!b.length && a.length) {
      await draw(a, b, distance);
      b.push(a[a.length-1]);
      a.pop();

    } else {
      if(a[a.length-1] < b[b.length-1]){
        while(a[a.length-1] < b[b.length-1]){
          await draw(a, b, distance);
          b.push(a[a.length-1]);
          a.pop();
        }

      } else if(b[b.length-1] < a[a.length-1]){
        while(b[b.length-1] < a[a.length-1]){
          await draw(b, a, distance*-1);
          a.push(b[b.length-1]);
          b.pop();
        }
      }
    }
};

//moving function: this should animate the disks
async function draw(a, b, distance){
  num = a[a.length-1].toString();
  disk = document.getElementById(num);

//get current translateX css value and then add the distance between start and destination peg
  regEx = /\.*translateX\((.*)px\)/i;
  translate = disk.getAttribute('style')
  value = parseInt(regEx.exec(translate)[1]) + (distance*400);

    //move disk up 
    disk.style.bottom = "385px";
    await delay(250);
    //move disk to the destination peg
    disk.style.transform = "translateX(" + value +"px)";
    await delay(250);
    //drop disk
    disk.style.bottom = b.length*20 +"px";
    await delay(250);
}; 
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
  flex-direction: column;
}

.towerOfHanoi {
  display: flex;
  flex-direction: row;
  height: 400px;
  width: 1200px;
  margin-top: 2em;
}

.tower1,
.tower2,
.tower3 {
  background-color: lightblue;
  flex-grow: 1;
  position: relative;
  display: flex;
  align-items: flex-end;
}

.stick {
  height: 50%;
  width: 10px;
  background-color: grey;
  margin: 0 auto;
}

.disk {
  height: 20px;
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  margin: auto;
  z-index: 10;
  transition: bottom 250ms ease-in-out, transform 250ms ease-in-out;
}
<form class="" action="index.html" method="post">
  <input type="text" class="number">
  <button class="submit" type="submit">Submit</button>
</form>
<div class="towerOfHanoi">
  <div class="tower1">
    <div class="stick"></div>
  </div>
  <div class="tower2">
    <div class="stick"></div>
  </div>
  <div class="tower3">
    <div class="stick"></div>
  </div>
</div>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...