How can I use RxJS to generate a requestAnimationFrame loop?
It's because the default behaviour of Observable.of
is to emit immediately.
To change this behaviour, you should specify the Scheduler
when calling 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>
Or, more simply, replace the of
and repeat
operators with:
Observable.interval(0, Rx.Scheduler.animationFrame)
This is how I use requestAnimationFrame with rxjs. I've seen a lot of developers using 0 instead of animationFrame.now(). It's much better to pass the time because you often need that in animations.
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>