Цикл массива с определенной скоростью в Javascript - PullRequest
0 голосов
/ 07 мая 2018

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

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

Затем я хочу «воспроизвести» этот массив на обычной скорости, как будто вы воспроизводите видео. Но вместо того, чтобы смотреть видео, я хочу показать текущие данные по каждому индексу, на котором вы находитесь на веб-интерфейсе.

Структура массива еще не создана, но я предполагаю, что просто сохраню и загрузлю файл JSON где-нибудь в базе данных. Это должно быть воспроизведено в моем интерфейсе. Я использовал Angular (6) для его построения, поэтому было бы неплохо, если бы его можно было смешать с Angular (чтобы отслеживать ход выполнения текущего индекса и привязывать значения текущего индекса к внешнему интерфейсу). .

Было бы легко использовать 0-1-2 и т. Д. Для indexx, или, может быть, что-то вроде отметок времени?

Любые предложения приветствуются. Самое главное, чтобы это было быстрым, чтобы вам не понадобилась сильная установка для игры.

Заранее спасибо!

Ответы [ 2 ]

0 голосов
/ 07 мая 2018

Вы можете сделать себя простым бегуном для таких вещей.Это в основном игровой движок, и вам нужен игровой цикл:)

Вот наивный пример.Пропускаем большую часть проверки и проверки ошибок здесь для пивоварения.

class TelemetryPlayer {
  constructor(items, render, interval) {
    // setup local data. 
    this.interval = interval;
    this.items = items;
    this.render = render;
    this.startLoop();
  }

  // Loop simply initializes before the first run, and then runs the loop.
  // Other places do the actual work. 
  startLoop() {
    this._renderInProgress = false;
    this._currentIndex = 0;
    // save the interval reference if you wanna pause/reset later on.
    this._interval = setInterval(this.doWork.bind(this), this.interval);    
  }

  // here we perform the actual render.
  doWork() {
    if (this._renderInProgress) {
      // previous render has not completed yet.
      console.log('skip');
      return;
    }
    console.log('Tick');
    this._renderInProgress = true;
    const item = this.items[this._currentIndex];
    console.log('Tick');

    // now, call your renderer, and update stuff when complete.
    this.render(item)
      .then(() => {
        // Or this can be a callback or similar.
        this._renderInProgress = false;
        // Ready next item. Do not go out of array bounds.
        this._currentIndex++;
        if (this._currentIndex === this.items.length) {
          this._currentIndex = 0;
        }
      });
  }

  // You can then add fun things like skip, pause, reset etc.
  skip(item)  {
    if (item < 0 || item > this.items.length) {
      return;
    }
    // pause first
    this.pause();
    this._currentIndex = item;
    this.unpause();
  }
  //
  reset() {
    this.skip(0);
  } 
  //
  pause() {
    this._interval = clearInterval(this._interval);
  }

  unpause() {
    if (!this._interval) {
      this._interval = setInterval(this.doWork.bind(this), this.interval);    
    }
  }

  // you can even add items later
  addItem(item) {
    this.items.push(item);
  }

  // or replace them.
  replaceItem(item, index) {
    this.items[index] = item;
    // show the new item right away.
    this.skip(index);
  }

  // or add an item to be played just once.
  playOnce(item) {
    this.pause();
    this.render(item);
    this.unpause();
  }
}

Теперь вот пример использования.Вы можете скопировать код (как класс выше, так и блок кода ниже) и вставить его в консоль прямо здесь, на StackOverflow, чтобы увидеть его в работе.Вы, вероятно, хотите заняться другими делами, но вы получите суть.

let items = [ 100, 200, 300, 50, 100, 200, 300, 250 ];

const timeline = document.createElement('ul');
// maybe better do this by adding class and external stylesheet
timeline.setAttribute('style', 'padding: 15px; border: 1px solid gray; list-style-type: none; height: 500px; width: 100%; position: absolute; top: 0;overflow-y: scroll;')
document.body.appendChild(timeline);

let render = function(item)  {
  return new Promise(function (resolve) {
    // run something (in) expensive with item now.
    const li = document.createElement('li');
    // again, better do this with class.
    li.setAttribute('style', `display: inline-block; width: 25px; margin: 5px; background-color: #c1c1c1; height: ${item}px;`);
    timeline.appendChild(li);
    li.scrollIntoView();

    // return when done.
    resolve();
  });
}

const player = new TelemetryPlayer(items, render, 1500);

// now you can do things like speed up etc.


// now you can do things like speed up etc.
function speedUp() {
  // speedup 3 seconds after "playback" starts.
  return new Promise((resolve) => setTimeout(() => {
    player.pause();
    player.interval = 600;
    player.unpause();
    resolve();
  }, 3000));  
}    

function playOnce() {
  // add item once, but not in the array we loop around in
  return new Promise((resolve) => setTimeout(() => {
    player.playOnce(1000);
    resolve();
  }, 3000));  
}
// or add a few items that will be repeated.
function addItems() {
  // add a super very high item 3 seconds after function call.
  return new Promise((resolve) => setTimeout(() => {
    player.pause();
    player.addItem(400);
    player.addItem(430);
    player.addItem(420);
    player.unpause();
    // now rewind to this block. I am off by one, likely.
    player.skipTo(player.items.length - 3);
    resolve();
  }, 5000))
}

speedUp()
.then(playOnce)
.then(addItems);
0 голосов
/ 07 мая 2018

Вам нужно использовать функцию setInterval, в которой вы будете перебирать массив в соответствии с вашей частотой.Таким образом, если ваша частота равна 60hz, это означает, что вы хотите переходить к следующему элементу в массиве через каждые 1000 / 60 миллисекунды

var data = [1, 2, 3, 4, 5]

var currentIndex = 0;

var interval = 1000 / 60

var id = setInterval(function() {
  // do your thing
  if(currentIndex == (data.length-1)) {
    clearInterval(id)
  } else {
    currentIndex++
  }
}, interval)

Это не особо перебирает массив, а скорее выполняет некоторые действия после интервалавремя и затем переход к следующему элементу, и когда вы закончите с массивом, это очистит интервал.Возможно, связанный список будет более полезным, чем массив здесь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...