Animating Objects

The term animation covers a whole host of topics, but this section is concerned just with the subcategory of animation that details ‘the process by which an object moves from point A to point B’. This type of animation is known as a ‘tween’ (since an object is moving between two points). The simplest possible tween consists of an element to move, the element’s current location as a start point, an end point, and the amount of time the animation will take. Modeled in RxJS, it looks something like this:

 function​ simpleTween(element, endPoint, durationSec) {
 // Convert duration to 60 frames per second
 let​ durationInFrames = 60 * durationSec;
 let​ distancePerStep = endPoint / durationInFrames;
 
 // 60 frames per second
  interval(1000 / 60)
  .pipe(
  map(n => n * distancePerStep),
  take(durationInFrames)
  )
  .subscribe((location) => {
  element.style.left = location + ​'px'​;
  });
 }

As always, there’s a catch. interval(1000 / 60) can only make a best effort attempt to emit at every interval—it provides no guarantee that it will emit an event exactly every 17 milliseconds. Every 17 milliseconds, RxJS asks the browser to execute a function. Many things could get in the way. If another function is currently being executed, our stream will be delayed. Browsers also throttle CPU usage of background tabs, so if the tab this is running in is not focused, the animation might get even further behind. Don’t take my word for it—run the following code to see just how far behind this interval can get. After you’ve done that, refresh the page, then switch over to another tab. Switch back after a while, and things get even weirder:

 import​ { interval } ​from​ ​'rxjs'​;
 import​ { take, map, pairwise } ​from​ ​'rxjs/operators'​;
 
 interval(1000 / 60)
 .pipe(
  take(60),
  map(() => performance.now()),
  pairwise(),
  map(lastTimestamps => lastTimestamps[1] - lastTimestamps[0]),
  map(msPerFrame => msPerFrame.toLocaleString())
 )
 .subscribe(msPerFrame =>
  console.log(​`Last frame took ​${msPerFrame}​ms to run, ideally 17`​)
 );

On my relatively modern laptop, I got numbers ranging from 8.5 ms all the way up to 30 ms. Reload the tab, then switch away while the frame processing happens. The numbers get even worse! If a laptop can’t keep an interval consistent, then there’s no hope for users who are trying to watch our animations on a mobile phone. The lesson is that we can’t count on “frames” as a unit of measurement if we want our animations to be timely. Instead, we need some measurement of how long it’s been since the last time an event came down our stream. While it’s possible to hack something together using performance.now() and pairwise like above, it’s time to talk about the Rx tool we’ve been unknowingly using all this time: Schedulers.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.183.210