123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- /**
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
- 'use strict';
- const keyOf = require('fbjs/lib/keyOf');
- const X_DIM = keyOf({x: null});
- const Y_DIM = keyOf({y: null});
- const Z_DIM = keyOf({z: null});
- const InitialOperationField = {
- transformTranslate: [0, 0, 0],
- transformScale: [1, 1, 1],
- };
- const InterpolateMatrix = {
- transformScale: function(mat, x, y, z) {
- mat[0] = mat[0] * x;
- mat[1] = mat[1] * x;
- mat[2] = mat[2] * x;
- mat[3] = mat[3] * x;
- mat[4] = mat[4] * y;
- mat[5] = mat[5] * y;
- mat[6] = mat[6] * y;
- mat[7] = mat[7] * y;
- mat[8] = mat[8] * z;
- mat[9] = mat[9] * z;
- mat[10] = mat[10] * z;
- mat[11] = mat[11] * z;
- },
- transformTranslate: function(mat, x, y, z) {
- mat[12] = mat[0] * x + mat[4] * y + mat[8] * z + mat[12];
- mat[13] = mat[1] * x + mat[5] * y + mat[9] * z + mat[13];
- mat[14] = mat[2] * x + mat[6] * y + mat[10] * z + mat[14];
- mat[15] = mat[3] * x + mat[7] * y + mat[11] * z + mat[15];
- },
- };
- const computeNextValLinear = function(anim, from, to, value) {
- const hasRoundRatio = 'round' in anim;
- const roundRatio = anim.round;
- let ratio = (value - anim.min) / (anim.max - anim.min);
- if (!anim.extrapolate) {
- ratio = ratio > 1 ? 1 : ratio < 0 ? 0 : ratio;
- }
- let nextVal = from * (1 - ratio) + to * ratio;
- if (hasRoundRatio) {
- nextVal = Math.round(roundRatio * nextVal) / roundRatio;
- }
- if (!isFinite(nextVal)) {
- nextVal = null;
- }
- return nextVal;
- };
- const computeNextValLinearScalar = function(anim, value) {
- return computeNextValLinear(anim, anim.from, anim.to, value);
- };
- const setNextValAndDetectChange = function(result, name, nextVal, didChange) {
- if (!didChange) {
- const prevVal = result[name];
- result[name] = nextVal;
- didChange = didChange || nextVal !== prevVal;
- } else {
- result[name] = nextVal;
- }
- return didChange;
- };
- const initIdentity = function(mat) {
- mat[0] = 1;
- mat[1] = 0;
- mat[2] = 0;
- mat[3] = 0;
- mat[4] = 0;
- mat[5] = 1;
- mat[6] = 0;
- mat[7] = 0;
- mat[8] = 0;
- mat[9] = 0;
- mat[10] = 1;
- mat[11] = 0;
- mat[12] = 0;
- mat[13] = 0;
- mat[14] = 0;
- mat[15] = 1;
- };
- const computeNextMatrixOperationField = function(
- anim,
- name,
- dim,
- index,
- value,
- ) {
- if (anim.from[dim] !== undefined && anim.to[dim] !== undefined) {
- return computeNextValLinear(anim, anim.from[dim], anim.to[dim], value);
- } else {
- return InitialOperationField[name][index];
- }
- };
- const computeTransform = function(
- anim,
- name,
- value,
- result,
- didChange,
- didMatrix,
- ) {
- const transform =
- result.transform !== undefined
- ? result.transform
- : (result.transform = [{matrix: []}]);
- const mat = transform[0].matrix;
- const m0 = mat[0];
- const m1 = mat[1];
- const m2 = mat[2];
- const m3 = mat[3];
- const m4 = mat[4];
- const m5 = mat[5];
- const m6 = mat[6];
- const m7 = mat[7];
- const m8 = mat[8];
- const m9 = mat[9];
- const m10 = mat[10];
- const m11 = mat[11];
- const m12 = mat[12];
- const m13 = mat[13];
- const m14 = mat[14];
- const m15 = mat[15];
- if (!didMatrix) {
- initIdentity(mat); // This will be the first transform.
- }
- const x = computeNextMatrixOperationField(anim, name, X_DIM, 0, value);
- const y = computeNextMatrixOperationField(anim, name, Y_DIM, 1, value);
- const z = computeNextMatrixOperationField(anim, name, Z_DIM, 2, value);
- InterpolateMatrix[name](mat, x, y, z);
- if (!didChange) {
- didChange =
- m0 !== mat[0] ||
- m1 !== mat[1] ||
- m2 !== mat[2] ||
- m3 !== mat[3] ||
- m4 !== mat[4] ||
- m5 !== mat[5] ||
- m6 !== mat[6] ||
- m7 !== mat[7] ||
- m8 !== mat[8] ||
- m9 !== mat[9] ||
- m10 !== mat[10] ||
- m11 !== mat[11] ||
- m12 !== mat[12] ||
- m13 !== mat[13] ||
- m14 !== mat[14] ||
- m15 !== mat[15];
- }
- return didChange;
- };
- /**
- * @param {object} anims Animation configuration by style property name.
- * @return {function} Function accepting style object, that mutates that style
- * object and returns a boolean describing if any update was actually applied.
- */
- const buildStyleInterpolator = function(anims) {
- function styleInterpolator(result, value) {
- let didChange = false;
- let didMatrix = false;
- for (const name in anims) {
- const anim = anims[name];
- if (anim.type === 'linear') {
- if (name in InterpolateMatrix) {
- didChange = computeTransform(
- anim,
- name,
- value,
- result,
- didChange,
- didMatrix,
- );
- didMatrix = true;
- } else {
- const next = computeNextValLinearScalar(anim, value);
- didChange = setNextValAndDetectChange(result, name, next, didChange);
- }
- } else if (anim.type === 'constant') {
- const next = anim.value;
- didChange = setNextValAndDetectChange(result, name, next, didChange);
- } else if (anim.type === 'step') {
- const next = value >= anim.threshold ? anim.to : anim.from;
- didChange = setNextValAndDetectChange(result, name, next, didChange);
- } else if (anim.type === 'identity') {
- const next = value;
- didChange = setNextValAndDetectChange(result, name, next, didChange);
- }
- }
- return didChange;
- }
- return styleInterpolator;
- };
- module.exports = buildStyleInterpolator;
|