mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-05-09 04:08:11 +08:00
Summary: This relied on NaN being turned into null (through JSON.stringify), which would then be handled by Yoga gracefully. But in some cases we do not call JSON.stringify and thus pass NaN directly to Yoga causing a problem. Reviewed By: fkgozali Differential Revision: D9764488 fbshipit-source-id: 021c9ffafba8f9bcef2476756a12df33c367bcb1
212 lines
5.4 KiB
JavaScript
212 lines
5.4 KiB
JavaScript
/**
|
|
* Copyright (c) 2015-present, Facebook, Inc.
|
|
*
|
|
* 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 {
|
|
var next = computeNextValLinearScalar(anim, value);
|
|
didChange = setNextValAndDetectChange(result, name, next, didChange);
|
|
}
|
|
} else if (anim.type === 'constant') {
|
|
var next = anim.value;
|
|
didChange = setNextValAndDetectChange(result, name, next, didChange);
|
|
} else if (anim.type === 'step') {
|
|
var next = value >= anim.threshold ? anim.to : anim.from;
|
|
didChange = setNextValAndDetectChange(result, name, next, didChange);
|
|
} else if (anim.type === 'identity') {
|
|
var next = value;
|
|
didChange = setNextValAndDetectChange(result, name, next, didChange);
|
|
}
|
|
}
|
|
return didChange;
|
|
}
|
|
return styleInterpolator;
|
|
};
|
|
|
|
module.exports = buildStyleInterpolator;
|