react-native-animated-look-up-table

react-native-animated-look-up-table

Today I published react-native-animated-look-up-table, a tool that can be used to implement complex transitions that exist out of the bounds of what’s capable of React Native’s Animated library, and even the awesome general purpose react-native-animated-math.

Mapsy depends on the ability to use Math.ln() in order to compute the Web Mercator Projection. This is used for the precise placement of animated geodesic features. I was originally optimistic that by using AnimatedMath, we could approximate the projection using Newton’s Method, however this proved to require large chains of animation nodes to produce the function with any level of reasonable accuracy. The problem with this approach is that an animated node is a fairly expensive thing to allocate; even worse when constructed by iterative functions.

As an alternative, react-native-animated-look-up-table allows us to delegate the direct results of a complex function provided we know the input minimum and maximum values to compute between.

This allows us to approximate complex functions with reasonable accuracy, that are comparably cheap to allocate:

import { createTransform } from 'react-native-animated-transform';

const sine = createTransform(
  Math.sin, 
  {
    from: 0,
    to: 2 * Math.PI,
    samples: 1024,
  },
);

This can then be delegated to an interpolate‘d animation node and used in conjunction with useNativeDriver to achieve fast execution, with React Native cleverly “guessing” the values between your samples:

<Animated.View
  style={{
    transform: [
      {
        scale: animValue
          .interpolate(sine),
      },
    ],
  }}
/>

The reason this works so well is because all of the possible complicated computation has already been defined at the time of initialization. Every resutling animation you use based upon it, you basically get for free, because all React Native has to do is look up the correct value from the serialized dictionary based upon your dynamic input.

An additional benefit to this approach is that it’s far easier. You don’t have to spend time implementing the building blocks of an equation using using the admittedly verbose Animated function API.

Why open source?

This is my first step in my reinvigorated attempt to start breaking Mapsy down into it’s reusable, component elements. There are many chunks of useful code buried away in that codebase, so extracting them to dedicated repositories will help achieve the following:

  • The overall scope of the project will become more focused on application-specific content.
  • The modularity of subsequent exported dependencies from Mapsy will be improved.
  • Other developers won’t have to sit through the torment of rolling their own.
  • Improvements can be made by the (far smarter) React Native community.

Any caveats?

I’ve seen this perform very poorly against the Hermes Engine. There seems some behaviour of Hermes that is not yet well optimized for the delegation of animations that rely upon calls to __makeNative(). It is is because of this drawback that even after the difficult migration to 0.60.0, I did not end up activating Hermes in Mapsy.

Likewise, although interpolation allows us to smoothly estimate through the generated samples, they’re still just approximations. Subsequently, any features of your input function which do not meet Nyquist’s Sampling Criterion will be lost. As a workaround, you can increase the number of samples to generate to “catch” missing frequencies; however, this may incur a costly allocation overhead.