【问题标题】:How to scale an object from the top left in react native using matrices?如何使用矩阵从左上角缩放对象?
【发布时间】:2017-11-26 05:26:54
【问题描述】:

我正在阅读this article,它解释了如何使用MatrixMath 在本机反应中进行旋转变换。我正在尝试为对象的比例设置动画,而不是旋转,我希望它使用对象左上角的原点而不是中心进行缩放。谁能解释一下如何做到这一点?

旋转矩阵的相关代码位是:

const matrix = transformUtil.rotateX(dx);
transformUtil.origin(matrix, { x: 0, y, z: 0 });

const perspective = this.props.perspective || rootDefaultProps.perspective;

ref.setNativeProps({
  style: {
    transform: [
      { perspective },
      { matrix },
    ],
  },
});

并且,从 transformUtil:

import MatrixMath from 'react-native/Libraries/Utilities/MatrixMath';

function transformOrigin(matrix, origin) {
  const { x, y, z } = origin;

  const translate = MatrixMath.createIdentityMatrix();
  MatrixMath.reuseTranslate3dCommand(translate, x, y, z);
  MatrixMath.multiplyInto(matrix, translate, matrix);

  const untranslate = MatrixMath.createIdentityMatrix();
  MatrixMath.reuseTranslate3dCommand(untranslate, -x, -y, -z);
  MatrixMath.multiplyInto(matrix, matrix, untranslate);
}

function rotateX(deg) {
  const rad = (Math.PI / 180) * deg;
  const cos = Math.cos(rad);
  const sin = Math.sitransfn(rad);
  return [
    1, 0, 0, 0,
    0, cos, -sin, 0,
    0, sin, cos, 0,
    0, 0, 0, 1,
  ];
}

export default {
  rotateX,
  origin: transformOrigin,
};

【问题讨论】:

    标签: javascript react-native matrix transform


    【解决方案1】:

    在深入解决所描述的问题之前,我强烈建议任何阅读本文的人学习(或复习)矩阵乘法。有一些很好的资源可以做到这一点,但我个人最喜欢的是Khan Academy

    如果您喜欢只阅读代码,这里是 Snack 中的工作解决方案https://snack.expo.io/BJnDImQlr

    细分:

    我们需要做的第一件事是设置我们要缩放的对象的变换原点。我们将使用 OP 在他们的问题中包含的文章中的 transformOrigin 函数的一部分。但是,我们只需要修改一次原点,因为不需要将它重新设置回顶部(文章中的特定动画要求它返回顶部)。

    
        function transformOrigin(matrix, origin) {
            const { x, y, z } = origin;
    
            const translate = MatrixMath.createIdentityMatrix();
            MatrixMath.reuseTranslate3dCommand(translate, x, y, z);
            MatrixMath.multiplyInto(matrix, translate, matrix);
        }
    
    

    我们可以使用矩阵乘法来缩放由适当矩阵(即MatrixMath.createIdentityMatrix)表示的任何对象。如果我们将下面描述的矩阵乘以目标对象矩阵,我们最终将得到相同的对象矩阵,该矩阵被x 缩放。

    
        function scale(x) {
            return [
                x, 0, 0, 0,
                0, x, 0, 0,
                0, 0, x, 0,
                0, 0, 0, 1
            ];
        }
    
    

    现在我们需要把所有东西放在一起。

    • 传入感兴趣的对象ref 及其属性。
    • 为该对象生成一个单位矩阵。
    • 通过矩阵乘法增加该对象的比例。
    • 将对象原点移动到所需的左上角位置 (xAxis: 0, yAxis: 0)。
    • 使用MatrixMath.multiplyInto 通过矩阵乘法处理之前的所有步骤。
    • 通过setNativeProps 对目标ref 对象应用转换。
    
        function transformScale(ref, scaleBy, width, height) {
            const matrix = MatrixMath.createIdentityMatrix();
            const toScale = scale(scaleBy);
    
            transformOrigin(matrix, {
                x: (width * scaleBy - width) / 2,
                y: (height * scaleBy - height) / 2,
                z: 0
            });
    
            MatrixMath.multiplyInto(matrix, matrix, toScale);
    
            ref.setNativeProps({
                style: { transform: [{ matrix }] }
            });
        }
    
    

    现在,我们将上述所有方法添加到 React 组件中。如果要增加或减少对象的比例,请更改transformScale(this._target, 3, width, height) 中的第二个参数。您甚至可以将scaleBy 设置为动态值并使用它制作动画。

    
        export default class App extends React.Component {
            constructor(props) {
                super(props);
                this.state = {
                    width: 0,
                    height: 0
                };
            }
    
            handleBaseLayout = (e) => {
                const { width, height } = e.nativeEvent.layout;
    
                this.setState({ width, height }, () => {
                    transformScale(this._target, 3, width, height);
                });
            };
    
            render() {
                return (
                    <View style={styles.container}>
                        <View
                            style={styles.target}
                            ref={c => (this._target = c)}
                            onLayout={this.handleBaseLayout}
                        />
                    </View>
                );
            }
        }
    
        const styles = StyleSheet.create({
            container: {
                flex: 1,
                justifyContent: 'center',
                paddingTop: Constants.statusBarHeight,
                backgroundColor: '#ecf0f1',
                padding: 8,
            },
            target: {
                width: 100,
                height: 100,
                backgroundColor: 'blue',
            },
        });
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-04
      • 1970-01-01
      • 2020-03-12
      • 1970-01-01
      相关资源
      最近更新 更多