我的目标是创建一个动画循环à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运行动画循环的正确方法是什么?
答案 0 :(得分:9)
这是因为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/rxjs@5.0.3/dist/global/Rx.min.js"></script>
或者,more simply,将of
和repeat
运算符替换为:
Observable.interval(0, Rx.Scheduler.animationFrame)
答案 1 :(得分:7)
这就是我将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)`;
});
&#13;
<script src="https://unpkg.com/@reactivex/rxjs@5.0.3/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>
&#13;
答案 2 :(得分:1)
从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++);
});
OR:
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();