Анимационный цикл с RxJs - PullRequest
       0

Анимационный цикл с RxJs

0 голосов
/ 03 октября 2018

Чего я хочу добиться:

Я хочу создать цикл анимации с RxJ.Логика следующая:

  1. Каждый x мс загрузка нового кадра (загрузка изображения из Интернета)
  2. Если предыдущий кадр все еще загружается, пропустите загрузку следующего кадра.
  3. Если анимация завершится (все изображения были загружены и отображены), остановитесь на x мс, а затем снова запустите цикл анимации.

Что у меня естьдо сих пор:

Поток для интервала:

private intervalStream: Observable<number> = interval(800);

Наблюдаемый, который излучает true, если кадр загружается, и false, если нет:

this.frameStateService.isAnyFrameLoading

метод, запускающий анимацию:

public startAnimation(): void {    

    const combined = combineLatest(this.intervalStream, this.layerStateService.isAnyLayerLoading);

    combined.pipe(
        map(
            ([interval, isLayerLoading]) => {
                if(!isLayerLoading && !this.frameStateService.isAnyFrameLoading) {
                    this.frameStateService.setCurrentFrameToNextFrame();
                } else {
                    timeout(5000);
                }
            }
        )
    ).subscribe();
}

Диаграмма:

interval   ----x----x----x----x----x----x----x
isLoading  f---t--f-t------f--t---ft---------- (f - false, t - true)

Что не работает:

  1. Не ожидает загрузки слоя.
  2. Анимация не перезапускается после окончательной задержки.

Ответы [ 2 ]

0 голосов
/ 03 октября 2018

Я бы предложил взглянуть на этот подход, своего рода вариацию того, что @martin писал ранее.

У вас есть 2 ингредиента:

  • список имен файлов (files) вы получаете откуда-то (например, службу, которую вы вызываете)
  • функцию (readFile), которая читает каждый файл - давайте предположим, что такая функция возвращает Observable, который испускается, когда содержимое файла читается и уведомляетсамо содержимое файла

Вы можете создать Observable, который будет выдавать имя файла для чтения, каждое излучение будет удалено с определенной задержкой (в вашем случае 800 мс), а затем ждать x мсперед повторением.Примерно так

const files = [
  'F1',
  'Second file',
  '3rd file',
  'file n 4'
];

const imagesToShow = from(files).pipe(
  mergeMap(f => of(f).pipe(delay(800)), 1)
);

const imagesToShowRepeated = imagesToShow.pipe(
  delay(5000),
  repeat()
)

Теперь вы можете использовать exhaustMap, чтобы получить то, что вы хотите, если мое понимание правильно, как в следующих строках

const loadFile = (fileName: string) => {
  return of(fileName).pipe(delay(Math.random()*2000)); // simulates the function reading a file
}

const animation = imagesToShowRepeated.pipe(
  exhaustMap(file => loadFile(file))
)
0 голосов
/ 03 октября 2018

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

import { interval, of } from 'rxjs';
import { exhaustMap, take, repeat, concat, delay, ignoreElements } from 'rxjs/operators';

const loadImage = () => of('img')

interval(1000)
  .pipe(
    exhaustMap(() => loadImage()), // wait until loadImage completes
    take(10), // number of frames
    concat(of(null).pipe( // delay after animation completes
      delay(5000),
      ignoreElements(),
    )),
    repeat(), // repeat the whole process
  )
  .subscribe(console.log);

Демонстрация в реальном времени: https://stackblitz.com/edit/rxjs6-demo-j9wl38?file=index.ts

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