大家好,我是前端西瓜哥。
canvaskit 类似 Canvas 2D,会维护画布的 当前矩阵(current matrix),之后通过 drawXx 渲染图形时,会应用这个矩阵的值对顶点做一次变换计算,基于新的点位置再绘制出来。
在合适的时机修改这个矩阵,我们就可以实现视图矩阵变换、模型变化等各种矩阵变换效果。
基本的变形矩阵
-
translate(dx, dy):画布的当前矩阵乘以位移矩阵; -
rotate(rot, rx, ry):乘以旋转矩阵,角传入的是角度,不是弧度,同时需要指定旋转中心; -
scale(sx, sy):乘以缩放矩阵; -
skew(sx, sy):乘以斜切矩阵。
示例:
const canvas = surface.getCanvas();
canvas.translate(100, 100); // 位移 100, 100
canvas.rotate(30, 0, 0); // 旋转 30 度
canvas.scale(2, 2); // 缩放 2 倍
canvas.drawRect(rect, redPaint);
一个 [0, 0, 100, 100] 的矩形,缩放为 2 倍,然后基于原点 0, 0 旋转 30 度,最后位移 100, 100,效果见下图。
乘以任意矩阵
concat(InputMatrix):左乘一个任意矩阵。这个矩阵是 行矩阵,所谓行矩阵就是一行行把矩阵的值放到一位数组里来做表达。
// 等价 canvas.scale(2, 2)
const m = [2, 0, 0, 0, 2, 0];
canvas.concat(m);
入参的类似就很丰富了,下面这些都行。
type InputMatrix = MallocObj | Matrix4x4 | Matrix3x3 | Matrix3x2 | DOMMatrix | number[];
获取当前矩阵的值
getTotalMatrix() 会返回画布的当前矩阵,是一个完整的 3x3 矩阵,把可以省略的 [0, 0, 1] 补上了。
canvas.getTotalMatrix()
// 返回值:
[ 3.464101552963257, -2, 100, 2, 3.464101552963257, 100, 0, 0, 1]
矩阵工具方法
有时候我们希望拿到矩阵数据进行计算,canvaskit 有提供一些工具方法。
注意这些方法返回的是完整的 3x3 矩阵数组。
-
CanvasKit.Matrix.identity():返回单位矩阵数组; -
CanvasKit.Matrix.multiply(m1, m2, m3, ...):返回多个 3x3 矩阵进行顺序相乘的结果; -
CanvasKit.Matrix.translated(dx, dy):返回位移矩阵; -
CanvasKit.Matrix.scaled(sx, sy, px, py):返回缩放矩阵,(px, py) 是变形中心; -
CanvasKit.Matrix.rotated(rad, px, py):返回基于点(px, py)旋转 rad 弧度的旋转矩阵; -
CanvasKit.Matrix.skewed(kx, ky, px, py);:返回斜切矩阵; -
CanvasKit.Matrix.invert(m):返回矩阵的逆矩阵; -
CanvasKit.Matrix.mapPoints(m, points):返回应用了矩阵后的所有点。这些点是用一维数组拍平表达的。
直接修改矩阵
skia 里是有个 setMatrix 的方法用来直接修改当前矩阵矩阵值的方法,但是 canvaskit 并没有暴露出来,都是些在原来的矩阵上乘上一个矩阵的方法。
一个办法是根据逆矩阵的定义,我们给当前矩阵乘上它的逆矩阵,就得到了单位矩阵,然后 concat 其他矩阵,就变成其他矩阵了。
const currentMatrix = canvas.getTotalMatrix();
const invertMatrix = CanvasKit.Matrix.invert(currentMatrix);
canvas.concat(invertMatrix);
canvas.concat(newMatrix);
或者在一开始的时候 store 一下。store 方法会保存当前 matrix 的 clip 信息,此时 matrix 就还是单位矩阵。然后后面要重置的时候 restore 一下,matrix 就还原成单位矩阵了。
canvas.save();
// ...
canvas.restore(); // 恢复原来的单位矩阵
canvas.concat(newMatrix);
最后但可能是最好的办法,就是自己编译 skia,把 setMatrix 方法还有其他你相用的方法暴露出来,编译成 wasm。
结尾
我是前端西瓜哥,关注我,学习更多前端图形知识。
相关阅读,