text: /**
   * Copyright (c) 2015-present, Facebook, Inc.
   * All rights reserved.
   *
   * This source code is licensed under the BSD-style license found in the
   * LICENSE file in the root directory of this source tree. An additional grant
   * of patent rights can be found in the PATENTS file in the same directory.
   *
   * @flow
   * @format
   */
  'use strict';
  
  const Animation = require('./Animation');
  
  const {shouldUseNativeDriver} = require('../NativeAnimatedHelper');
  
  import type {AnimationConfig, EndCallback} from './Animation';
  import type AnimatedValue from '../nodes/AnimatedValue';
  
  export type DecayAnimationConfig = AnimationConfig & {
    velocity: number | {x: number, y: number},
    deceleration?: number,
  };
  
  export type DecayAnimationConfigSingle = AnimationConfig & {
    velocity: number,
    deceleration?: number,
  };
  
  class DecayAnimation extends Animation {
    _startTime: number;
    _lastValue: number;
    _fromValue: number;
    _deceleration: number;
    _velocity: number;
    _onUpdate: (value: number) => void;
    _animationFrame: any;
    _useNativeDriver: boolean;
  
    constructor(config: DecayAnimationConfigSingle) {
      super();
      this._deceleration =
        config.deceleration !== undefined ? config.deceleration : 0.998;
      this._velocity = config.velocity;
      this._useNativeDriver = shouldUseNativeDriver(config);
      this.__isInteraction =
        config.isInteraction !== undefined ? config.isInteraction : true;
      this.__iterations = config.iterations !== undefined ? config.iterations : 1;
    }
  
    __getNativeAnimationConfig() {
      return {
        type: 'decay',
        deceleration: this._deceleration,
        velocity: this._velocity,
        iterations: this.__iterations,
      };
    }
  
    start(
      fromValue: number,
      onUpdate: (value: number) => void,
      onEnd: ?EndCallback,
      previousAnimation: ?Animation,
      animatedValue: AnimatedValue,
    ): void {
      this.__active = true;
      this._lastValue = fromValue;
      this._fromValue = fromValue;
      this._onUpdate = onUpdate;
      this.__onEnd = onEnd;
      this._startTime = Date.now();
      if (this._useNativeDriver) {
        this.__startNativeAnimation(animatedValue);
      } else {
        this._animationFrame = requestAnimationFrame(this.onUpdate.bind(this));
      }
    }
  
    onUpdate(): void {
      const now = Date.now();
  
      const value =
        this._fromValue +
        this._velocity /
          (1 - this._deceleration) *
          (1 - Math.exp(-(1 - this._deceleration) * (now - this._startTime)));
  
      this._onUpdate(value);
  
      if (Math.abs(this._lastValue - value) < 0.1) {
        this.__debouncedOnEnd({finished: true});
        return;
      }
  
      this._lastValue = value;
      if (this.__active) {
        this._animationFrame = requestAnimationFrame(this.onUpdate.bind(this));
      }
    }
  
    stop(): void {
      super.stop();
      this.__active = false;
      global.cancelAnimationFrame(this._animationFrame);
      this.__debouncedOnEnd({finished: false});
    }
  }
  
  module.exports = DecayAnimation;
  