# Matrix math for the web

## 什么是变换矩阵？

``````var identityMatrix = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
];
``````

``````[1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1]

[4, 3, 2, 1]
``````

### 定义相乘函数

``````function multiplyMatrixAndPoint(matrix, point) {

// 给矩阵的每一部分一个简单的变量名, 列数（c）与行数（r）
var c0r0 = matrix[ 0], c1r0 = matrix[ 1], c2r0 = matrix[ 2], c3r0 = matrix[ 3];
var c0r1 = matrix[ 4], c1r1 = matrix[ 5], c2r1 = matrix[ 6], c3r1 = matrix[ 7];
var c0r2 = matrix[ 8], c1r2 = matrix[ 9], c2r2 = matrix[10], c3r2 = matrix[11];
var c0r3 = matrix[12], c1r3 = matrix[13], c2r3 = matrix[14], c3r3 = matrix[15];

// 定义点坐标
var x = point[0];
var y = point[1];
var z = point[2];
var w = point[3];

// 点坐标和第一列对应相乘, 再求和
var resultX = (x * c0r0) + (y * c0r1) + (z * c0r2) + (w * c0r3);

// 点坐标和第二列对应相乘, 再求和
var resultY = (x * c1r0) + (y * c1r1) + (z * c1r2) + (w * c1r3);

// 点坐标和第三列对应相乘, 再求和
var resultZ = (x * c2r0) + (y * c2r1) + (z * c2r2) + (w * c2r3);

// 点坐标和第四列对应相乘, 再求和
var resultW = (x * c3r0) + (y * c3r1) + (z * c3r2) + (w * c3r3);

return [resultX, resultY, resultZ, resultW]
}
``````

``````// identityResult等于[4,3,2,1]
var identityResult = multiplyMatrixAndPoint(identityMatrix, [4,3,2,1]);
``````

### 两个矩阵相乘

``````function multiplyMatrices(matrixA, matrixB) {

// 将第二个矩阵按列切片
var column0 = [matrixB[0], matrixB[4], matrixB[8], matrixB[12]];
var column1 = [matrixB[1], matrixB[5], matrixB[9], matrixB[13]];
var column2 = [matrixB[2], matrixB[6], matrixB[10], matrixB[14]];
var column3 = [matrixB[3], matrixB[7], matrixB[11], matrixB[15]];

// 将每列分别和矩阵相乘
var result0 = multiplyMatrixAndPoint( matrixA, column0 );
var result1 = multiplyMatrixAndPoint( matrixA, column1 );
var result2 = multiplyMatrixAndPoint( matrixA, column2 );
var result3 = multiplyMatrixAndPoint( matrixA, column3 );

// 把结果重新组合成矩阵
return [
result0[0], result1[0], result2[0], result3[0],
result0[1], result1[1], result2[1], result3[1],
result0[2], result1[2], result2[2], result3[2],
result0[3], result1[3], result2[3], result3[3]
]
}
``````

### 用法

``````var someMatrix = [
4, 0, 0, 0,
0, 3, 0, 0,
0, 0, 5, 0,
4, 8, 4, 1
]

var identityMatrix = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
];

// 返回someMatrix的数组表示
var someMatrixResult = multiplyMatrices(identityMatrix, someMatrix);
``````

## 平移矩阵

``````var x = 50;
var y = 100;
var z = 0;

var translationMatrix = [
1,    0,    0,   0,
0,    1,    0,   0,
0,    0,    1,   0,
x,    y,    z,   1
];
``````

## 用矩阵操作DOM

``````<div id='move-me' class='transformable'>
<h2>Move me with a matrix</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit...</p>
</div>
``````

``````// 从矩阵数组创建matrix3d样式属性
function matrixArrayToCssMatrix(array) {
return "matrix3d(" + array.join(',') + ")";
}

// 获取DOM元素
var moveMe = document.getElementById('move-me');

// 返回结果如："matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 50, 100, 0, 1);"
var matrix3dRule = matrixArrayToCssMatrix( translationMatrix );

// 设置变换
moveMe.style.transform = matrix3dRule;
``````

## 缩放矩阵

``````var w = 1.5; // width  (x)
var h = 0.7; // height (y)
var d = 1;   // depth  (z)

var scaleMatrix = [
w,    0,    0,   0,
0,    h,    0,   0,
0,    0,    d,   0,
0,    0,    0,   1
];
``````

## 旋转矩阵

``````// 不借助矩阵将点绕原点旋转
var point = [10,2];

// 计算到原点的距离
var distance = Math.sqrt(point[0] * point[0] + point[1] * point[1]);

// 60度
var rotationInRadians = Math.PI / 3;

var transformedPoint = [
];
``````

``````var sin = Math.sin;
var cos = Math.cos;

// NOTE: There is no perspective in these transformations, so a rotation
//       at this point will only appear to only shrink the div

var a = Math.PI * 0.3; // 转角

// 绕Z轴旋转
var rotateZMatrix = [
cos(a), -sin(a),    0,    0,
sin(a),  cos(a),    0,    0,
0,       0,    1,    0,
0,       0,    0,    1
];
``````

``````function rotateAroundXAxis(a) {

return [
1,       0,        0,     0,
0,  cos(a),  -sin(a),     0,
0,  sin(a),   cos(a),     0,
0,       0,        0,     1
];
}

function rotateAroundYAxis(a) {

return [
cos(a),   0, sin(a),   0,
0,   1,      0,   0,
-sin(a),   0, cos(a),   0,
0,   0,      0,   1
];
}

function rotateAroundZAxis(a) {

return [
cos(a), -sin(a),    0,    0,
sin(a),  cos(a),    0,    0,
0,       0,    1,    0,
0,       0,    0,    1
];
}
``````

## 矩阵组合

```  transformation = rotate * translate * scale
```

### 组合多种变换

``````var transformMatrix = MDN.multiplyArrayOfMatrices([
rotateAroundZAxis(Math.PI * 0.5),    // 第3步：旋转90度
translate(0, 200, 0),                // 第2步：下移100像素
scale(0.8, 0.8, 0.8),                // 第1步：缩小
]);

``````

``````var transformMatrix = MDN.multiplyArrayOfMatrices([
scale(1.25, 1.25, 1.25),             // 第6步：放大
translate(0, -200, 0),               // 第5步：上移
rotateAroundZAxis(-Math.PI * 0.5),   // 第4步：倒转
rotateAroundZAxis(Math.PI * 0.5),    // 第3步：旋转90度
translate(0, 200, 0),                // 第2步：下移100像素
scale(0.8, 0.8, 0.8),                // 第1步：缩小
]);
``````