如何使用矩阵在native native中从左上角缩放对象

mhe*_*ers 6 javascript transform matrix react-native

我正在阅读这篇文章,该文章解释了如何使用反应原生进行旋转变换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 },
    ],
  },
});
Run Code Online (Sandbox Code Playgroud)

并且,从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,
};
Run Code Online (Sandbox Code Playgroud)

Art*_*m K 3

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

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

分解:

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


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

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

Run Code Online (Sandbox Code Playgroud)

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


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

Run Code Online (Sandbox Code Playgroud)

现在我们需要将所有内容放在一起。

  • 传入感兴趣的对象ref及其属性。
  • 为该对象生成单位矩阵。
  • 通过矩阵乘法增加该对象的规模。
  • 将对象原点移动到所需的左上角位置 ( xAxis: 0, yAxis: 0)。
  • 用于MatrixMath.multiplyInto通过矩阵乘法处理前面的所有步骤。
  • ref通过将变换应用于目标对象setNativeProps

    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 }] }
        });
    }

Run Code Online (Sandbox Code Playgroud)

现在,我们将上述所有方法添加到 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',
        },
    });

Run Code Online (Sandbox Code Playgroud)