mirror of
https://github.com/status-im/react-native.git
synced 2025-01-15 20:15:11 +00:00
Implement transform styles, redux
This commit is contained in:
parent
d2dbf4e0ed
commit
357a54500e
@ -34,7 +34,10 @@ var ViewStylePropTypes = {
|
|||||||
),
|
),
|
||||||
shadowOpacity: ReactPropTypes.number,
|
shadowOpacity: ReactPropTypes.number,
|
||||||
shadowRadius: ReactPropTypes.number,
|
shadowRadius: ReactPropTypes.number,
|
||||||
|
transform: ReactPropTypes.arrayOf(ReactPropTypes.object),
|
||||||
transformMatrix: ReactPropTypes.arrayOf(ReactPropTypes.number),
|
transformMatrix: ReactPropTypes.arrayOf(ReactPropTypes.number),
|
||||||
|
|
||||||
|
// DEPRECATED
|
||||||
rotation: ReactPropTypes.number,
|
rotation: ReactPropTypes.number,
|
||||||
scaleX: ReactPropTypes.number,
|
scaleX: ReactPropTypes.number,
|
||||||
scaleY: ReactPropTypes.number,
|
scaleY: ReactPropTypes.number,
|
||||||
|
@ -19,6 +19,7 @@ var TextInputState = require('TextInputState');
|
|||||||
var flattenStyle = require('flattenStyle');
|
var flattenStyle = require('flattenStyle');
|
||||||
var invariant = require('invariant');
|
var invariant = require('invariant');
|
||||||
var mergeFast = require('mergeFast');
|
var mergeFast = require('mergeFast');
|
||||||
|
var precomputeStyle = require('precomputeStyle');
|
||||||
|
|
||||||
type MeasureOnSuccessCallback = (
|
type MeasureOnSuccessCallback = (
|
||||||
x: number,
|
x: number,
|
||||||
@ -93,7 +94,7 @@ var NativeMethodsMixin = {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var style = flattenStyle(nativeProps.style);
|
var style = precomputeStyle(flattenStyle(nativeProps.style));
|
||||||
|
|
||||||
var props = null;
|
var props = null;
|
||||||
if (hasOnlyStyle) {
|
if (hasOnlyStyle) {
|
||||||
|
@ -23,6 +23,7 @@ var styleDiffer = require('styleDiffer');
|
|||||||
var deepFreezeAndThrowOnMutationInDev = require('deepFreezeAndThrowOnMutationInDev');
|
var deepFreezeAndThrowOnMutationInDev = require('deepFreezeAndThrowOnMutationInDev');
|
||||||
var diffRawProperties = require('diffRawProperties');
|
var diffRawProperties = require('diffRawProperties');
|
||||||
var flattenStyle = require('flattenStyle');
|
var flattenStyle = require('flattenStyle');
|
||||||
|
var precomputeStyle = require('precomputeStyle');
|
||||||
var warning = require('warning');
|
var warning = require('warning');
|
||||||
|
|
||||||
var registrationNames = ReactIOSEventEmitter.registrationNames;
|
var registrationNames = ReactIOSEventEmitter.registrationNames;
|
||||||
@ -160,7 +161,7 @@ ReactIOSNativeComponent.Mixin = {
|
|||||||
// before actually doing the expensive flattening operation in order to
|
// before actually doing the expensive flattening operation in order to
|
||||||
// compute the diff.
|
// compute the diff.
|
||||||
if (styleDiffer(nextProps.style, prevProps.style)) {
|
if (styleDiffer(nextProps.style, prevProps.style)) {
|
||||||
var nextFlattenedStyle = flattenStyle(nextProps.style);
|
var nextFlattenedStyle = precomputeStyle(flattenStyle(nextProps.style));
|
||||||
updatePayload = diffRawProperties(
|
updatePayload = diffRawProperties(
|
||||||
updatePayload,
|
updatePayload,
|
||||||
this.previousFlattenedStyle,
|
this.previousFlattenedStyle,
|
||||||
|
161
Libraries/StyleSheet/precomputeStyle.js
Normal file
161
Libraries/StyleSheet/precomputeStyle.js
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @providesModule precomputeStyle
|
||||||
|
* @flow
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var MatrixMath = require('MatrixMath');
|
||||||
|
var deepFreezeAndThrowOnMutationInDev = require('deepFreezeAndThrowOnMutationInDev');
|
||||||
|
var invariant = require('invariant');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method provides a hook where flattened styles may be precomputed or
|
||||||
|
* otherwise prepared to become better input data for native code.
|
||||||
|
*/
|
||||||
|
function precomputeStyle(style: ?Object): ?Object {
|
||||||
|
if (!style || !style.transform) {
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
invariant(
|
||||||
|
!style.transformMatrix,
|
||||||
|
'transformMatrix and transform styles cannot be used on the same component'
|
||||||
|
);
|
||||||
|
var newStyle = _precomputeTransforms({...style});
|
||||||
|
deepFreezeAndThrowOnMutationInDev(newStyle);
|
||||||
|
return newStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a transform matrix based on the provided transforms, and use that
|
||||||
|
* within the style object instead.
|
||||||
|
*
|
||||||
|
* This allows us to provide an API that is similar to CSS and to have a
|
||||||
|
* universal, singular interface to native code.
|
||||||
|
*/
|
||||||
|
function _precomputeTransforms(style: Object): Object {
|
||||||
|
var {transform} = style;
|
||||||
|
var result = MatrixMath.createIdentityMatrix();
|
||||||
|
|
||||||
|
transform.forEach(transformation => {
|
||||||
|
var key = Object.keys(transformation)[0];
|
||||||
|
var value = transformation[key];
|
||||||
|
if (__DEV__) {
|
||||||
|
_validateTransform(key, value, transformation);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (key) {
|
||||||
|
case 'matrix':
|
||||||
|
MatrixMath.multiplyInto(result, result, value);
|
||||||
|
break;
|
||||||
|
case 'rotate':
|
||||||
|
_multiplyTransform(result, MatrixMath.reuseRotateZCommand, [_convertToRadians(value)]);
|
||||||
|
break;
|
||||||
|
case 'scale':
|
||||||
|
_multiplyTransform(result, MatrixMath.reuseScaleCommand, [value]);
|
||||||
|
break;
|
||||||
|
case 'scaleX':
|
||||||
|
_multiplyTransform(result, MatrixMath.reuseScaleXCommand, [value]);
|
||||||
|
break;
|
||||||
|
case 'scaleY':
|
||||||
|
_multiplyTransform(result, MatrixMath.reuseScaleYCommand, [value]);
|
||||||
|
break;
|
||||||
|
case 'translate':
|
||||||
|
_multiplyTransform(result, MatrixMath.reuseTranslate3dCommand, [value[0], value[1], value[2] || 0]);
|
||||||
|
break;
|
||||||
|
case 'translateX':
|
||||||
|
_multiplyTransform(result, MatrixMath.reuseTranslate2dCommand, [value, 0]);
|
||||||
|
break;
|
||||||
|
case 'translateY':
|
||||||
|
_multiplyTransform(result, MatrixMath.reuseTranslate2dCommand, [0, value]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error('Invalid transform name: ' + key);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
...style,
|
||||||
|
transformMatrix: result,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a destructive operation on a transform matrix.
|
||||||
|
*/
|
||||||
|
function _multiplyTransform(
|
||||||
|
result: Array<number>,
|
||||||
|
matrixMathFunction: Function,
|
||||||
|
args: Array<number>
|
||||||
|
): void {
|
||||||
|
var matrixToApply = MatrixMath.createIdentityMatrix();
|
||||||
|
var argsWithIdentity = [matrixToApply].concat(args);
|
||||||
|
matrixMathFunction.apply(this, argsWithIdentity);
|
||||||
|
MatrixMath.multiplyInto(result, result, matrixToApply);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a string like '0.5rad' or '60deg' into radians expressed in a float.
|
||||||
|
* Note that validation on the string is done in `_validateTransform()`.
|
||||||
|
*/
|
||||||
|
function _convertToRadians(value: string): number {
|
||||||
|
var floatValue = parseFloat(value, 10);
|
||||||
|
return value.indexOf('rad') > -1 ? floatValue : floatValue * Math.PI / 180;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _validateTransform(key, value, transformation) {
|
||||||
|
var multivalueTransforms = [
|
||||||
|
'matrix',
|
||||||
|
'translate',
|
||||||
|
];
|
||||||
|
if (multivalueTransforms.indexOf(key) !== -1) {
|
||||||
|
invariant(
|
||||||
|
Array.isArray(value),
|
||||||
|
'Transform with key of %s must have an array as the value: %s',
|
||||||
|
key,
|
||||||
|
JSON.stringify(transformation)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
switch (key) {
|
||||||
|
case 'matrix':
|
||||||
|
invariant(
|
||||||
|
value.length === 9 || value.length === 16,
|
||||||
|
'Matrix transform must have a length of 9 (2d) or 16 (3d). ' +
|
||||||
|
'Provided matrix has a length of %s: %s',
|
||||||
|
value.length,
|
||||||
|
JSON.stringify(transformation)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case 'translate':
|
||||||
|
break;
|
||||||
|
case 'rotate':
|
||||||
|
invariant(
|
||||||
|
typeof value === 'string',
|
||||||
|
'Transform with key of "%s" must be a string: %s',
|
||||||
|
key,
|
||||||
|
JSON.stringify(transformation)
|
||||||
|
);
|
||||||
|
invariant(
|
||||||
|
value.indexOf('deg') > -1 || value.indexOf('rad') > -1,
|
||||||
|
'Rotate transform must be expressed in degrees (deg) or radians ' +
|
||||||
|
'(rad): %s',
|
||||||
|
JSON.stringify(transformation)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
invariant(
|
||||||
|
typeof value === 'number',
|
||||||
|
'Transform with key of "%s" must be a number: %s',
|
||||||
|
key,
|
||||||
|
JSON.stringify(transformation)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = precomputeStyle;
|
131
Libraries/Utilities/MatrixMath.js
Executable file
131
Libraries/Utilities/MatrixMath.js
Executable file
@ -0,0 +1,131 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* @providesModule MatrixMath
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Memory conservative (mutative) matrix math utilities. Uses "command"
|
||||||
|
* matrices, which are reusable.
|
||||||
|
*/
|
||||||
|
var MatrixMath = {
|
||||||
|
createIdentityMatrix: function() {
|
||||||
|
return [
|
||||||
|
1,0,0,0,
|
||||||
|
0,1,0,0,
|
||||||
|
0,0,1,0,
|
||||||
|
0,0,0,1
|
||||||
|
];
|
||||||
|
},
|
||||||
|
|
||||||
|
createCopy: function(m) {
|
||||||
|
return [
|
||||||
|
m[0], m[1], m[2], m[3],
|
||||||
|
m[4], m[5], m[6], m[7],
|
||||||
|
m[8], m[9], m[10], m[11],
|
||||||
|
m[12], m[13], m[14], m[15],
|
||||||
|
];
|
||||||
|
},
|
||||||
|
|
||||||
|
createTranslate2d: function(x, y) {
|
||||||
|
var mat = MatrixMath.createIdentityMatrix();
|
||||||
|
MatrixMath.reuseTranslate2dCommand(mat, x, y);
|
||||||
|
return mat;
|
||||||
|
},
|
||||||
|
|
||||||
|
reuseTranslate2dCommand: function(matrixCommand, x, y) {
|
||||||
|
matrixCommand[12] = x;
|
||||||
|
matrixCommand[13] = y;
|
||||||
|
},
|
||||||
|
|
||||||
|
reuseTranslate3dCommand: function(matrixCommand, x, y, z) {
|
||||||
|
matrixCommand[12] = x;
|
||||||
|
matrixCommand[13] = y;
|
||||||
|
matrixCommand[14] = z;
|
||||||
|
},
|
||||||
|
|
||||||
|
createScale: function(factor) {
|
||||||
|
var mat = MatrixMath.createIdentityMatrix();
|
||||||
|
MatrixMath.reuseScaleCommand(mat, factor);
|
||||||
|
return mat;
|
||||||
|
},
|
||||||
|
|
||||||
|
reuseScaleCommand: function(matrixCommand, factor) {
|
||||||
|
matrixCommand[0] = factor;
|
||||||
|
matrixCommand[5] = factor;
|
||||||
|
},
|
||||||
|
|
||||||
|
reuseScale3dCommand: function(matrixCommand, x, y, z) {
|
||||||
|
matrixCommand[0] = x;
|
||||||
|
matrixCommand[5] = y;
|
||||||
|
matrixCommand[10] = z;
|
||||||
|
},
|
||||||
|
|
||||||
|
reuseScaleXCommand(matrixCommand, factor) {
|
||||||
|
matrixCommand[0] = factor;
|
||||||
|
},
|
||||||
|
|
||||||
|
reuseScaleYCommand(matrixCommand, factor) {
|
||||||
|
matrixCommand[5] = factor;
|
||||||
|
},
|
||||||
|
|
||||||
|
reuseScaleZCommand(matrixCommand, factor) {
|
||||||
|
matrixCommand[10] = factor;
|
||||||
|
},
|
||||||
|
|
||||||
|
reuseRotateYCommand: function(matrixCommand, amount) {
|
||||||
|
matrixCommand[0] = Math.cos(amount);
|
||||||
|
matrixCommand[2] = Math.sin(amount);
|
||||||
|
matrixCommand[8] = Math.sin(-amount);
|
||||||
|
matrixCommand[10] = Math.cos(amount);
|
||||||
|
},
|
||||||
|
|
||||||
|
createRotateZ: function(radians) {
|
||||||
|
var mat = MatrixMath.createIdentityMatrix();
|
||||||
|
MatrixMath.reuseRotateZCommand(mat, radians);
|
||||||
|
return mat;
|
||||||
|
},
|
||||||
|
|
||||||
|
// http://www.w3.org/TR/css3-transforms/#recomposing-to-a-2d-matrix
|
||||||
|
reuseRotateZCommand: function(matrixCommand, radians) {
|
||||||
|
matrixCommand[0] = Math.cos(radians);
|
||||||
|
matrixCommand[1] = Math.sin(radians);
|
||||||
|
matrixCommand[4] = -Math.sin(radians);
|
||||||
|
matrixCommand[5] = Math.cos(radians);
|
||||||
|
},
|
||||||
|
|
||||||
|
multiplyInto: function(out, a, b) {
|
||||||
|
var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
|
||||||
|
a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
|
||||||
|
a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
|
||||||
|
a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
|
||||||
|
|
||||||
|
var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
|
||||||
|
out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
|
||||||
|
out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
|
||||||
|
out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
|
||||||
|
out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
|
||||||
|
|
||||||
|
b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7];
|
||||||
|
out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
|
||||||
|
out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
|
||||||
|
out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
|
||||||
|
out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
|
||||||
|
|
||||||
|
b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11];
|
||||||
|
out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
|
||||||
|
out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
|
||||||
|
out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
|
||||||
|
out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
|
||||||
|
|
||||||
|
b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15];
|
||||||
|
out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
|
||||||
|
out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
|
||||||
|
out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
|
||||||
|
out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = MatrixMath;
|
Loading…
x
Reference in New Issue
Block a user