# Matrix math for the web

## 什么是变换矩阵？

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

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

[4, 3, 2, 1] // 在 [x, y, z, w] 处求点积
``````

### 定义相乘函数

js
``````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];
}
``````

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

### 两个矩阵相乘

js
``````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],
];
}
``````

### 用法

js
``````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);
``````

## 平移矩阵

js
``````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

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

js
``````// 从矩阵数组创建 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;
``````

## 缩放矩阵

js
``````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];
``````

## 旋转矩阵

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

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

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

var transformedPoint = [
Math.cos(rotationInRadians) * distance,
Math.sin(rotationInRadians) * distance,
];
``````

js
``````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,
];
``````

js
``````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
```

### 组合多种变换

js
``````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 步：缩小
]);
``````

js
``````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 步：缩小
]);
``````