如何使用RxJS生成requestAnimationFrame循环?

问题描述 投票:9回答:3

我的目标是创建一个动画循环àlarequestAnimationFrame,这样我就可以做到这样的事情:

animationObservable.subscribe(() =>
{
    // drawing code here
});

我尝试将此代码作为基本测试:

let x = 0;

Rx.Observable
    .of(0)
    .repeat(Rx.Scheduler.animationFrame)
    .takeUntil(Rx.Observable.timer(1000))
    .subscribe(() => console.log(x++));

Here is a JSFiddle but I'm not liable for any browser crashes from running this.

我希望这会将数字从0记录到大约60(因为这是我的显示器的刷新率)超过1秒。相反,它会快速记录数字(比requestAnimationFrame快得多),开始导致页面滞后,最后在10000和几秒钟之后溢出堆栈。

为什么animationFrame调度程序以这种方式运行,以及使用RxJS运行动画循环的正确方法是什么?

javascript rxjs rxjs5 requestanimationframe
3个回答
11
投票

这是因为Observable.of的默认行为是立即发射。

要更改此行为,您应在调用Scheduler时指定Observable.of

let x = 0;

Rx.Observable
    .of(0, Rx.Scheduler.animationFrame)
    .repeat()
    .takeUntil(Rx.Observable.timer(1000))
    .subscribe(() => console.log(x++));
<script src="https://npmcdn.com/@reactivex/[email protected]/dist/global/Rx.min.js"></script>

或者,more simply,用以下代码替换ofrepeat运算符:

Observable.interval(0, Rx.Scheduler.animationFrame)

8
投票

这就是我将requestAnimationFrame与rxjs一起使用的方法。我见过很多开发人员使用0而不是animationFrame.now()。通过时间会好得多,因为你经常需要动画。

const { Observable, Scheduler } = Rx;

const requestAnimationFrame$ = Observable
  .defer(() => Observable
    .of(Scheduler.animationFrame.now(), Scheduler.animationFrame)
    .repeat()
    .map(start => Scheduler.animationFrame.now() - start)
  );

// Example usage
const duration$ = duration => requestAnimationFrame$
  .map(time => time / duration)
  .takeWhile(progress => progress < 1)
  .concat([1])

duration$(60000)
  .subscribe((i) => {
    clockPointer.style.transform = `rotate(${i * 360}deg)`;
  });
<script src="https://unpkg.com/@reactivex/[email protected]/dist/global/Rx.js"></script>

<div style="border: 3px solid black; border-radius: 50%; width: 150px; height: 150px;">
  <div id="clockPointer" style="width: 2px; height: 50%; background: black; margin-left: 50%; padding-left: -1px; transform-origin: 50% 100%;"></div>
</div>

2
投票

从RxJs> = 5.5开始,您可以通过以下方式执行此操作:

import { animationFrameScheduler, of, timer } from 'rxjs';
import { repeat,takeUntil } from 'rxjs/operators';

let x = 0;

    of(null, animationFrameScheduler)
      .pipe(
        repeat(),
        takeUntil(timer(1000)),
      )
      .subscribe(() => {
        console.log(x++);
      });

要么:

import { animationFrameScheduler, of, timer } from 'rxjs';
import { repeat, tap, takeUntil } from 'rxjs/operators';

let x = 0;

of(null, animationFrameScheduler)
  .pipe(
    tap(() => {
      console.log(x++);
    }),
    repeat(),
    takeUntil(timer(1000)),
  )
  .subscribe();
© www.soinside.com 2019 - 2024. All rights reserved.