ewizard
ewizard

Reputation: 2862

React Native - use transformation matrix to change the origin of the scale transform from the center to the top

I am using the below code to do a transform animation:

transform: [
    // scaleX, scaleY, scale, theres plenty more options you can find online for this.
    {  scaleY: this.state.ViewScale } // this would be the result of the animation code below and is just a number.
]}}>

Currently, the transform-origin (<- not actually available in react native) is the center. For the animation, the component scales from the center, so it looks like it is "expanding" from the center. I want it to "expand" from the top (i.e. make the transform origin the top of the component...I think).

I found a method that simulates the transform-origin css:

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

But I am not sure what matrices to use to affect the component the way I want. I have some understanding of transformation matrices, but only for translating and rotating - I am not sure how to affect the origin of a scale transform.

For anyone looking to do some digging, thanks: https://en.wikipedia.org/wiki/Transformation_matrix

Upvotes: 4

Views: 3767

Answers (1)

Gan Quan
Gan Quan

Reputation: 477

You need 3 matrix transformations. 1) Translate view center to the desired origin point, 2) Apply scaling, and 3) Apply negative translation.

const matrix = MatrixMath.createIdentityMatrix();

// First translation, move view center to top left corner
const translate = MatrixMath.createIdentityMatrix();
MatrixMath.reuseTranslate3dCommand(translate, -viewWidth / 2, -viewHeight / 2, 0);
MatrixMath.multiplyInto(matrix, matrix, translate);

// Scale, center point and the top left corner are now overlapping so view will expand or shrink from the top left corner
const scale = MatrixMath.createIdentityMatrix();
MatrixMath.reuseScale3dCommand(scale, this.state.ScaleView, this.state.ScaleView, 1);
MatrixMath.multiplyInto(matrix, matrix, scale);

// Move your view's top left corner to it's original position
const untranslate = MatrixMath.createIdentityMatrix();
MatrixMath.reuseTranslate3dCommand(untranslate, viewWidth / 2, viewHeight / 2, 0);
MatrixMath.multiplyInto(matrix, matrix, untranslate);

// You need to set transform matrix somewhere in your JSX like this:
// <View style={{ transform: [ { matrix } ] }} />
// Or, you can call ref.setNativeProps().

I think this way you have to do scaling using matrix, so no need to use specific transform functions like scale/scaleX/scaleY.

You can also manually calculate translate values and use transform's translateX/translateY functions to achieve the same effect.

Upvotes: 1

Related Questions